2008-11-01 7 views
5

Ich habe die folgende Zeile:Wie kann ich meine Regex beheben, um nicht zu viel mit einem gierigen Quantifizierer übereinzustimmen?

"14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)" 

ich das Parsen durch eine einfache regexp mit:

if($line =~ /(\d+:\d+)\ssay;(.*);(.*);(.*);(.*)/) { 
    my($ts, $hash, $pid, $handle, $quote) = ($1, $2, $3, $4, $5); 
} 

Aber das; am Ende vermasselt es Dinge und ich weiß nicht warum. Sollte der gierige Betreiber nicht "alles" behandeln?

Antwort

18

Der gierige Betreiber versucht, so viel Zeug zu packen, wie es kann und trotzdem die Zeichenkette paßt besser zu machen arbeiten. Was passiert, ist der erste (nach "sagen") ergreift "0ed673079715c343281355c2a1fde843; 2", der zweite nimmt "laka", der dritte findet "Hallo" und der vierte passt die Klammer.

Was Sie tun müssen, ist alles andere als das letzte nicht-gierig zu machen, so greifen sie so wenig wie möglich und passen noch die Zeichenfolge:

(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*) 
+0

Das ist großartig! Kannst du mir schnell den Unterschied sagen? og. * Danke! :) –

+1

Der Unterschied ist das. *?stoppt bei der ersten Instanz von was auch immer folgt, während. * stoppt bei der letzten Instanz von was auch immer folgt. – eyelidlessness

+0

Ah, tolle Leute! Bin dankbar! :-) –

3

versuchen, die ersten 3 (.*) ungreedy (.*?)

7
(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*) 

sollte

+0

Ich denke, Sie haben ein Extra ([^;] *); Ich denke, der letzte Teil ist ein Kommentar mit einem Smiley "Hallo;)" – Ady

+0

Ady: Rechts: der letzte Teil kann so einfach sein wie (. *), Um den Rest der Zeile zu bekommen. Fixed – VonC

2

Sie * nicht gierige machen könnte ein durch Anhängen Fragezeichen:

$line =~ /(\d+:\d+)\ssay;(.*?);(.*?);(.*?);(.*)/ 

oder Sie können in jedem Teil mit Ausnahme des letzten, alles außer einem Semikolon entsprechen:

$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/ 
7

Obwohl ein Regex dies leicht tun kann, bin ich mir nicht sicher, ob es der einfachste Ansatz ist. Es ist wahrscheinlich der kürzeste, aber das macht es nicht wirklich am besten.

Stattdessen würde ich so etwas wie dies vorschlagen:

$x="14:48 say;0ed673079715c343281355c2a1fde843;2;laka;hello ;)"; 

if (($ts,$rest) = $x =~ /(\d+:\d+)\s+(.*)/) 
{ 
    my($command,$hash,$pid,$handle,$quote) = split /;/, $rest, 5; 
    print join ",", map { "[$_]" } $ts,$command,$hash,$pid,$handle,$quote 
} 

Daraus ergibt sich:

[14:48],[say],[0ed673079715c343281355c2a1fde843],[2],[laka],[hello ;)] 

Ich denke, das ist nur ein bisschen besser lesbar. Nicht nur das, ich denke, es ist auch einfacher zu debuggen und zu warten, denn das ist näher an der Art und Weise, wie Sie es tun würden, wenn ein Mensch dasselbe mit Stift und Papier versuchen würde. Zerlegen Sie die Zeichenfolge in Blöcke, die Sie dann einfacher parsen können - lassen Sie den Computer genau das tun, was Sie tun würden. Wenn es an der Zeit ist, Änderungen vorzunehmen, denke ich, dass es besser wird. YMMV.

3

Wenn die Werte in Ihrer durch Semikolons getrennten Liste keine Semikolons enthalten können, erhalten Sie den effizientesten und geradlinigsten regulären Ausdruck, indem Sie diese einfach ausschreiben. Wenn bestimmte Werte nur eine Zeichenfolge aus Hex-Zeichen sein können, buchstabieren Sie diese. Lösungen, die einen faulen oder gierigen Punkt verwenden, führen immer zu einer Menge nutzloser Rückverfolgung, wenn die Regex nicht mit der Betreff-Zeichenfolge übereinstimmt.

(\d+:\d+)\ssay;([a-f0-9]+);(\d+);(\w+);([^;\r\n]+) 
+0

Jan, wenn Sie möchten, dass etwas als Quellcode markiert wird, muss jede Zeile mit vier Leerzeichen beginnen. Und willkommen in SO. –