【问题标题】:Negative lookahead preceded by .*以 .* 开头的负前瞻
【发布时间】:2020-08-21 15:39:59
【问题描述】:

我想选择{} 中的所有文本,但前提是其中没有\status…{}

应匹配的示例:

\subsection{Hello}                -> "\subsection”, "Hello"
\section{Foobar}                  -> "\section", "Foobar"
\subsubsection{This is a Triumph} -> "\subsubsection", "This is a Triumph"

应该匹配的示例:

\subsection{Hello\statusdone{}}
\section{Hello World\statuswip{}}
\section{Everything\statusproofreading{}}

我认为负前瞻非常适合:

(\\.*section)\{(.*)(?!\\status.*)\}

但它们匹配:

\subsection{Hello\statusdone{}}           -> "\subsection", "Hello\statusdone{}"
\section{Hello World\statuswip{}}         -> "\section", "Hello World\statuswip{}"
\section{Everything\statusproofreading{}} -> "\section", "Everything\statusproofreading{}"

我怀疑这是因为.* 在否定前瞻之前。如果我在以下正则表达式中将其替换为例如Hello

(\\.*section)\{(Hello)(?!\\status.*)\}

它正确地不匹配第一个负例\subsection{Hello\statusdone{}}

我该如何解决这个问题?

【问题讨论】:

    标签: regex negative-lookbehind


    【解决方案1】:

    正则表达式没有针不在大海捞针测试仪内。 (或者至少不是常见的实现。)

    您对零宽度断言的工作方式感到困惑。这是一场 ANY 比赛,而不是一场 ALL 比赛。第一个位置匹配的那一刻,它适合并返回它。

    你有一个两通的工作摆在你面前。第一个问题是您在 LaTeX 或其他任何地方没有正则语言,这意味着正则表达式不适用于任意文本。

    \section{\math{\ref{\status{asfd}}}} 和你匹配的最后一个“}”等

    你需要一个解析器来做这件事,而不是正则表达式。对不起。

    【讨论】:

    • 你是绝对正确的,RegEx 不是处理 LaTeX 的理想工具。但这都是 VS Code 提供的。这是一个非常狭窄和有限的用例,我不打算把它变成一个库或任何东西:)我仍然不太明白为什么 .* 会匹配整个字符串,如果有负前瞻到位:在“Hello\statusdone{}”中,它匹配“Hello”,我可以看到它只会匹配“Hell”,因为它是 ANY 而不是 ALL 匹配。但为什么是整个字符串?为什么在这种情况下它可以忽略前瞻?
    • “.*”不必在某个位置匹配。通过添加零宽度断言,您只是排除了星号可能停止的一些位置。星号是贪心的,所以它先扫描到字符串的末尾,然后开始回溯。在每个位置,它会判断这是否是匹配星号之后即将发生的事情的合适位置,并且您已在下一个断言中排除了其中一些位置。
    • 如果你让星号不贪婪,它可能会有所帮助,但它会导致其他问题。
    【解决方案2】:

    您应该在模式中将负前瞻移动到更早的位置,以便它在整个字符串 (.*) 被消耗之前检查该子字符串是否存在。

    你可以使用:

    \\.*section\{((?!.*\\status.*\{\})[^}]+)}
    

    现场演示here

    【讨论】:

      猜你喜欢
      • 2017-03-27
      • 1970-01-01
      • 2016-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 2020-07-03
      相关资源
      最近更新 更多