gpt4 book ai didi

.net - 将正则表达式与一个单词的可变长度后视和另一个单词的可变长度负后视相匹配?

转载 作者:行者123 更新时间:2023-12-01 09:52:44 24 4
gpt4 key购买 nike

我有一个正则表达式,仅当字符串在 A 之前的某处包含模式 B 时才捕获模式 A

为了简单起见,假设A\b\d{3}\b (即三位数)和 B 是单词“foo”。

因此我的正则表达式是 (?<=\b(?:foo)\b.*?)(?<A>\b\d{3}\b) .

(?<=               # look-behind
\b(?:foo)\b # pattern B
.*? # variable length
)
(?<A>\b\d{3}\b) # pattern A

例如,对于字符串

"foo text 111, 222 and not bar something 333 but foo 444 and better 555"

它捕获

(111, 222, 333, 444, 555)

我有一个新要求,现在我必须排除以模式 C 开头的捕获,假设 C 是单词“bar”。我想要构建的是一个表达

(?<=               # look-behind
\b(?:foo)\b # pattern B
??????????? # anything that does not contains pattern C
)
(?<A>\b\d{3}\b) # pattern A

因此,在示例字符串中我必须捕获

(111, 222, 444, 555)

当然是像 (?<=\b(?:foo)\b.*?)(?<!\b(?:bar)\b.*?)(?<A>\b\d{3}\b) 这样的东西

(?<=               # look-behind
\b(?:foo)\b # pattern B
.*?
)
(?<! # negative look-behind
\b(?:bar)\b # pattern C
.*?
)
(?<A>\b\d{3}\b) # pattern A

将不起作用,因为它会在第一次出现“bar”之后排除所有内容,并且捕获将是

(111, 222)

正则表达式 (?<=\b(?:foo)\b(?!.*?(?:\bbar\b)).*?)(?<A>\b\d{3}\b)

(?<=                     # look-behind
\b(?:foo)\b # pattern B
(?! # negative lookahead
.*? # variable lenght
(?:\bbar\b) # pattern C
)
.*? # variable lenght
)
(?<A>\b\d{3}\b) # pattern A

也不会工作,因为对于我的测试字符串中的第一个“foo”,它总是会找到“bar”作为后缀并且它只会捕获

(444, 55)

到目前为止,使用Conditional Matching of Expressions并且(现在)知道while inside a lookbehind, .net matches and captures from the right to the left , 我能够创建以下正则表达式 (?<=(?(C)(?!)| (?:\bfoo\b))(?:(?<!\bbar)\s|(?<C>\bbar\s)|[^\s])*)(?<A>\b\d{3}\b)

(?<=                     # look-behind
(?(C) # if capture group C is not empty
(?!) # fail (pattern C was found)
| # else
(?:\bfoo\b) # pattern B
)
(?:
(?<!\bbar)\s # space not preceeded by pattern C (consume the space)
|
(?<C>\bbar\s) # pattern C followed by space (capture in capture group C)
|
[^\s] # anything but space (just consume)
)* # repeat as needed
)
(?<A>\b\d{3}\b) # pattern A

它有效,但太复杂了,因为模式 ABC 比我在这里发布的示例要复杂得多.

是否可以简化这个正则表达式?也许使用平衡组?

最佳答案

您可以使用基于 \G anchor 的模式来匹配上一次匹配之后的位置:

(?:\G(?!\A)|\bfoo\b)(?:(?!\b(?:bar|\d{3})\b).)*(\d{3})

demo

详情:

(?:
\G(?!\A) # contiguous to a previous match and not at the start of the string
| # OR
\bfoo\b # foo: the condition for the first match
)
(?:(?!\b(?:bar|\d{3})\b).)* # all that is not "bar" or a 3 digit number (*)
(\d{3})

(*) 请注意,如果您可以针对您的实际情况使用更好的子模式(即不使用包含交替的前瞻性来测试每个字符),请毫不犹豫地更改它. (例如,基于字符类的东西:[^b\d]*(?>(?:\B[b\d]+|b(?!ar\b)|\d(?!\d\d\b))[^b\d]*)*)


另一种方式:由于.net regex engine 能够存储重复的捕获,你也可以这样写:

\bfoo\b(?:(?:(?!\b(?:bar|\d{3})\b).)*(\d{3}))+

但是这一次,您需要遍历 foo 的每次出现以提取第 1 组中的结果。它不那么方便但模式更快,因为它不是以交替开始的。

请注意,如果 "bar""\d{3}" 以单词字符开头和结尾,您可以以更有效的方式编写模式:

\bfoo(?:\W+(?>(?!bar\b)\w+\W+)*?(\d{3}))+\b

其他方式:将字符串拆分为“foo”和“bar”(保留定界符),循环遍历每个部分。当部分是“foo”时,将标志设置为 true,当部分是“bar”时,将其设置为 false,当它不是“foo”或“bar”时,如果标志为真,则提取数字。

关于.net - 将正则表达式与一个单词的可变长度后视和另一个单词的可变长度负后视相匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34813707/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com