java - 为什么正则表达式可选的非捕获组不作为可选的并且搞砸比赛?

标签 java regex

我正在使用使用正则表达式搜索 html 文档的第 3 方应用程序,在这种情况下,它没有正确的结构(没有头部或主体),并将匹配项作为属性形式返回excel文件。它不解析它们。我已经知道尝试使用正则表达式解析 html 所引起的恐怖。

所以我写了一个正则表达式,它应该捕获段落或列表项中的每个句子,但在检查匹配后我注意到有时它不会匹配所有句子并且一旦该句子或列表项给出一个匹配就会停止匹配错误。几乎总是与列表项一起使用,但偶尔与句子一起使用。在意识到这是人为错误后,我添加了可选的非捕获组,这完全搞砸了一切。

这是我最初编写的在大多数情况下都有效的正则表达式:

([^<>]*?)[.!?<]|[ <"'/]

因为有些句子写错了标点前加了一个空格,所以我加了可选的非捕获组:

([^<>]*?)(?:[ ])?[.!?<]|[ <"/l]

这是它正在搜索的文本的示例:

Buy this because it is soooooooooooooooooooo freaking awesome! If you buy this 
everyone will think you're "cool." You'll get all the babes !<br><br><ul><li>It 
will make you smell better<li>It will make you preform better.</li><li>Will make
you last longer in bed!<li>Will fix any acne problem.</li> <li>It will reduce the
amount you perspire to .01% your normal amount!<br><li>It will make you 
"invincible."</li></ul>

因为它们不能用作 anchor (文本从 html 文件的开头开始)我只是让它立即开始捕获。如您所见,它的编码很糟糕并且存在语法错误,这就是我以这种方式结束它的原因。

第一个捕获了大部分句子但遗漏了一些......第二个返回一堆空白的空匹配,这搞砸了捕获的数组。 就好像把非捕获组后面的都不管了。

我考虑过这样做,但是这会返回匹配的每个单词:

([^<>]*?)[ .!?<]|[ .!?<"/l]

唯一的问题是这会在中间切断一些句子,并且需要第三个范围,我认为它会有很多不同的选项(注意随机的 <br> 标签)并且需要一段时间才能找到它们。

从表面上看,它没有使用可选的非捕获组!为什么是这样?还是我忽略了一些非常简单的事情?我觉得可能是后者。

最佳答案

我想到了这个野兽:

(?:^|\s+|>)((?:[^<>.!?\s])(?:[^<>.!?]|\.\d)+(?:\.(?!\d)"?|!|\?)?)

让我试着解释一下我在这里做什么。

(?:^|\s+|>)       # only start after at the string's beginning, after a row of
                  # spaces, or after closing a tag
                  # this eliminates all in-tag matches (like "li" and "br")
(                 # opening a capturing group that will contain the actual match
(?:[^<>.!?\s])    # require at least one character that is not in the given group
                  # this eliminates matching a single space between two <li>s
                  # NOTE: there are probably better ways to do this
(?:[^<>.!?]|\.\d) # defines possible sentence characters; allow everything but
                  # <, >, ., !, ? EXCEPT FOR . followed by a digit
(?:\.(?!\d)"?|!|\?)?
                  # include possible sentence endings; that is . not followed by
                  # a digit (hence, the negative lookahead), but possibly
                  # followed by ", or !, or ?, or nothing at all
)                 # close the main matching group

现在您应该能够在捕获的索引 1 处访问您的句子。

我相信您可能遇到过我对句子的假设会被打破的情况。但我只能根据你给出的例子来工作,它的所有奇怪之处都包括在内。

关于java - 为什么正则表达式可选的非捕获组不作为可选的并且搞砸比赛?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12824193/

相关文章:

php - preg_replace 去除前导斜线

c# - 正则表达式匹配IP地址+通配符

java - Lambda 表达式在一个接口(interface)上工作吗?

java - 关于在 Eclipse 中生成的 serialVersionUID

regex - 如何在文件内容替换器 teamcity 的变量中转义反斜杠

regex - Django 1.3 传递参数以过滤 url.py 中基于类的通用 ListView

java - 正则表达式 - 捕获组混淆

java - 随机演示主题选择器返回 null

java - GlassFish 应用程序客户端容器

java - 错误: Expecting ")" before end of parameters