正则表达式挂起模式匹配

时间:2012-10-13 09:30:23

标签: regex perl

我输入文件here(请解压缩)和下面的代码。印刷后“pat = \ n”;它在模式匹配中挂起,而我在Windows任务管理器Perl(v5.010000)中看到占用25%的CPU时间:

use strict;
open FP, "<default.php" or die "can't read";

$/ = undef;    

my $content = <FP>;

while ( $content =~ /(['"])([^\s\x00-\x1f]{300,})\1/gs ) {
#looks like we've found base encoded string etc
    my $subpat = $2;
    print "pat=<$subpat>\n";
    if ( $subpat =~ m#(?:(....).{5,30}(?=\1)){50}#s ) {
      print "hello world";
    } else {
      die("");
    }
    exit;
}

编辑:理想情况下我想要找出连续组(最大50)中任何统一的字节重复模式(长度:4),其中每个组大小最多为4 + 30字节,最小为4 + 5字节。 / p>

例如(在每个大小为1到30个字节的组中重复'=&gt;'):

  

'CS'=&GT; '捷克', 'DA'=&GT; '丹麦', 'NL'=&GT; '荷兰', '连接'=&GT; '芬兰', 'FR'=&GT;”法国”, '日'=&GT; '德国', 'EL'=&GT; '希腊人',

行:print“pat = \ n”;打印以下内容并挂起:

  

轻拍=&LT;, '小时'=&GT; '克罗地亚语', 'CS'=&GT; '捷克', 'DA'=&GT; '丹麦', 'NL'=&GT; '荷兰','连接'=&GT;' 芬兰 ' 'FR'=&GT; '法国', '德'=&GT; '德', '厄尔尼诺'=&GT; '希腊', '喜'=&GT; '印地文',' 它'=&GT;' 意大利 ' 'JA'=&GT; '日语', 'KO'=&GT; '韩语', '无'=&GT; '挪威', 'PL'=&GT; '波兰语',' 角'=&GT;' 葡萄牙语 ' 'RO'=&GT; '罗马尼亚', 'RU'=&GT; '俄罗斯', 'ES'=&GT; '西班牙语', 'SV'=&GT; '瑞典',' CA '=&GT;' 加泰罗尼亚语 ' 'TL'=&GT; '菲律宾', 'IW'=&GT; '希伯来语', 'ID'=&GT; '印度尼西亚', 'LV'=&GT; '拉脱维亚',' LT '=&GT;' 立陶宛语 ' 'SR'=&GT; '塞尔维亚语', 'SK'=&GT; '斯洛伐克语', 'SL'=&GT; '斯洛文尼亚语', 'UK'=&GT; '乌克兰',' 六'=&GT;' 越南 ' '平'=&GT; '阿尔巴尼亚人', '等'=&GT; '爱沙尼亚语', 'GL'=&GT; '加利西亚语', '虎'=&GT; '匈牙利语',' 公吨'=&GT;' 马耳他 ' '日'=&GT; '泰', 'TR'=&GT; '土耳其', 'FA'=&GT; '波斯', 'AF'=&GT; '语',' 毫秒'=&GT;' 马来 ' 'SW'=&GT; '斯瓦希里', 'GA'=&GT; '爱尔兰', 'CY'=&GT; '威尔士', '是'=&GT; '白俄罗斯',' 是'=&GT;' 冰岛 ' 'MK'=&GT; '马其顿', '义'=&GT; '依地语', 'HY'=&GT; '亚美尼亚', 'AZ'=&GT; '阿塞拜疆',' 欧盟'=&GT;' 巴斯克 ' 'KA'=&GT; '格鲁吉亚',' HT'=&GT;&GT;

2 个答案:

答案 0 :(得分:5)

Perl正则表达并不是特别聪明。您的模式是通过回溯实现的 - 基本上,在每个决策点(例如,未锚定的开始,或{5,30}),正则表达式将其状态保存在堆栈上,并继续向前进行尽可能小的匹配。如果卡住,它会从堆栈中弹出一个级别。

通常这很好用,因为输入的大小是有限的,在那里有文字或字符类匹配以尽早切断失败的匹配,并且嵌套变量重复指令的使用是有限的。此外,当不存在回溯时,可以将正则表达式(理论上,尽管perl不会这样做)转换为确定性有限自动机,这可以有效地执行。

在这里,你有很多通配符匹配,一个大输入字符串,加上实际上是一个50迭代循环,中间有一个25层分支,周围有一个循环,试图找到开始和结束这场比赛。在最坏的情况下,你的正则表达式可能不得不回溯25 ^ 50次,而且甚至没有考虑缺少一个开始或结束锚。

所以你需要找出一种更聪明的方法来使这个算法工作。尝试生成字符串的每个4个字符的子字符串,并计算出现次数。对于出现多次的每个子字符串,请检查找到的匹配项的偏移量,以查看是否有您的模式。

答案 1 :(得分:1)

直观地看回溯及其成本的好方法是使用Regexp::Debugger

为正则表达式建模

Jeffrey Friedl的“掌握正则表达式”是一个很好的伴侣,它详细讨论了回溯。