在下一次出现第一个匹配行之前,匹配不由另一个特定行跟随的特定行

时间:2018-10-29 14:58:37

标签: python regex regex-lookarounds regex-group

我将从示例开始,因为它可能是最简单的解释。我们有一个多行文件:

...
STARTING LINE with something 83
...
STARTING LINE with other 12
...
ENDING LINE with yet another info
...
STARTING LINE with another 43
...

...表示除STARTING LINE .*ENDING LINE .*之外的任何内容(多行,包括空行)。

我们必须捕获包含所有的所有STARTING LINE .*,后跟ENDING LINE .*的组,这意味着该示例中STARTING LINE .*的第一个和最后一个出现。

单独STARTING LINE .*STARTING LINE .*...ENDING LINE .*对出现的次数未知。

我尝试了多个具有正向和负向,向前和向后提前的表达式,但从未设法正确捕获出现的情况。

如果需要,我可以提供更多示例,但是可能很难向您提供我已经尝试过的表达式,因为我没有跟踪它们,而当前的表达式捕获了所有出现的事件,包括我们没有发现的事件想要

  1. (^STARTING LINE .*?$)(?!^ENDING LINE)[.\n]+

  2. (^STARTING LINE .*?$(?!.*^ENDING LINE)[.\n]*)

请注意,我们只希望一组中有STARTING LINE .*行。

我们使用带有re.MULTILINE标志(gm)的Python 2.7正则表达式引擎。也尝试了其他re.DOTALLs)选项,但均未成功。

3 个答案:

答案 0 :(得分:1)

以下正则表达式在TCP_FASTOPEN_CONNECT模式(demo)下对我有用:

MULTILINE

说明:

  • ^STARTING LINE .+$\n(?!(?:(?!(?:STARTING|ENDING) LINE ).+\n)*ENDING LINE ) :起始行(由于^STARTING LINE .+\n不需要$
  • \n:零个或多个中间线(由于(?:(?!(?:STARTING|ENDING) LINE ).+\n)*不需要^$
  • \n:结尾行(由于先前的ENDING LINE不需要^

PS。假设您的换行确实是\n,而不是\n

答案 1 :(得分:1)

您可以使用STARTING LINE中的match,直到遇到换行符为止,然后STARTING LINE再次使用正向超前。这样一来,您知道比赛之间至少有STARTING LINE次。

对于最后一次匹配,您可以使用否定的超前查询来检查您是否不能再跟换行符(ENDING LINE)。

^STARTING LINE(?:.*(?:(?!\n(STARTING|ENDING) LINE)\n.*)*(?=\nSTARTING LINE)|(?![\s\S]*\nENDING LINE)[\s\S]*$)

Regex demo

说明

  • ^行的开头
  • STARTING LINE字面上匹配
  • (?:启动非捕获组
    • .*匹配0个以上的字符
    • (?:非捕获组
      • (?!否定断言来断言右边的内容不是
        • \n(STARTING|ENDING) LINE匹配换行符,后跟STARTING LINE或ENDING LINE
      • )关闭捕获组
      • \n.*匹配换行符和0个以上的字符
    • )*关闭负前瞻并重复0次以上
    • (?=肯定在右边的断言是
      • \nSTARTING LINE匹配换行符,后跟STARTING LINE
    • )提前关闭
    • |
    • (?!开始否定超前
      • [\s\S]*\nENDING LINE匹配任意字符,包括换行符0次以上,后跟换行符和ENDING LINE
    • )近距离否定预测
    • [\s\S]*$匹配任意字符,包括换行符0次以上,直到字符串结尾
  • )关闭非捕获组

答案 2 :(得分:0)

恐怕您需要通过流而不是单个正则表达式来解决它。像这样:

如果有帮助,请使用awk解决方案:

$ awk '/^STARTING LINE / { if ( startingline > "" ) { print(startingline); startingline=""; } else { startingline=$0; } } /^ENDING LINE / { startingline=""; } END { if ( startingline > "" ) print(startingline); }' file.txt
STARTING LINE with something 83
STARTING LINE with another 43