2016-03-31 21 views
3

Ich versuche, eine Regex schreiben, die mir den Inhalt des 21. Feld in dieser Liste für die Zeilen, die mit einem I beginnt, erhalten, vorausgesetzt das Feld enthält eine Zahl in diesem Format nnn-nnnnnn (wie 001-123456):Wie schreibe ich diese Regex ohne katastrophale Backtracking

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 

Hier ist die einfache regex, die ich verwende, da ich den Feldinhalt in der 2. Capture-Gruppe an Erfassung:

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

ich habe über katastrophisches Backtracking, aber meine Regex-Fähigkeiten sind begrenzt und ich verstehe nicht wie um diese Regex zu schreiben, damit ich nicht das katastrophale Backtracking bekomme.

Hilfe wäre willkommen.

+0

Wenn Sie es hat Format kennen 'nnn-nnnnnn' warum nicht einfach' \ d {3} verwenden - \ d {6} '? –

+1

@noob Ich benutze das, aber ich bin nur am 21. Feld interessiert - ich möchte diese Zeichenfolge in keinem anderen Feld zuordnen. – Zek

+0

Da andere Felder nicht die Nummer dieses Musters haben, wird nur das 21. Feld verwendet. –

Antwort

5

Sie katastrophal vermeiden Rückzieher durch Negation Muster verwendet:

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

[^|]* Matches 0 oder mehr Zeichen, die nicht |

RegEx Demo

5

IMO, eine bessere Möglichkeit besteht aufzuspalten die Schnur auf Rohren und dann das erste und das 21. Feld zu überprüfen. Ein Beispiel in der Befehlszeile mit dem Parameter Autosplit -a:

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

Beispiel in einem Skript:

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 
+3

Dies ist der richtige Weg, um das Problem anzugehen. Regex zum Parsen einer Datei mit Trennzeichen ist nur schmerzhaft. – Sobrique

Verwandte Themen