.NET正则表达式-前M行的前N个字符

.NET正则表达式-前M行的前N个字符,.net,regex,chars,.net,Regex,Chars,对于以下4种基本情况,我需要4个通用正则表达式: 最多A个字符从B个字符开始从行开始最多C个字符从文件开始的D行开始 最多A个字符从B个字符后开始,从行的开头开始,最多C个字符出现在文件末尾的D行之前 最多A个字符在B个字符之前开始,从行的末尾开始,最多C行在文件开头的D行之后开始 最多A个字符在B个字符之前从行末开始最多C行在D行之前从文件结尾开始 这将允许选择文件中任意位置的任意文本块 到目前为止,我已经成功地提出了仅适用于线路和字符的案例: 你为什么不这样做呢 //Assuming you

对于以下4种基本情况,我需要4个通用正则表达式:

最多A个字符从B个字符开始从行开始最多C个字符从文件开始的D行开始 最多A个字符从B个字符后开始,从行的开头开始,最多C个字符出现在文件末尾的D行之前 最多A个字符在B个字符之前开始,从行的末尾开始,最多C行在文件开头的D行之后开始 最多A个字符在B个字符之前从行末开始最多C行在D行之前从文件结尾开始 这将允许选择文件中任意位置的任意文本块

到目前为止,我已经成功地提出了仅适用于线路和字符的案例:


你为什么不这样做呢

//Assuming you have it read into a string name sourceString
String[] SplitString = sourceString.Split(Environment.Newline); //You will probably need to account for any line delimeter
String[M] NewStrings;
for(i=0;i<M;i++) {
    NewStrings[i] = SplitString[i].SubString(0,N) //Or (N, SplitString[i].Length -1) depending on what you need
}
你不需要正则表达式,也不需要LINQ


我重读了你问题的开头,你可以简单地参数化for循环和Split的开始和结束,以得到你所需要的东西。

你为什么不这样做呢:

//Assuming you have it read into a string name sourceString
String[] SplitString = sourceString.Split(Environment.Newline); //You will probably need to account for any line delimeter
String[M] NewStrings;
for(i=0;i<M;i++) {
    NewStrings[i] = SplitString[i].SubString(0,N) //Or (N, SplitString[i].Length -1) depending on what you need
}
你不需要正则表达式,也不需要LINQ

我重读了你问题的开头,你可以简单地参数化for循环和Split的开始和结束,以获得你所需要的内容。

编辑:根据你的评论,听起来这确实是你无法控制的。我之所以发布这个答案,是因为我觉得开发人员经常会被技术挑战所困扰,而忽略了实际目标:解决问题,尤其是在正则表达式方面。我知道我也是这样。我认为这只是一个不幸的结果,既有技术性又有创造性

因此,如果可能的话,我想让大家重新关注手头的问题,并强调,在一个储备充足的工具集存在的情况下,Regex不是这项工作的合适工具。如果出于你无法控制的原因,它是你唯一可以使用的工具,那么,当然,你别无选择

我想你可能有真正的理由要求一个正则表达式解决方案;但由于这些原因没有得到充分解释,我觉得你还是有可能只是固执

你说这需要在正则表达式中完成,但我不相信


首先,我仅限于.NET2.0[…]

没问题。谁说你需要LINQ来解决这样的问题?LINQ只是让事情变得更容易;它不会让不可能的事情成为可能

例如,这里有一种方法可以实现问题中的第一个案例,将其重构为更灵活的内容将非常简单,这样您就可以涵盖案例2-3:

public IEnumerable<string> ScanText(TextReader reader,
                                    int start,
                                    int count,
                                    int lineStart,
                                    int lineCount)
{
    int i = 0;
    while (i < lineStart && reader.Peek() != -1)
    {
        reader.ReadLine();
        ++i;
    }

    i = 0;
    while (i < lineCount && reader.Peek() != -1)
    {
        string line = reader.ReadLine();

        if (line.Length < start)
        {
            yield return ""; // or null? or continue?
        }
        else
        {
            int length = Math.Min(count, line.Length - start);
            yield return line.Substring(start, length);
        }

        ++i;
    }
}
因此,对于一般问题有一个.NET2.0友好的解决方案,不使用正则表达式或LINQ

其次,我需要正则表达式的灵活性,以允许在这些[…]的基础上构建更复杂的表达式

也许我只是在做傻事;是什么阻止你从非正则表达式开始,然后再使用正则表达式进行更复杂的行为呢?例如,如果您需要对上面ScanText返回的行进行额外处理,您当然可以使用Regex进行处理。但是从一开始就坚持使用正则表达式似乎。。。我不知道,只是没必要

