匹配在第一个行的下一次出现之前没有跟随另一个特定行的特定行

Match a specific line that is not followed by another specific line before the next occurrence of the first one

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

...
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 .*,这意味着 [=12= 的第一次和最后一次出现] 在示例中。

单独 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.DOTALL (s) 选项但没有成功。

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

如果这里有帮助,请参阅 awk 解决方案:

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

以下正则表达式适用于 MULTILINE 模式 (demo):

^STARTING LINE .+$\n(?!(?:(?!(?:STARTING|ENDING) LINE ).+\n)*ENDING LINE )

解释:

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

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

您可以使用来自 STARTING LINE 的匹配,直到遇到换行符,然后 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 匹配换行符后跟起始行
    • ) 关闭前瞻
    • |
    • (?! 开始否定前瞻
      • [\s\S]*\nENDING LINE 匹配任何字符,包括换行符 0 次以上,后跟换行符和 ENDING LINE
    • ) 关闭否定前瞻
    • [\s\S]*$ 匹配任意字符包括换行符0+次直到字符串结束
  • )关闭非捕获组