首页 > 解决方案 > 分隔符之间的正则表达式捕获,除非分隔符在其他分隔符之间

问题描述

我正在尝试在 Javascript 中组合一个正则表达式,它可以捕获两个定界符(连字符-)之间的所有内容,如下所示(以粗体捕获的文本):

    -大家好!- 我在这!

但是,我也使用大括号来表示特殊信息,如下所示:This is {special} stuff here.在大括号内发现的任何连字符分隔符都应该被忽略:

    -这个 {stuff} 匹配- 这里。
    - {这里-}没有找到匹配项。
    -但是最后一个 {hyphen-} 有效-

此外,连字符应该只匹配最外面的偶数连字符。也就是说,里面可能有额外的连字符,但仅限于偶数对:

    -一些 - 内部连字符 - 在里面- 这里。
    -一些 -- 内部连字符- 但外面的奇怪连字符 -。
    -内部连字符 -inside- {braces-} -在这个计数中仍然被忽略- 像往常一样 -
    -必须计算 - 和 {the-braces}之前和之后的连字符 -

此外,我需要平衡所有这些,同时仍然允许半括号工作。也就是说,如果没有右大括号,则连字符是合法的,如果没有左大括号,连字符也是合法的:

    -这是{很好-
    -这也是- 这里}

我可以让偶数连字符与类似的东西相匹配^-((?:[^-]|(?:[^-]*?-){2})*)-,(我的每个案例-都以行开头的 a 开头)但是在这上面添加大括号让我头疼。我在这里问了一个较早的相关问题,关于忽略大括号内的文本,但上下文不同,我似乎无法在那里解决它。

标签: javascriptregex

解决方案


我修改了您的正则表达式以忽略大括号内的所有连字符:

/^-((?:(?:(?!{.*?})[^-\n]|{.*?})|(?:(?:(?!{.*?})[^-\n]|{.*?})*?-){2})*)-/

演示可以在这里找到。该演示包含\n在各个[^-]部分中,因为它将整个文件作为输入而不是逐行进行。

与你原来的正则表达式相比,我已经[^-]用这个替换了这两个部分:

(?:(?!{.*?})[^-]|{.*?})

这段逻辑确保不计算大括号之间的连字符。它必须包含两次以确保在“偶数计数器”中也跳过大括号之间的连字符。

我使用了先行条件来检查是否有匹配的右大括号,按照此处所述重写以支持 javascript。如果找到右大括号,我们将无条件匹配大括号之间的整个部分。如果找不到右大括号,我们将其视为普通字符。

它还不支持正确的嵌套大括号,但可以使用与连字符类似的构造来添加。

为什么需要负前瞻?

目标是跳过大括号之间的所有连字符。为了解释它是如何工作的,让我们考虑以下更简单的正则表达式^-(?:[^-]|{.*?})*-:此正则表达式尝试查找不在大括号之间的下一个连字符。

[^-]部分使用任何不是连字符的字符。正则表达式执行器将逐个字符地遍历字符串,直到遇到连字符。

- 未找到匹配项 {这里|-}。

它不会使用另一个选项,因为第一个就足够了。在这个位置,下一个字符是连字符。这将匹配正则表达式中的最后一个连字符,完成匹配过程。

- 未找到匹配项 {这里- |}。

不幸的是,这个连字符在大括号之间,应该被忽略。


可以尝试更改选项的顺序,如下所示^-(?:{.*?}|[^-])*-:如果我们尝试另一个示例,我们将看到它可以正常工作:

-但最后一个 {hyphen-} 有效- |

但是,当我们使用原始示例时,出现了问题。不同之处发生在这个位置:

-未找到匹配项|{这里-}。

在这里,正则表达式执行器首先尝试跳过大括号之间的内容,如下所示:

-没有找到匹配{这里-} |。

然后它将无法在字符串的其余部分中找到连字符。但是正则表达式执行器并不愚蠢。有两个选项,所以它只会在左大括号处尝试第二个选项。这允许执行器在大括号之间输入内容,它会在那里找到连字符:

- 未找到匹配项 {这里- |}。

当我们添加负前瞻时,正则表达式看起来像这样^-(?:(?!{.*?})[^-]|{.*?})*-:同样,不同之处在于这个位置:

-未找到匹配项|{这里-}。

在这里,负前瞻匹配。这会强制正则表达式执行器使用其他选项。这样做会导致以下情况:

-没有找到匹配{这里-} |。

正则表达式执行器跳过了大括号之间的整个部分,负前瞻确保回溯不会改变这一点。因为第二个连字符在大括号之间,并且正则表达式执行器不会进入大括号,所以它找不到第二个大括号,并将这个字符串标记为“不匹配”。


推荐阅读