不幸的是,由于项目的性质,它必须在RegEx中完成[…]

如果真是这样,那就很好了。但是,如果您的理由仅来自上述摘录,那么我不同意使用正则表达式解决扫描某些文本行中的某些字符的问题的这一特定方面,即使该问题的其他方面不在本问题范围内,也需要正则表达式

另一方面,如果你因为某种武断的原因被迫使用正则表达式,比如说,有人选择写一些需求/规范,可能没有花太多心思,正则表达式将用于这项任务,那么我个人建议反对它。向任何有能力更改此要求的人解释,不需要正则表达式,并且不使用正则表达式即可轻松解决问题。。。或者使用普通代码和正则表达式的组合

我能想到的唯一的另一种可能性是,这可能是由于我自己缺乏想象力,无法解释为什么需要使用正则表达式来解决您在问题中描述的问题,因为您仅限于使用一个特定的工具,该工具只接受正则表达式作为用户输入。但是您的问题被标记为.net,因此我必须假设您可以在一定程度上编写自己的代码来解决这个问题。如果是这样的话,我会再说一遍:我认为你不需要正则表达式

Edit:根据你的评论,这听起来真的是你无法控制的事情。我之所以发布这个答案,是因为我觉得自己经常这样做,尤其是在日常生活中 在表达式中,开发人员很容易陷入技术挑战,而忽略了实际目标:解决问题。我知道我也是这样。我认为这只是一个不幸的结果,既有技术性又有创造性

因此,如果可能的话,我想让大家重新关注手头的问题,并强调,在一个储备充足的工具集存在的情况下,Regex不是这项工作的合适工具。如果出于你无法控制的原因,它是你唯一可以使用的工具,那么,当然,你别无选择

我想你可能有真正的理由要求一个正则表达式解决方案;但由于这些原因没有得到充分解释,我觉得你还是有可能只是固执

你说这需要在正则表达式中完成,但我不相信


首先,我仅限于.NET2.0[…]

没问题。谁说你需要LINQ来解决这样的问题?LINQ只是让事情变得更容易;它不会让不可能的事情成为可能

例如,这里有一种方法可以实现问题中的第一个案例,将其重构为更灵活的内容将非常简单,这样您就可以涵盖案例2-3:

public IEnumerable<string> ScanText(TextReader reader,
                                    int start,
                                    int count,
                                    int lineStart,
                                    int lineCount)
{
    int i = 0;
    while (i < lineStart && reader.Peek() != -1)
    {
        reader.ReadLine();
        ++i;
    }

    i = 0;
    while (i < lineCount && reader.Peek() != -1)
    {
        string line = reader.ReadLine();

        if (line.Length < start)
        {
            yield return ""; // or null? or continue?
        }
        else
        {
            int length = Math.Min(count, line.Length - start);
            yield return line.Substring(start, length);
        }

        ++i;
    }
}
因此,对于一般问题有一个.NET2.0友好的解决方案,不使用正则表达式或LINQ

其次,我需要正则表达式的灵活性,以允许在这些[…]的基础上构建更复杂的表达式

也许我只是在做傻事;是什么阻止你从非正则表达式开始,然后再使用正则表达式进行更复杂的行为呢?例如,如果您需要对上面ScanText返回的行进行额外处理,您当然可以使用Regex进行处理。但是从一开始就坚持使用正则表达式似乎。。。我不知道,只是没必要

不幸的是,由于项目的性质,它必须在RegEx中完成[…]

如果真是这样,那就很好了。但是,如果您的理由仅来自上述摘录,那么我不同意使用正则表达式解决扫描某些文本行中的某些字符的问题的这一特定方面,即使该问题的其他方面不在本问题范围内,也需要正则表达式

另一方面,如果你因为某种武断的原因被迫使用正则表达式,比如说,有人选择写一些需求/规范,可能没有花太多心思,正则表达式将用于这项任务,那么我个人建议反对它。向任何有能力更改此要求的人解释,不需要正则表达式,并且不使用正则表达式即可轻松解决问题。。。或者使用普通代码和正则表达式的组合


我能想到的唯一的另一种可能性是,这可能是由于我自己缺乏想象力,无法解释为什么需要使用正则表达式来解决您在问题中描述的问题,因为您仅限于使用一个特定的工具,该工具只接受正则表达式作为用户输入。但是您的问题被标记为.net,因此我必须假设您可以在一定程度上编写自己的代码来解决这个问题。如果是这样的话,我会再说一遍:我认为你不需要正则表达式

首先,下面是基本情况1的答案:

