为什么正则表达式可选的非捕获组不作为可选和搞砸匹配?

时间:2012-10-10 16:33:10

标签: java regex

我正在使用使用正则表达式搜索html文档的第三方应用,在这种情况下,它没有正确的结构(没有头部或正文),并将匹配作为表单返回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>

因为它们没有什么可用作锚(文本从html文件的开头开始)我只是让它立即开始捕获。如你所见,它的编码很差并且有语法错误,这就是我按照我的方式结束它的原因。

第一个捕获了大部分句子,但遗漏了一些......第二个返回了一堆空匹配的空白,这搞乱了捕获所做的数组。 就像在非捕获组之后无视一切。

我想过这样做,但这会将每个单词作为匹配返回:

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

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

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

1 个答案:

答案 0 :(得分:3)

我想出了这只野兽:

(?:^|\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访问您的句子。

我相信你可能会遇到一些案例,即我对句子看起来像是什么样的假设。但是我只能从你给出的例子开始,包括所有奇怪的东西。