【问题标题】:How can i optimize this regex?我该如何优化这个正则表达式?
【发布时间】:2015-12-08 22:08:45
【问题描述】:

我有这段文字:

before label bla bla bla aaaa<TAG1>bbbb bla bla bla bla abcd<TAG2>efgh after

还有这个正则表达式:

label\W+(?:\w+\W+){1,60}?(?:.){0,}?(\<TAG1\>|\<TAG2\>)(?:.){0,}?\W+(?:\w+\W+){1,60}(?:.){0,}?(\<TAG2\>|\<TAG1\>)(?:.){0,}?

它完成了这项工作,它按预期工作,但似乎并没有真正优化。

这是一个测试:https://regex101.com/r/eS2kS6/1

基本上我必须找到一个标签,在 N 个单词之后我应该得到 &lt;TAG1&gt;&lt;TAG2&gt;,在 N 个单词之后我应该得到 &lt;TAG1&gt;&lt;TAG2&gt;

注意:

必须将&lt;TAG1&gt;&lt;TAG2&gt; 视为单词的可能“子字符串”,这一点非常重要。有时可以是aaaa&lt;TAG1&gt;bbbb,有时直接是&lt;TAG1&gt;。正如您在示例中看到的那样,它适用于两种情况。

【问题讨论】:

  • 所有'n个单词'的东西似乎都是多余的,因为你已经在标签之前、之间和之后匹配了'any'。

标签: java regex


【解决方案1】:

通常有助于可视化正则表达式:

请注意,(?:.){0,}? 是表示.* 的一种迂回方式。现在也很容易看到有两个相同的块可以合并,所以让我们解决这个问题:

label\W+(?:(?:\w+\W+){1,60}?.*(\<TAG1\>|\<TAG2\>).*){2}

这是等效的,但更短。从这里开始,问题就变成了你到底想匹配什么。所有这些\ws 和\Ws 对我来说看起来有点奇怪,尤其是与.'s 一起使用时。我通常更喜欢匹配 \s 而不是 \W,因为我通常确实是指“某种空白”,但您需要确定您真正需要的。

您使用的“匹配一个到六十个单词而不是单词跟随任何东西”模式 ((?:\w+\W+){1,60}?.*) 可能不是您想要的 - 它会匹配 a$&lt;TAG例如,但不是a&lt;TAG。如果您想允许一个或多个单词,请尝试(?:\s*\w+)+。这匹配零个或多个空格,后跟一个或多个字符,一次或多次。如果您想将其限制为60,您可以将最终的+ 替换为{1,60}(但从您的描述中不清楚60 的来源——您需要它吗?)。

这就是我们现在的位置:

label\s+(?:(?:\w+\s*)+(\<TAG1\>|\<TAG2\>)\w*){2}

这与您之前的模式完全 不同 - 它与您的示例字符串中的 after 不匹配(从您的描述中不清楚它是否应该)。如果要在第二个标签之后继续匹配,只需在末尾添加.*即可。


话虽如此,看起来很像您正在尝试解析复杂的语法(即non-regular language),即rife with peril。如果您发现自己正在编写和重写正则表达式以尝试使其捕获所需的数据,则可能需要升级到适当的上下文解析器。

特别是,您的正则表达式和我的调整都不会强制 N 每次都相同。您的描述听起来好像您只想匹配第一个标签之前有 N 单词的字符串,并且恰好在它和第二个标签之间有 N 单词。使用正则表达式可能会实现这种匹配,但它肯定不会是干净的。如果这是一个要求,那么正则表达式可能不是正确的工具。

【讨论】:

  • 我不必解析 HTML 文档。 是我需要检查的单词示例。但它可以替换为例如“狗”和“猫”。但是我的目标是一种文本挖掘,我必须找到特定的模式并提取内容。什么是适合您的工具?
  • 我没有说你在解析 HTML 文档,我说你可能正在解析一种非常规语言(而 HTML 是这种语言的常见示例)。一个流行的语法生成器和解析器是ANTLR,但还有很多其他的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-21
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 2012-01-30
  • 1970-01-01
相关资源
最近更新 更多