非贪婪正则表达式或否定字符 class 哪个更好?

Which would be better non-greedy regex or negated character class?

我需要从字符串 @anything_here@dhhhd@shdjhjs@ 中匹配 @anything_here@。所以我使用了以下正则表达式。

^@.*?@

^@[^@]*@

两种方法都行,但我想知道哪种方法更好。具有非贪婪重复的正则表达式或具有否定字符的正则表达式 class?

显然 ^@[^@]*@ 选项要好得多。

否定字符 class 被量化 greedily 这意味着正则表达式引擎会立即抓取除 @ 之外的 0 个或更多字符,尽可能多.参见 this regex demo 并匹配:

当您使用惰性点匹配模式时,引擎会匹配 @,然后尝试匹配结尾的 @(跳过 .*?)。它在索引 1 处找不到 @,因此 .*? 匹配 a 字符。此 .*? 模式 扩展 的次数与 @ 以外的字符一样多,直到第一个 @.

参见lazy dot matching based pattern demo here,这里是匹配步骤:

如果可能的话,否定字符 类 通常应该优先于惰性匹配。

如果正则表达式成功,^@[^@]*@可以一步匹配@之间的内容,而^@.*?@需要对@之间的每个字符展开s.

当失败时(对于没有结尾 @ 的情况)大多数正则表达式引擎会应用一点魔法并在内部将 [^@]* 视为 [^@]*+,因为有一个清晰的边界在 @ 和非 @ 之间,因此它将匹配到字符串的末尾,识别丢失的 @ 并且不回溯,但立即失败。 .*? 将照常扩展一个字符一个字符。

在较大的上下文中使用时,[^@]* 也永远不会扩展到结尾 @ 的边界,而这对于惰性匹配来说是很有可能的。例如。 ^@[^@]*a[^@]*@ 不会匹配 @bbbb@a@^@.*?a.*?@ 会。

请注意,[^@] 也将匹配换行符,而 . 则不会(在大多数正则表达式引擎中,除非在单行模式下使用)。您可以通过将换行符添加到否定中来避免这种情况 - 如果不需要的话。