Regex 高效的正则表达式,用于要求特定的句型,但允许html等

Regex 高效的正则表达式,用于要求特定的句型,但允许html等,regex,Regex,(通常情况下,在写这篇文章时,我认为我已经修复了表达式本身,因此它现在可以用于我的目的,因此效率现在是我的主要关注点——但我仍然希望了解表达式是否可以改进,或者是否会超出应有的范围,因此我将整个解释留在了文档中。) 我正在尝试编写一个正则表达式,它将验证用户提交的文本是否符合长度要求。用户必须写出7个或更多完整的句子,包含4个或更多单词。我们将其定义如下: - 4 words means 3 or more sections of '1 or more non-space characters

(通常情况下,在写这篇文章时,我认为我已经修复了表达式本身,因此它现在可以用于我的目的,因此效率现在是我的主要关注点——但我仍然希望了解表达式是否可以改进,或者是否会超出应有的范围,因此我将整个解释留在了文档中。)

我正在尝试编写一个正则表达式,它将验证用户提交的文本是否符合长度要求。用户必须写出7个或更多完整的句子,包含4个或更多单词。我们将其定义如下:

- 4 words means 3 or more sections of '1 or more non-space characters followed by 1 or more spaces', then 1 instance of '1 or more non-space characters optionally followed by a space' (because some people like to put spaces before their punctuation marks I guess)  
- A sentence is ended with a punctuation mark (.?!)  
- Zero or more spaces are allowed after each sentence  
- (Repeat 7 times)  
这个定义可以更改为任何合理的定义,但到目前为止,我就是这么想的。这给了我以下正则表达式:

((\S+\s+){3,}\S+[.?!]\s*){7,}  
这似乎有效,但我显然捏造了很多东西,不知道是否有人有更好的想法。(它必须允许在任何时候使用html,以及用户编写的许多其他怪癖。我不太担心玩系统的人——仍然有手动检查,这只是减轻负载的第一阶段检查。)


我的另一个主要关注点是效率——我不熟悉正则表达式,不知道什么是“正常”计算时间,但我正在使用的调试器在我粘贴文本块进行检查时遇到困难,我不知道这是由我的正则表达式还是调试器引起的。在文本中没有匹配项的较长部分,它通常会超时。有没有更有效的方法来完成我想要的…?

首先,在进行全文匹配时,始终用
^…$
包围正则表达式
^
将正则表达式的开头锚定到验证字符串的开头,
$
将正则表达式的结尾锚定到字符串的结尾。否则,如果不匹配,它将从每个字符开始重复验证尝试(至少(4个单词*3个空格)*7个句子=工作量过大)

第二,尽可能使用相互排斥的组
\S(任何非空白的内容)
包括字符
,因此如果找不到标点符号,它必须回溯并重试它匹配的每个
\S
。(也就是说,因为第一遍会将其标记为一个单词而不是标点符号),所以我建议将
\S
替换为相互排斥的“非空白或标点符号”
[^\S.?!]
。请注意,[]包含小写字母s,而不是大写字母s<代码>[^…]
是“匹配不在此组中的任何字符”

这两件事会让你从灾难性的回溯下降到合理的~1-3k步数,具体取决于段落长度

更新:
如果您允许对验证逻辑进行小的修改,使多个短句可以一起算作一个句子,那么下面的正则表达式就可以了

^(\s*(\S+\s+){3}([.?!]\s*)?([^\s.?!]+\s+)*\S+\s*[.?!]){7,}$
这种混合版本将允许短句而不会造成灾难性的回溯。如果没有小的规则更改,您将需要在可变长度模式中嵌套可变长度模式;当模式不完全互斥时,这是灾难性的。(最新演示)

另外,从技术上讲,你可以用
{7}
替换
{7}
,如果一旦找到7个句子,你就不在乎后面会发生什么。(这将使正则表达式在发现最低生存能力后立即停止,这将更容易接受某些极端边缘情况)


(你可以在regex101.com上玩它)

我认为只解析输入文本,搜索单词标记和标点,并保留必要的计数器比只使用regex更有效。似乎正则表达式太多了。你用的是什么语言?你为什么要用正则表达式?这并不是解决此问题的最佳解决方案。正则表达式解析器在不同的编程语言中实现方式不同(这也意味着它们有不同的风格),其中一些非常有效,有些则不然。请注意,
\s
是所有空白字符的字符集,而不仅仅是空格。如果你只想匹配空格,你应该只使用“`”(一个文字空格)。不幸的是,我不太了解这个系统的使用情况,因为我正在帮助一个朋友(他也不太了解),而且我自己也无法访问它(无用,我知道)。基本上,系统会给我们一个方框,上面写着“如果你愿意,可以在这里放一些正则表达式”,这是除了最大长度或字段类型之外的唯一验证选项。因此使用RegEx(到目前为止,我最喜欢的调试器恰好是regex101)。我将尝试锚定,虽然我有点想弄清楚我是否确实想要两个锚定-我有点担心它错误地失败了某些事情?不过,我会测试一下。对于替换,我想让它接受,比方说,8个句子,其中一个中间句子只有3个单词,这肯定会让它失败,因为它遇到了一个不符合4个单词要求的句子结尾?当我添加锚时,它会给我灾难性的回溯。。。但是如果没有它们,它会接受我正在使用的文本。因此,我认为锚定对于我想要检查的内容来说是个问题,但这也告诉我,系统通常会拒绝的任何很长的文本都将导致灾难性的回溯,因为它没有足够快地找到匹配项。。。听起来很糟糕?有没有一个标准的方法,一个系统可以处理类似的事情-它很可能只是超时并拒绝?(我不想冒险破坏整个该死的网站,因为它不是我的…)@RosieThomas用混合解决方案更新了答案。至于失败部分,由于regex更像是一个规范,引擎是如何实现的(regex风格)以及调用regex的代码是如何编写的,这可以从“regex失败”到“线程因异常崩溃”不等。我建议您对您的系统进行测试