我有以下正则表达式:
(\d+\s+[-]\s+.*?(?=\s+-)|\d+\s+[-].*)
正则表达式将使用此文本
"Option 01 - Random phrase - Top Menu",
"Option 02 - Another Random Phrase - Su Menu",
"Option 03 - More 01 Phrase - Menu",
"Option 04 - More Phrase -",
"Option 05 - Simple Phrase"
要这样住
01 - Random phrase ",
02 - Another Random Phrase ",
03 - More 01 Phrase ",
04 - More Phrase ",
05 - Simple Phrase ",
此Regex的功能是获取以数字开头的破折号,并在最后一个破折号之前。例如:
当最终没有踪迹时,基本上会发生这种情况:
但是,在 max_execution_time
上调试此正则表达式会导致您需要63到122个步骤。也就是说,此正则表达式非常慢。
在批评这个问题之前,我已经阅读了正则表达式的所有文档,我想让您知道我所指的是特定术语..一个需要解决的问题。毕竟,这不是网站吗?
告诉我,我该如何解决该正则表达式的缓慢性?
答案 0 :(得分:5)
您不必担心在regex101.com上看到的步骤,因为C#regex库非常可靠。如果您在regex101上使用很长的字符串测试像(?s)a.*?b
这样的简单正则表达式,它将报告灾难性的回溯,而在C#代码中也可以正常工作。
有一种方法可以改进您的模式,因为它有一些冗余:请参见重复的\d+\s+[-]
模式。
您需要的只是
\d+\s+-.*?(?=\s+-|$)
请参见regex101和RegexStorm上的正则表达式演示。
如果.*?(?=\s+-)
仅在-
后有空格时才匹配,请使用
\d+\s+-(?:\s.*?(?=\s+-)|.+)
如果您想对其进行进一步的优化,则可能需要研究导致该问题的unroll-the-loop principle
\d+\s+-(?:\s+\S*(?:\s(?!\s*-)\S*)*|.+)
请参见this regex demo(最小步数)。
在这里,\S*(?:\s(?!\s*-)\S*)*
与.*?(?=\s+-|$)
等效(几乎),但是效率更高,因为在“批”中匹配高达空格的块,仅在以下情况下才检查连字符遇到空格。
详细信息
\d+
-1个以上数字\s+
-超过1个空格-
-连字符.*?(?=\s+-|$)
-尽可能少的0个字符,直到第一次出现的1+个空格和-
或直到字符串的末尾。(?:\s.*?(?=\s+-)|.+)
-非捕获组:
\s.*?(?=\s+-)
-空格,最少0个字符,最多1个空格和-
|
-或.+
-字符串的其余部分。\S*(?:\s(?!\s*-)\S*)*
:
\S*
-0 +个非空白字符(?:\s(?!\s*-)\S*)*
-重复0次或更多次
\s
-空格(?!\s*-)
-后面没有0+空格和-
\S*
-0 +个非空白字符答案 1 :(得分:2)
您也可以尝试\d+\s+-[^-]*
来获得所需的内容。到目前为止,步骤数最少。或者,您可以添加\d+\s+-[^-]*(?=\s)
,以防需要在-
之前剪切它。 demo
答案 2 :(得分:1)
正如其他人在评论中指出的那样,尚不清楚Regex应该做什么,因为您似乎不想从潜在的匹配中捕获任何东西。但是无论如何,我还是建议使用以下正则表达式,它将选项字符串解析为其基本组件:
^[^\d]*\d+\s+-\s+.*?(?:\s+-\s+.*?)?$
从此开始,您可以在要捕获的部分周围添加括号。例如:
^[^\d]*(\d+)\s+-\s+(.*?)(?:\s+-\s+(.*?))?$
这将捕获选项号和破折号之间的文本。对于选项04和05,第三次捕获将为空。
编辑:现在,问题的作者已经阐明了应该捕获哪些子字符串,我想这个简单明了的正则表达式是合适的:
\d+[^-]*-[^-"]*
它捕获选项号,搜索第一个破折号,然后捕获直到下一个破折号或引号的所有内容:
<01 - Random phrase >
<02 - Another Random Phrase >
<03 - More 01 Phrase >
<04 - More Phrase >
<05 - Simple Phrase>
请注意,此处仅添加了尖括号以显示尾随空格。这就是你想要的吗?