regex - 使用正则表达式的大字符串的灾难性回溯问题
问题描述
我正在尝试捕获两个字符串之间的所有内容,问题是我要捕获的这个字符串可以长达 3000 行数字和逗号。因此,当发生这种情况时,我会遇到灾难性回溯的错误。
这是我正在使用的正则表达式,也是下面的示例数据
NEM12[\s\S]+?<\/CSVIntervalData>
<.CSVIntervalData>100,NEM12,201807290900,WBAYM,EEQ 200,3030910307,B1E1K1Q1,03,B1,N1,91111580,kWh,30, 300,20180728,.278,.278,.278,.278,.278, .278,.278,.278,.278,.278,.278,.278,.278,.056,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,.074,.278,.278,.278,.278,.278,.278,.278,.278,.278,.278, .278,.278,.278,E75,,,20180729000320, 900 </CSVIntervalData>
请注意,中间可以有一千行数字、点和逗号
解决方案
您的正则表达式基于惰性匹配模式,如果您需要匹配的字符串很长,这意味着正则表达式引擎的大量开销。当NEM12
匹配到时,</CSVIntervalData>
会尝试,一旦引擎找不到它,它会扩展[\s\S]*?
模式,匹配任何字符,然后再次重新测试</CSVIntervalData>
模式,等等。一旦它多次执行,您可能会遇到问题(在 regex101,您通常会看到超时问题,而不是灾难性的回溯,因为这里没有使用惰性模式进行回溯,回溯仅由贪婪模式触发) .
你可以做的是解开惰性模式:
NEM12[^<]*(?:<(?!/CSVIntervalData>)[^<]*)*</CSVIntervalData>
请参阅正则表达式演示(注意 317 步与 46 步的区别)。
[\s\S]*?
替换为[^<]*(?:<(?!/CSVIntervalData>)[^<]*)*
: 0+ 以外的字符,然后是任何 0+不跟随的<
序列,后跟任何 0+ 以外的字符。虽然它更长,但它匹配块中的文本,并且在预期匹配很长的情况下更快更可靠。如果您的文本在分隔符之间包含太多连续字符,则速度不会那么快,但实际数据通常并非如此。<
/CSVIntervalData>
<
<
如果您需要捕获这两个字符串NEM12
和之间</CSVIntervalData>
的内容,请不要忘记捕获组:
NEM12([^<]*(?:<(?!/CSVIntervalData>)[^<]*)*)</CSVIntervalData>
^ ^
请参阅此正则表达式演示。
推荐阅读
- java - 如果一条记录在 oracle 中插入失败,则避免 jdbc 批量插入失败
- angular - 在组件之间建立通信的任何其他方式 angular 5
- c# - 使用 Mono 将 C# 编译为 WebAssembly
- c - 当 C 头文件在闪存驱动器中时运行函数类型的程序?
- angular - 如何绑定响应式表单构建器属性以进行选择
- opencv - 从 Ubuntu 16.04 卸载 OpenCV 3.2.0 时出错
- mongodb - 有没有一种方法可以使用 mongo-connector 将 mongo 文档更新与 Solr 同步?
- php - 在php中将double转换为int
- redis - Airflow Celery 和 Redis 作业卡在等待状态
- sql-server - MSSQL 查询框架