【问题标题】:How to write this regex without catastrophic backtracking如何在没有灾难性回溯的情况下编写此正则表达式
【发布时间】:2016-04-01 06:31:59
【问题描述】:

我正在尝试编写一个正则表达式,它将获取此列表中以 I 开头的行的第 21 个字段的内容,前提是该字段包含格式为 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  

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

^I(\|.*?){20}(\d{3}-\d{6})

我已阅读有关灾难性回溯的信息,但我的正则表达式技能有限,而且我不明白如何编写此正则表达式,以免发生灾难性回溯。

我们将不胜感激。

【问题讨论】:

  • 当您知道它的格式为nnn-nnnnnn 为什么不简单地使用\d{3}-\d{6} 呢?
  • @noob 我 am 使用它,但我只对第 21 个字段感兴趣 - 我不想在任何其他字段中匹配此字符串。
  • 由于您的其他字段没有该模式的编号,因此仅使用该模式将匹配第 21 个字段。
  • @noob 帖子中的数据只是一个样本
  • 你使用了错误的方法。您需要在管道上拆分字符串,然后检查第一个字段是否为 I 以及第 21 个字段是否不为空(或具有您想要的格式)。

标签: regex perl pcre


【解决方案1】:

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

^I(?:\|[^|]*){20}(\d{3}-\d{6})

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

RegEx Demo

【讨论】:

    【解决方案2】:

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

    perl -F'\|' -anE'say $& if $F[0] eq "I" && $F[20]=~/\S+/' file
    

    脚本中的示例:

    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  
    

    【讨论】:

    • 这是解决问题的正确方法。正则表达式解析分隔文件很痛苦。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    相关资源
    最近更新 更多