如何编写这个正则表达式没有灾难性的回溯

Zek*_*Zek 3 regex perl pcre

我正在尝试编写一个正则表达式,它将获取此列表中第21个字段的内容,用于以I开头的行,前提是该字段包含此格式的数字nnn-nnnnnn(如001-123456):

T|112||     |               | |AZ        |D         |1   |       1|
I|   10|ACAA          |BY CORD EACH             |      10.00-|       .99 |     |      .36 |1   |       1|D         |I|CO |BTE  |N| |       .00 |      .00 |15 |1    |001-123456     |ACAA 
I|   20|LEES03        |TINTED OZ                |       2.00-|      6.50 |     |     4.48 |1   |       1|D         |I|FL |LTGE |N| |       .00 |      .00 |45 |1    |001-234555     |JEE  
I|   20|LEES03        |TINTED OZ                |       2.00-|      6.50 |     |     4.48 |1   |       1|D         |I|FL |LTGE |N| |       .00 |      .00 |45 |1    |               |JEE  
I|   20|LEES03        |TINTED OZ                |       2.00-|      6.50 |     |     4.48 |1   |       1|D         |I|FL |LTGE |N| |       .00 |      .00 |45 |1    |001-234552     |JEE  
Run Code Online (Sandbox Code Playgroud)

这是我正在使用的简单正则表达式,在那里我捕获第二个捕获组中的字段内容:

^I(\|.*?){20}(\d{3}-\d{6})
Run Code Online (Sandbox Code Playgroud)

我读过关于灾难性的回溯,但我的正则表达式技巧是有限的,我不明白如何编写这个正则表达式,以便我不会得到灾难性的回溯.

帮助将不胜感激.

anu*_*ava 5

您可以通过使用否定模式来避免灾难性的回溯:

^I(?:\|[^|]*){20}(\d{3}-\d{6})
Run Code Online (Sandbox Code Playgroud)

[^|]* 匹配0或更多不是的字符 |

RegEx演示


Cas*_*yte 5

IMO,更好的方法是将字符串拆分为管道,然后检查第一个和第21个字段.带有autosplit参数的命令行示例-a:

perl -F'\|' -anE'say $& if $F[0] eq "I" && $F[20]=~/\S+/' file
Run Code Online (Sandbox Code Playgroud)

脚本中的示例:

use strict;
use warnings;
use feature qw(say);

my @F;
while(<DATA>) {
    @F = split /\|/;
    say $1 if $F[0] eq 'I' && $F[20] =~ /(\d+-\d+)/
}

__DATA__
T|112||     |               | |AZ        |D         |1   |       1|
I|   10|ACAA          |BY CORD EACH             |      10.00-|       .99 |     |      .36 |1   |       1|D         |I|CO |BTE  |N| |       .00 |      .00 |15 |1    |001-123456     |ACAA 
I|   20|LEES03        |TINTED OZ                |       2.00-|      6.50 |     |     4.48 |1   |       1|D         |I|FL |LTGE |N| |       .00 |      .00 |45 |1    |001-234555     |JEE  
I|   20|LEES03        |TINTED OZ                |       2.00-|      6.50 |     |     4.48 |1   |       1|D         |I|FL |LTGE |N| |       .00 |      .00 |45 |1    |               |JEE  
I|   20|LEES03        |TINTED OZ                |       2.00-|      6.50 |     |     4.48 |1   |       1|D         |I|FL |LTGE |N| |       .00 |      .00 |45 |1    |001-234552     |JEE  
Run Code Online (Sandbox Code Playgroud)

  • 这是解决问题的正确方法.用于解析分隔文件的正则表达式很痛苦. (3认同)