C# 如何不让正则表达式做太多的步骤?
我有一个简单的正则表达式(用于c#): 1) 以“ecua”开头的单词C# 如何不让正则表达式做太多的步骤?,c#,regex,C#,Regex,我有一个简单的正则表达式(用于c#): 1) 以“ecua”开头的单词 2) 无论之后发生什么 3) “embajada”之后的单词“whatever” 但这会造成太多的步骤,我该如何防止呢?我只想让它通过字符,直到找到“embajada”这个词,而不是在每个字符上回溯。这看起来像是简单的正则表达式,但当我使用较大的文本时,当模式失败时,它会抛出灾难性的回溯(或超时) 例如: 提前谢谢这就是你要找的吗\b(ecua\w+).*?(embajada)这就是你要找的吗\b(ecua\w+).*?(e
2) 无论之后发生什么
3) “embajada”之后的单词“whatever”
但这会造成太多的步骤,我该如何防止呢?我只想让它通过字符,直到找到“embajada”这个词,而不是在每个字符上回溯。这看起来像是简单的正则表达式,但当我使用较大的文本时,当模式失败时,它会抛出灾难性的回溯(或超时) 例如:
提前谢谢这就是你要找的吗<代码>\b(ecua\w+).*?(embajada)这就是你要找的吗<代码>\b(ecua\w+).*?(embajada)在 下面是不同方法的比较表。第一个是我的,第二个是修改的
OP的regex
,第三个是另一个用户在这里给出的答案的修改版本,第四个是由Wiktor
。不成功的匹配是由于embajada
到embajad
+------+--------+--------+--------+--------+-------+------+--------------+
| Regex | Successful | Unsuccessful |
+------+--------+--------+--------+--------+-------+------+--------------+
| \becua.*embajada | 310 steps | 167543 steps |
| \becua(?:.*)\b(.(?=embajada))*embajada | 993 steps | 579122 steps |
| \becua.*?embajada | 23897 steps | 167543 steps |
| (?>\becua\p{L}*\b\s*\S*)
| (?>(?:\s+(?!embajada)\S*)*)\s+embajada | 18001 steps | 111394 steps |
+------+--------+--------+--------+--------+-------+------+--------------+
第一个正则表达式似乎在成功和不成功的匹配中采取最少的步骤
下面是不同方法的比较表。第一个是我的,第二个是修改的OP的regex
,第三个是另一个用户在这里给出的答案的修改版本,第四个是由Wiktor
。不成功的匹配是由于embajada
到embajad
+------+--------+--------+--------+--------+-------+------+--------------+
| Regex | Successful | Unsuccessful |
+------+--------+--------+--------+--------+-------+------+--------------+
| \becua.*embajada | 310 steps | 167543 steps |
| \becua(?:.*)\b(.(?=embajada))*embajada | 993 steps | 579122 steps |
| \becua.*?embajada | 23897 steps | 167543 steps |
| (?>\becua\p{L}*\b\s*\S*)
| (?>(?:\s+(?!embajada)\S*)*)\s+embajada | 18001 steps | 111394 steps |
+------+--------+--------+--------+--------+-------+------+--------------+
第一个正则表达式似乎在成功匹配和不成功匹配中采取的步骤最少您可以用贪婪的方式编写模式,但这次使用原子组中的量词封闭所有部分。要做到这一点,您显然需要进行前瞻性测试,但为了限制过多测试的影响,您可以使用字符类([^e]
此处)帮助正则表达式引擎仅在感兴趣的位置执行测试:
\becua(?>\w*[^e]*(?:\Be[^e]*|e(?!mbajada\b)[^e]*)*)embajada
详情:
\becua
(?>
\w* # last part of "ecua..."
[^e]* # all that is not an "e"
(?:
\Be # an "e" not at the start of a word
[^e]*
|
e(?!mbajada\b) # an "e" that is not the start of "embajada"
[^e]*
)* # repeat as possible
) # close the atomic group (backtracking is no more possible)
embajada
现在是一种非贪婪的方法(限制非贪婪量词影响的相同想法):
您可以用贪婪的方式编写模式,但这次将所有部分用量词封装在一个原子组中。要做到这一点,您显然需要进行前瞻性测试,但为了限制过多测试的影响,您可以使用字符类([^e]
此处)帮助正则表达式引擎仅在感兴趣的位置执行测试:
\becua(?>\w*[^e]*(?:\Be[^e]*|e(?!mbajada\b)[^e]*)*)embajada
详情:
\becua
(?>
\w* # last part of "ecua..."
[^e]* # all that is not an "e"
(?:
\Be # an "e" not at the start of a word
[^e]*
|
e(?!mbajada\b) # an "e" that is not the start of "embajada"
[^e]*
)* # repeat as possible
) # close the atomic group (backtracking is no more possible)
embajada
现在是一种非贪婪的方法(限制非贪婪量词影响的相同想法):
你必须使用(?=embajada)
而不是(?!embajada)
,我想你的文本中没有“embajada”这个词,只有“gembajada”。我会展开它:不要太激动。先看看有什么问题。当你包含\s+
时没有匹配,因为没有\sembajada
,只有\sgembajada
@WiktorStribiż如果没有匹配你必须使用(?=embajada)
而不是(?!embajada)
,我认为没有“embajada”这个词在你的文本中,只有“gembajada”。我会展开它:不要太激动。先看看有什么问题。当您包含\s+
时,没有匹配项,因为没有\sembajada
,只有\sgembajada
@WiktorStribiż如果没有匹配项,它将导致灾难性的回溯
。您正在从注释中尝试我的模式:)?美好的最好显示来自的测试。我最新的(?>\becua\p{L}*\b\s*\s*)(?>(?:\s+(?!embajada)\s*))\s+embajada
显示每秒78,2次迭代。请参阅Casimir的答案,研究该模式。比我的快三倍。@WiktorStribiżew看起来像,regexhero.net/tester
上的analyze
功能只对专业人士可用users@WiktorStribiżew我没有得到基准选项中的任何内容。明天将检查它。您正在尝试我的评论模式:)?美好的最好显示来自的测试。我最新的(?>\becua\p{L}*\b\s*\s*)(?>(?:\s+(?!embajada)\s*))\s+embajada
显示每秒78,2次迭代。请参阅Casimir的答案,研究该模式。比我的快三倍。@WiktorStribiżew看起来像,regexhero.net/tester
上的analyze
功能只对专业人士可用users@WiktorStribiżew我没有得到基准选项中的任何内容..我明天会检查它。注意:\w
将匹配\u
和数字,我认为\p{L}
是[a-zA-Záíóúñúñúëëöü]
的更好替代品。谢谢兄弟!!它起作用了!!我选择第二个正则表达式是因为它更容易实现(我需要将用户插入的关键字转换成正则表达式)。有一句话:\w
将匹配\u
和数字,我认为\p{L}
是[a-zA-Záíóúñëëöü]
的更好替代品。谢谢兄弟!!它起作用了!!我选择第二个正则表达式是因为它更容易实现(我需要将用户插入的关键字转换为正则表达式)。它可以工作,但失败时会执行117k个步骤。一个用户对一个正则表达式进行了注释,该正则表达式在相同情况下执行66k个步骤,但在失败时会执行117k个步骤,一个用户对一个在相同情况下执行66k步的正则表达式进行了注释