Come posso risolvere il mio regex in modo che non corrisponda troppo a un avido quantificatore? [duplicare]

StackOverflow https://stackoverflow.com/questions/255815

Domanda

    

Questa domanda ha già una risposta qui:

         

Ho la seguente riga:

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

Analizzo questo usando un semplice regexp:

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

Ma il; alla fine rovina tutto e non so perché. L'operatore avido non dovrebbe gestire "tutto"?

È stato utile?

Soluzione

L'operatore avido cerca di afferrare quante più cose possibile e ancora abbinare la stringa. Quello che sta succedendo è il primo (dopo "dire") che afferra "0ed673079715c343281355c2a1fde843; 2", il secondo prende "laka", il terzo trova "ciao"; e il quarto corrisponde alla parentesi.

Quello che devi fare è rendere tutto tranne l'ultimo non avido, quindi afferrano il meno possibile e continuano a corrispondere alla stringa:

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

Altri suggerimenti

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

dovrebbe funzionare meglio

Anche se un regex può facilmente farlo, non sono sicuro che sia l'approccio più diretto. È probabilmente il più breve, ma ciò non lo rende effettivamente il più mantenibile.

Invece, suggerirei qualcosa del genere:

$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 { "[

Anche se un regex può facilmente farlo, non sono sicuro che sia l'approccio più diretto. È probabilmente il più breve, ma ciò non lo rende effettivamente il più mantenibile.

Invece, suggerirei qualcosa del genere:

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

Ciò si traduce in:

<*>

Penso che questo sia solo un po 'più leggibile. Non solo, penso che sia anche più facile eseguire il debug e la manutenzione, perché è più vicino al modo in cui lo faresti se un umano tentasse la stessa cosa con carta e penna. Suddividi la stringa in blocchi che puoi analizzare più facilmente: chiedi al computer di fare esattamente quello che faresti. Quando arriva il momento di apportare modifiche, penso che questo andrà meglio. YMMV.

]" } $ts,$command,$hash,$pid,$handle,$quote }

Ciò si traduce in:

<*>

Penso che questo sia solo un po 'più leggibile. Non solo, penso che sia anche più facile eseguire il debug e la manutenzione, perché è più vicino al modo in cui lo faresti se un umano tentasse la stessa cosa con carta e penna. Suddividi la stringa in blocchi che puoi analizzare più facilmente: chiedi al computer di fare esattamente quello che faresti. Quando arriva il momento di apportare modifiche, penso che questo andrà meglio. YMMV.

Prova a rendere i primi 3 (. *) ungreedy (.*?)

Se i valori nel tuo elenco delimitato da punti e virgola non possono includere alcun punto e virgola, otterrai l'espressione regolare più efficiente e semplice semplicemente spiegandola. Se alcuni valori possono essere, per esempio, solo una stringa di caratteri esadecimali, precisalo. Le soluzioni che usano un punto pigro o avido porteranno sempre a molti inutili backtracking quando il regex non corrisponde alla stringa del soggetto.

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

Puoi rendere * non avido aggiungendo un punto interrogativo:

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

oppure puoi abbinare tutto tranne un punto e virgola in ogni parte tranne l'ultimo:

$line =~ /(\d+:\d+)\ssay;([^;]*);([^;]*);([^;]*);(.*)/
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top