Regex regexObj = new Regex(
    @"(?<=            # Assert that the following can be matched before the current position
     \A               # Start of string
     (?:.*\r\n){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     .{2}             # 2 characters (B = 2)
    )                 # End of lookbehind assertion
    .{1,3}            # Match 1-3 characters (A = 3)", 
    RegexOptions.IgnorePatternWhitespace);
因此,在文本中

line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
它会匹配的

ne3
ne4
ne5
3 b
4 b
5 b
2 b
3 b
4 b

首先,以下是基本情况1的答案:

Regex regexObj = new Regex(
    @"(?<=            # Assert that the following can be matched before the current position
     \A               # Start of string
     (?:.*\r\n){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     .{2}             # 2 characters (B = 2)
    )                 # End of lookbehind assertion
    .{1,3}            # Match 1-3 characters (A = 3)", 
    RegexOptions.IgnorePatternWhitespace);
因此,在文本中

line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
它会匹配的

ne3
ne4
ne5
3 b
4 b
5 b
2 b
3 b
4 b

下面是一个用于基本情况2的正则表达式:

Regex regexObj = new Regex(
    @"(?<=              # Assert that the following can be matched before the current position
     ^                # Start of line
     .{2}             # 2 characters (B = 2)
    )                 # End of lookbehind assertion
    .{1,3}            # Match 1-3 characters (A = 3)
    (?=               # Assert that the following can be matched after the current position
     .*$              # rest of the current line
     (?:\r\n.*){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     \z               # end of the string
    )", 
    RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
它会匹配的

ne2
ne3
ne4

ne2从第五行到最后一行C+D=5中的第三个字符B=2开始,以此类推。

这里有一个用于基本情况2的正则表达式:

Regex regexObj = new Regex(
    @"(?<=              # Assert that the following can be matched before the current position
     ^                # Start of line
     .{2}             # 2 characters (B = 2)
    )                 # End of lookbehind assertion
    .{1,3}            # Match 1-3 characters (A = 3)
    (?=               # Assert that the following can be matched after the current position
     .*$              # rest of the current line
     (?:\r\n.*){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     \z               # end of the string
    )", 
    RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
它会匹配的

ne2
ne3
ne4

ne2从第五行到最后一行C+D=5中的第三个字符B=2开始,以此类推。

基本情况3有一个:

Regex regexObj = new Regex(
    @"(?<=            # Assert that the following can be matched before the current position
     \A               # Start of string
     (?:.*\r\n){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     .*               # any number of characters
    )                 # End of lookbehind assertion
    (?=               # Assert that the following can be matched after the current position
     .{8}             # 8 characters (B = 8)
     $                # end of line
    )                 # End of lookahead assertion
    .{1,3}            # Match 1-3 characters (A = 3)", 
    RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
它会匹配的

ne3
ne4
ne5
3 b
4 b
5 b
2 b
3 b
4 b

3 b因为它是3个字符A=3,从第8到最后一个字符b=8开始,从第三行D=2开始,以此类推

Regex regexObj = new Regex(
    @"(?<=            # Assert that the following can be matched before the current position
     \A               # Start of string
     (?:.*\r\n){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     .*               # any number of characters
    )                 # End of lookbehind assertion
    (?=               # Assert that the following can be matched after the current position
     .{8}             # 8 characters (B = 8)
     $                # end of line
    )                 # End of lookahead assertion
    .{1,3}            # Match 1-3 characters (A = 3)", 
    RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
它会匹配的

ne3
ne4
ne5
3 b
4 b
5 b
2 b
3 b
4 b

3 b因为它是3个字符A=3,从第8个到最后一个字符b=8开始,从第三行D=2开始,等等。

最后是基本情况4的一个解决方案:

Regex regexObj = new Regex(
    @"(?=             # Assert that the following can be matched after the current position
     .{8}             # 8 characters (B = 8)
     (?:\r\n.*){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     \z               # end of the string
    )                 # End of lookahead assertion
    .{1,3}            # Match three characters (A = 3)", 
    RegexOptions.IgnorePatternWhitespace);
文中

line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
这将匹配

ne3
ne4
ne5
3 b
4 b
5 b
2 b
3 b
4 b

2 b因为它是三个字符A=3,从第五行到最后一行C+D=5的第八个到最后一个字符b=8开始,以此类推。

最后是基本情况4的一个解决方案:

Regex regexObj = new Regex(
    @"(?=             # Assert that the following can be matched after the current position
     .{8}             # 8 characters (B = 8)
     (?:\r\n.*){2,4}  # 2 to 4 entire lines (D = 2, C = 4+1-2)
     \z               # end of the string
    )                 # End of lookahead assertion
    .{1,3}            # Match three characters (A = 3)", 
    RegexOptions.IgnorePatternWhitespace);
文中

line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
这将匹配

ne3
ne4
ne5
3 b
4 b
5 b
2 b
3 b
4 b

2 b因为它是三个字符A=3,从第五行到最后一行C+D=5中第八个到最后一个字符b=8开始,以此类推。

请原谅两点:

我提出的解决方案并不完全基于正则表达式。我知道,我读到你需要纯正则表达式解决方案。但是我研究了一个有趣的问题,我很快得出结论,在这个问题上使用正则表达式过于复杂了。我觉得无法用纯正则表达式解答。我发现 e下面的,我给他们看;也许,他们可以给你一些想法

我不懂C或.NET,只懂Python。由于正则表达式在所有语言中几乎都是相同的,所以我想我只使用正则表达式来回答这个问题,这就是为什么我开始研究这个问题。现在,我仍然用Python展示我的解决方案,因为我认为无论如何它都很容易理解

我认为通过一个唯一的正则表达式很难捕获文本中出现的所有字母,因为在几行中查找几个字母对我来说似乎是一个在匹配中查找嵌套匹配的问题也许我对正则表达式不够熟练

因此,我认为最好首先搜索所有行中出现的所有字母,并将它们放在一个列表中,然后通过在列表中切片来选择出现的字母

对于在一行中搜索字母,我首先觉得正则表达式是合适的。因此,使用函数selectRE的解决方案

战后,我意识到在一行中选择字母与在方便的索引中切片一行是一样的,这与切片一个列表是一样的。因此,函数选择

我同时给出了这两个解,因此可以验证这两个函数的两个结果的相等性

import re

def selectRE(a,which_chars,b,x,which_lines,y,ch):
    ch = ch[:-1] if ch[1]=='\n' else ch # to obtain an exact number of lines
    NL = ch.count('\n') +1 # number of lines

    def pat(a,which_chars,b):
        if which_chars=='to':
            print repr(('.{'+str(a-1)+'}' if a else '') + '(.{'+str(b-a+1)+'}).*(?:\n|$)')
            return re.compile(('.{'+str(a-1)+'}' if a else '') + '(.{'+str(b-a+1)+'}).*(?:\n|$)')
        elif which_chars=='before':
            print repr('.*(.{'+str(a)+'})'+('.{'+str(b)+'}' if b else '')+'(?:\n|$)')
            return re.compile('.*(.{'+str(a)+'})'+('.{'+str(b)+'}' if b else '')+'(?:\n|$)')
        elif which_chars=='after':
            print repr(('.{'+str(b)+'}' if b else '')+'(.{'+str(a)+'}).*(?:\n|$)')
            return re.compile(('.{'+str(b)+'}' if b else '')+'(.{'+str(a)+'}).*(?:\n|$)')

    if   which_lines=='to'    :  x   = x-1
    elif which_lines=='before':  x,y = NL-x-y,NL-y
    elif which_lines=='after' :  x,y = y,y+x

    return pat(a,which_chars,b).findall(ch)[x:y]


def select(a,which_chars,b,x,which_lines,y,ch):
    ch = ch[:-1] if ch[1]=='\n' else ch # to obtain an exact number of lines
    NL = ch.count('\n') +1 # number of lines

    if   which_chars=='to'    :  a   = a-1
    elif which_chars=='after' :  a,b = b,a+b

    if   which_lines=='to'    :  x   = x-1
    elif which_lines=='before':  x,y = NL-x-y,NL-y
    elif which_lines=='after' :  x,y = y,y+x

    return [ line[len(line)-a-b:len(line)-b] if which_chars=='before' else line[a:b]
             for i,line in enumerate(ch.splitlines()) if x<=i<y ]


ch = '''line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
'''
print ch,'\n'

print 'Characters 3-6 of lines 3-5. A total of 3 matches.'
print selectRE(3,'to',6,3,'to',5,ch)
print   select(3,'to',6,3,'to',5,ch)
print
print 'Characters 1-5 of lines 4-5. A total of 2 matches.'
print selectRE(1,'to',5,4,'to',5,ch)
print   select(1,'to',5,4,'to',5,ch)
print
print '7 characters before the last 3 chars of lines 2-6. A total of 5 matches.'
print selectRE(7,'before',3,2,'to',6,ch)
print   select(7,'before',3,2,'to',6,ch)
print
print '6 characters before the 2 last characters of 3 lines before the 3 last lines.'
print selectRE(6,'before',2,3,'before',3,ch)
print   select(6,'before',2,3,'before',3,ch)
print 
print '4 last characters of 2 lines before 1 last line. A total of 2 matches.'
print selectRE(4,'before',0,2,'before',1,ch)
print   select(4,'before',0,2,'before',1,ch)
print
print 'last 1 character of 4 last lines. A total of 2 matches.'
print selectRE(1,'before',0,4,'before',0,ch)
print   select(1,'before',0,4,'before',0,ch)
print
print '7 characters before the last 3 chars of 3 lines after the 2 first lines. A total of 5 matches.'
print selectRE(7,'before',3,3,'after',2,ch)
print   select(7,'before',3,3,'after',2,ch)
print
print '5 characters before the 3 last chars of the 5 first lines'
print selectRE(5,'before',3,5,'after',0,ch)
print   select(5,'before',3,5,'after',0,ch)
print
print 'Characters 3-6 of the 4 first lines'
print selectRE(3,'to',6,4,'after',0,ch)
print   select(3,'to',6,4,'after',0,ch)
print
print '9 characters after the 2 first chars of the 3 lines after the 1 first line'
print selectRE(9,'after',2,3,'after',1,ch)
print   select(9,'after',2,3,'after',1,ch)

现在我将学习Tim Pietzcker棘手的解决方案请原谅两点:

我提出的解决方案并不完全基于正则表达式。我知道,我读到你需要纯正则表达式解决方案。但是我研究了一个有趣的问题,我很快得出结论,在这个问题上使用正则表达式过于复杂了。我觉得无法用纯正则表达式解答。我找到了下面这些,并展示了它们;也许,他们可以给你一些想法

我不懂C或.NET,只懂Python。由于正则表达式在所有语言中几乎都是相同的,所以我想我只使用正则表达式来回答这个问题,这就是为什么我开始研究这个问题。现在,我仍然用Python展示我的解决方案,因为我认为无论如何它都很容易理解

我认为通过一个唯一的正则表达式很难捕获文本中出现的所有字母,因为在几行中查找几个字母对我来说似乎是一个在匹配中查找嵌套匹配的问题也许我对正则表达式不够熟练

因此,我认为最好首先搜索所有行中出现的所有字母,并将它们放在一个列表中,然后通过在列表中切片来选择出现的字母

对于在一行中搜索字母,我首先觉得正则表达式是合适的。因此,使用函数selectRE的解决方案

战后,我意识到在一行中选择字母与在方便的索引中切片一行是一样的,这与切片一个列表是一样的。因此,函数选择

我同时给出了这两个解,因此可以验证这两个函数的两个结果的相等性

import re

def selectRE(a,which_chars,b,x,which_lines,y,ch):
    ch = ch[:-1] if ch[1]=='\n' else ch # to obtain an exact number of lines
    NL = ch.count('\n') +1 # number of lines

    def pat(a,which_chars,b):
        if which_chars=='to':
            print repr(('.{'+str(a-1)+'}' if a else '') + '(.{'+str(b-a+1)+'}).*(?:\n|$)')
            return re.compile(('.{'+str(a-1)+'}' if a else '') + '(.{'+str(b-a+1)+'}).*(?:\n|$)')
        elif which_chars=='before':
            print repr('.*(.{'+str(a)+'})'+('.{'+str(b)+'}' if b else '')+'(?:\n|$)')
            return re.compile('.*(.{'+str(a)+'})'+('.{'+str(b)+'}' if b else '')+'(?:\n|$)')
        elif which_chars=='after':
            print repr(('.{'+str(b)+'}' if b else '')+'(.{'+str(a)+'}).*(?:\n|$)')
            return re.compile(('.{'+str(b)+'}' if b else '')+'(.{'+str(a)+'}).*(?:\n|$)')

    if   which_lines=='to'    :  x   = x-1
    elif which_lines=='before':  x,y = NL-x-y,NL-y
    elif which_lines=='after' :  x,y = y,y+x

    return pat(a,which_chars,b).findall(ch)[x:y]


def select(a,which_chars,b,x,which_lines,y,ch):
    ch = ch[:-1] if ch[1]=='\n' else ch # to obtain an exact number of lines
    NL = ch.count('\n') +1 # number of lines

    if   which_chars=='to'    :  a   = a-1
    elif which_chars=='after' :  a,b = b,a+b

    if   which_lines=='to'    :  x   = x-1
    elif which_lines=='before':  x,y = NL-x-y,NL-y
    elif which_lines=='after' :  x,y = y,y+x

    return [ line[len(line)-a-b:len(line)-b] if which_chars=='before' else line[a:b]
             for i,line in enumerate(ch.splitlines()) if x<=i<y ]


ch = '''line1 blah 1
line2 blah 2
line3 blah 3
line4 blah 4
line5 blah 5
line6 blah 6
'''
print ch,'\n'

print 'Characters 3-6 of lines 3-5. A total of 3 matches.'
print selectRE(3,'to',6,3,'to',5,ch)
print   select(3,'to',6,3,'to',5,ch)
print
print 'Characters 1-5 of lines 4-5. A total of 2 matches.'
print selectRE(1,'to',5,4,'to',5,ch)
print   select(1,'to',5,4,'to',5,ch)
print
print '7 characters before the last 3 chars of lines 2-6. A total of 5 matches.'
print selectRE(7,'before',3,2,'to',6,ch)
print   select(7,'before',3,2,'to',6,ch)
print
print '6 characters before the 2 last characters of 3 lines before the 3 last lines.'
print selectRE(6,'before',2,3,'before',3,ch)
print   select(6,'before',2,3,'before',3,ch)
print 
print '4 last characters of 2 lines before 1 last line. A total of 2 matches.'
print selectRE(4,'before',0,2,'before',1,ch)
print   select(4,'before',0,2,'before',1,ch)
print
print 'last 1 character of 4 last lines. A total of 2 matches.'
print selectRE(1,'before',0,4,'before',0,ch)
print   select(1,'before',0,4,'before',0,ch)
print
print '7 characters before the last 3 chars of 3 lines after the 2 first lines. A total of 5 matches.'
print selectRE(7,'before',3,3,'after',2,ch)
print   select(7,'before',3,3,'after',2,ch)
print
print '5 characters before the 3 last chars of the 5 first lines'
print selectRE(5,'before',3,5,'after',0,ch)
print   select(5,'before',3,5,'after',0,ch)
print
print 'Characters 3-6 of the 4 first lines'
print selectRE(3,'to',6,4,'after',0,ch)
print   select(3,'to',6,4,'after',0,ch)
print
print '9 characters after the 2 first chars of the 3 lines after the 1 first line'
print selectRE(9,'after',2,3,'after',1,ch)
print   select(9,'after',2,3,'after',1,ch)

现在我将学习Tim Pietzcker棘手的解决方案,这看起来是一项不需要常规表达式就可以轻松解决的任务,特别是使用LINQ。。。为什么要在这里使用正则表达式?首先,我仅限于.NET 2.0,因此LINQ不是一个选项,不幸的是,其次,我需要正则表达式的灵活性,以允许在这些正则表达式的基础上使用更复杂的表达式,即不选择每个字符,而仅选择一些特定的字符,等等。这些正则表达式令人费解。在我看来,你最好用函数来代替正则表达式来做这件事。我不能理解你大部分的帖子。。。你能举几个例子吗,或者至少一个?为什么不拆分行并选择子字符串?为什么必须用正则表达式来解决这个问题?当前的要求,即行和字符位置,使其成为一个糟糕透顶的选择。这看起来是一项不需要常规表达式就可以轻松解决的任务,特别是使用LINQ。。。为什么要在这里使用正则表达式?首先,我仅限于.NET 2.0,因此LINQ不是一个选项,不幸的是,其次,我需要正则表达式的灵活性,以允许在这些正则表达式的基础上使用更复杂的表达式,即不选择每个字符,而仅选择一些特定的字符,等等。这些正则表达式令人费解。在我看来,你最好用函数来代替正则表达式来做这件事。我不能理解你大部分的帖子。。。你能举几个例子吗,或者至少一个?为什么不拆分行并选择子字符串?为什么必须用正则表达式来解决这个问题?当前的要求,即行和字符位置,使它成为一个糟糕透顶的选择。这当然会起作用,除非它不是正则表达式,正如我所解释的,我需要正则表达式。事实上,我不能100%确定是否可以用正则表达式来实现,但另一方面,在我看来,这样的字符位置选择应该是非常琐碎的。@George你为什么需要正则表达式,当有人必须通读所有这些内容时,你会过分混淆你的意图。主要是向后兼容性和

与其他只接受RegEx作为输入的应用程序的兼容性。这肯定会起作用,除非它不是RegEx,正如我解释的,我需要RegEx。事实上,我不能100%确定是否可以用正则表达式来实现,但另一方面,在我看来,这样的字符位置选择应该非常简单。@George为什么需要正则表达式,当有人必须通读所有这些内容时,你会过分混淆你的意图。主要是向后兼容,以及与其他只接受RegEx作为输入的应用程序的兼容性。+1。我写Regex Hero是为了用正则表达式帮助人们,甚至我也不得不同意你的观点。在大多数情况下,正则表达式是一种工具,可以节省您解析文本的时间。但是,当你花更多的时间按照自己的意愿弯曲正则表达式来完成一些可以用过程代码更容易、更有效地完成的事情时,这种做法就无法达到目的了。谢谢Dan,extensove的回答。这当然是一个很好的解决方案,我知道有几种方法可以按程序实现,但为了向后兼容以及与其他应用程序的兼容性,需要使用RegEx。我加入.net的唯一原因是指定了确切的正则表达式风格,因为它们可能会有所不同。@George:你可能想通过对有用的答案进行投票来表达你的感激之情,特别是当你问了这么复杂的问题并得到了这么详细的答案时。@Tim我当然很乐意,乔治:好吧,我没注意到你还没有注册。那我建议你登记一下。这是值得的。对我们所有人来说:+1。我写Regex Hero是为了用正则表达式帮助人们,甚至我也不得不同意你的观点。在大多数情况下,正则表达式是一种工具,可以节省您解析文本的时间。但是,当你花更多的时间按照自己的意愿弯曲正则表达式来完成一些可以用过程代码更容易、更有效地完成的事情时,这种做法就无法达到目的了。谢谢Dan,extensove的回答。这当然是一个很好的解决方案,我知道有几种方法可以按程序实现,但为了向后兼容以及与其他应用程序的兼容性,需要使用RegEx。我加入.net的唯一原因是指定了确切的正则表达式风格,因为它们可能会有所不同。@George:你可能想通过对有用的答案进行投票来表达你的感激之情,特别是当你问了这么复杂的问题并得到了这么详细的答案时。@Tim我当然很乐意,乔治:好吧,我没注意到你还没有注册。那我建议你登记一下。这是值得的。对我们所有人来说:@Tim是的!非常感谢。这对案例1非常有效!正是我需要的!如果你能为案例2做类似的事情,那就太好了,因为文件的结尾是一个不同的故事,涉及它的表达式有点难。。。!还有一个小的附带问题:为什么在前两行之后得到3行,最后使用{2,4}而不是{3,5},行索引是基于0的吗?对于附带问题:断言检查当前行之前是否有2、3或4行,因此确保当前行是行号3、4或5。要获得以第6行开始的五行,您需要{5,9}。至于编写其他正则表达式:没问题,如果您对有帮助的答案进行投票。@Tim您说服我注册,因为有太多功能对于未注册的用户是禁用的。虽然坦率地说-太糟糕了,这个网站没有提供自己的用户系统。。。不太热衷于在多个站点上共享同一ID。我当然对你的答案投了赞成票似乎我对案例3也有问题-无法理解如何重写正则表达式以使字符从行尾开始计数,即使除了这种情况,它与案例1完全相同。@Tim YES!非常感谢。这对案例1非常有效!正是我需要的!如果你能为案例2做类似的事情,那就太好了,因为文件的结尾是一个不同的故事,涉及它的表达式有点难。。。!还有一个小的附带问题:为什么在前两行之后得到3行,最后使用{2,4}而不是{3,5},行索引是基于0的吗?对于附带问题:断言检查当前行之前是否有2、3或4行,因此确保当前行是行号3、4或5。要获得以第6行开始的五行,您需要{5,9}。至于编写其他正则表达式:没问题,如果您对有帮助的答案进行投票。@Tim您说服我注册,因为有太多功能对于未注册的用户是禁用的。虽然坦率地说-太糟糕了,这个网站没有提供自己的用户系统。。。不太热衷于在多个站点上共享同一ID。我当然对你的答案投了赞成票看起来我在案例3中也有问题——甚至不知道如何重写正则表达式以使字符从行尾开始计数

虽然除了这种情况,这和案例1完全一样。谢谢你,蒂姆!这是一种工作方式,除了在案例3中它没有考虑到B——换句话说,它的行为就好像B=0。此外,我不得不将其修改为?m:?这非常有效,但与案例4的编辑有相同的问题-如果行中的字符数小于a+B,则不会返回匹配。但是,只有当一行中的字符数经过更多的实验之后,我仍然无法让这个正则表达式工作时,情况才会如此。在您插入值之后,虽然它看起来像?m:?但我终于能够为案例3找到正确的正则表达式:?m:.{1,A}?谢谢您,Tim!这是一种工作方式,除了在案例3中它没有考虑到B——换句话说,它的行为就好像B=0。此外,我不得不将其修改为?m:?这非常有效,但与案例4的编辑有相同的问题-如果行中的字符数小于a+B,则不会返回匹配。但是,只有当一行中的字符数经过更多的实验之后,我仍然无法让这个正则表达式工作时,情况才会如此。在插入值之后,虽然它看起来像?m:?但我终于能够为案例3找到正确的正则表达式:?m:.{1,A}?出于某种原因,这一个似乎根本不起作用:尝试到处玩,但没有成功。另外,对于使用\r\n.*here来解释任何一行,通常不能100%确定-因为我们是从文件末尾开始计算的,如果我们到达了第一行,那么在该行内容之前就不会有\r\n和\n,因为它是第一行。在RegexBuddy中工作,如果我正确理解了您的要求。我添加了一个示例说明它的功能。无需担心前导\r\n;当距离增加时,比如说{2,8},如果它击中第一行,它不会有任何伤害。嗯,出于某种原因,这对我来说根本不起作用。我尝试了一些基于.NET的工具,比如Expresso,但在所有情况下都没有匹配项。虽然只是通过查看这个正则表达式,我看不出有什么问题。。。显然,在.NET风格中一定有一些行为不同的东西。而且我绝对确保打开了正确的正则表达式选项。我想我可能已经找到了一个适用于案例2的选项:?m:?出于某种原因,这个选项似乎根本不起作用:尝试到处玩,但没有成功。另外,对于使用\r\n.*here来解释任何一行,通常不能100%确定-因为我们是从文件末尾开始计算的,如果我们到达了第一行,那么在该行内容之前就不会有\r\n和\n,因为它是第一行。在RegexBuddy中工作,如果我正确理解了您的要求。我添加了一个示例说明它的功能。无需担心前导\r\n;当距离增加时,比如说{2,8},如果它击中第一行,它不会有任何伤害。嗯,出于某种原因,这对我来说根本不起作用。我尝试了一些基于.NET的工具,比如Expresso,但在所有情况下都没有匹配项。虽然只是通过查看这个正则表达式,我看不出有什么问题。。。显然,在.NET风格中一定有一些行为不同的东西。我绝对确保打开了正确的正则表达式选项。我想我可能已经找到了一个适用于案例2的选项:?m:?这个选项非常适用于选择行,我将看看是否可以将其适用于案例2。但是这里有一些关于角色选择的有趣的事情。首先,比赛中的字符数似乎不是由{1,3}决定的,而应该是由{5}决定的,它应该是从行尾跳过的字符数。蒂姆,我必须感谢你的巨大贡献。这些正则表达式揭示了如何在正则表达式中处理角色选择任务!这个新编辑几乎解决了这个问题!除一种情况外:如果行中的字符数少于A+B,则匹配中的字符数应为A>匹配中的字符数>0。它目前的工作方式是,如果字符数小于A+B,则根本没有匹配。我尝试将{8}更改为类似于{6,8}的内容,但这似乎也不起作用-它产生的匹配比应有的多…实际上,多亏了从原始表达式中获得的见解,Tim,我也能为案例4找到一个:?m:.{1,A}?=.{B}?:\r\n[^\r]*{D,C+D-1}\z。所以,谢谢你的帮助,蒂姆!你真的帮我解决了这个问题@乔治:太好了!很抱歉,我无法更快地回答,因为我在过去的大部分时间里都不在电脑旁。我很高兴你能自己解决这个问题。这一个在选择线路时非常有效。我将看看是否能将其应用于案例2。但是这里有一些关于角色选择的有趣的事情。首先,比赛中的字符数似乎不是由{1,3}决定的,而应该是由{5}决定的,它应该是从行尾跳过的字符数。蒂姆,我必须感谢你的巨大贡献。这些正则表达式揭示了
一般来说,字符选择任务应该在正则表达式中进行!这个新编辑几乎解决了这个问题!除一种情况外:如果行中的字符数少于A+B,则匹配中的字符数应为A>匹配中的字符数>0。它目前的工作方式是,如果字符数小于A+B,则根本没有匹配。我尝试将{8}更改为类似于{6,8}的内容,但这似乎也不起作用-它产生的匹配比应有的多…实际上,多亏了从原始表达式中获得的见解,Tim,我也能为案例4找到一个:?m:.{1,A}?=.{B}?:\r\n[^\r]*{D,C+D-1}\z。所以,谢谢你的帮助,蒂姆!你真的帮我解决了这个问题@乔治:太好了!很抱歉,我无法更快地回答,因为我在过去的大部分时间里都不在电脑旁。我很高兴你能自己弄明白。