我正在尝试进行非贪婪的否定匹配,我也需要捕获它。我在 Python 中使用这些标志,re.DOTALL | 重新本地化 | re.MULTILINE,对一些文本文件“数据库”进行多行清理,其中每个字段都以反斜杠开始新行。每条记录都以 \lx 字段开头。
\lx foo
\ps n
\nt note 1
\ps v
\nt note
\ge happy
\nt note 2
\ge lonely
\nt note 3
\ge lonely
\dt 19/Dec/2011
\lx bar
...
我试图确保每个 \ge 字段在其记录中的某个位置上方都有一个 \ps 字段,一对一。目前,一个 \ps 后面经常跟几个 \ge ,因此需要复制下来,就像上面的两个单独的 \ge 一样。
以下是大部分需要的逻辑:在任何 \ps 字段之后,但在遇到另一个 \ps 或 \lx 之前,先找到一个 \ge,然后再找到另一个 \ge。捕获所有内容,以便可以将 \ps 字段复制到第二个 \ge 之前。
这是我的非功能性尝试。替换这个:
^(\\ps\b.*?\n)((?!^\\(ps|lx)*?)^(\\ge.*?\n)((?!^\\ps)*?)^(\\ge.*?\n)
有了这个:
\1\2\3\4\1\5
即使在一个小文件(34 行长)上,我也会遇到内存错误。当然,即使这可行,我也必须多次运行它,因为它只是试图处理第二个 \ge,而不是第三个或第四个。所以这方面的任何想法也会让我感兴趣。
更新: Alan Moore 的解决方案效果很好,尽管有些情况需要稍作调整。可悲的是,我不得不关闭 DOTALL,否则我无法阻止第一个 .* 包括随后的 \ps 字段——即使是非贪婪的 .*? 形式。但是我很高兴刚才在正则表达式点信息中了解了 (?s) 修饰符。这使我可以在一般情况下关闭 DOTALL,但仍可在其他必要的正则表达式中使用它。
这是建议的正则表达式,浓缩为我需要的单行格式:
^(?P<PS_BLOCK>(?P<PS_LINE>\\ps.*\n)(?:(?!\\(?:ps|lx|ge)).*\n)*\\ge.*\n)(?P<GE_BLOCK>(?:(?!\\(?:ps|lx|ge)).*\n)*\\ge.*\n)
那行得通,但是当我修改上面的示例时,它在“注释 2”上方插入了 \ps。它还将 \lxs 和 \ge2 与 \lx 和 \ge 相同(需要一些 \b)。所以,我选择了一个稍微调整的版本:
^(?P<PS_BLOCK>(?P<PS_LINE>\\ps\b.*\n)(?:(?!\\(?:ps|lx|ge)\b).*\n)*\\ge\b.*\n)(?P<AFTER_GE1>(?:(?!\\(?:ps|lx|ge)\b).*\n)*)(?P<GE2_LINE>\\ge\b.*\n)
这个替换字符串:
\g<PS_BLOCK>\g<AFTER_GE1>\g<PS_LINE>\g<GE2_LINE>
再次感谢!