Come fare una partita non golosa in grep?


Risposte:


276

Stai cercando una partita non golosa (o pigra). Per ottenere una corrispondenza non avida nelle espressioni regolari è necessario utilizzare il modificatore ?dopo il quantificatore. Ad esempio è possibile passare .*a .*?.

Per impostazione predefinita grepnon supporta modificatori non avidi, ma è possibile utilizzare grep -Pper utilizzare la sintassi Perl.


3
eegg: dot all modificatore è anche noto come multilinea. È un modificatore che cambia il "." abbinare il comportamento per includere newline (normalmente non lo fa). Non esiste un tale modificatore in grep, ma in pcregrep .
A. Wilson,

1
Correzione: nella maggior parte degli aromi regex che lo supportano, la modalità che consente .di abbinare le nuove righe è chiamata modalità DOTALL o single-line ; Ruby è l'unico che lo chiama multilinea . Negli altri gusti, multilinea è la modalità che consente alle ancore ( ^e $) di abbinarsi ai confini della linea. Ruby non ha una modalità equivalente perché in Ruby funzionano sempre in questo modo.
Alan Moore,

5
-Pè stato completamente nuovo per me, sto felicemente svanendo da anni, e usando solo -E... tanti anni sprecati! - Nota per sé: rileggi le pagine Man come una cosa (ancora di più!) Normale, non digerisci mai abbastanza opzioni e opzioni.
ocodo,

29
Su alcune piattaforme (come Mac OS X) grepnon supporta -P, ma se si utilizza egrepè possibile utilizzare il .*?modello per ottenere lo stesso risultato. egrep -o 'start.*?end' text.html
SaltyNuts,

4
Come estensione al commento di @SaltyNuts, Mac OS X non supporta -Pma -Echiamerebbe egrepquindi il suggerito .*?funziona bene.
Fredrik Erlandsson,

83

In realtà l' .*?unico funziona perl. Non sono sicuro di quale sarebbe la sintassi della regexp estesa grep equivalente. Fortunatamente puoi usare la sintassi perl con grep, quindi grep -Pfunzionerebbe ma grep -Eche è lo stesso che egrepnon funzionerebbe (sarebbe avido).

Vedi anche: http://blog.vinceliu.com/2008/02/non-greedy-regular-expression-matching.html


9
grep -Pnon funziona in GNU grep 2.9 - l'ho appena provato (non commette errori, silenziosamente non applica il ?. Intertestamente né la classe non es.:env|grep '[^\=]*\='
roberto tomás

2
Non c'è alcuna grep -Popzione o pgrepcomando in Darwin / OS X 10.8 Mountain Lion, ma egrepfunziona alla grande.
Steve HHH,

2
C'è un pgrepcomando sulla mia casella OS X 10.9, ma è un programma completamente diverso il cui scopo è "trovare o segnalare i processi per nome".
Desty,

@ robertotomás Rispondendo a un commento di 6 anni qui, ma .... Ho pensato anche a questo e poi ho capito che stavo ricevendo più partite non golose. Ad esempio, su un terminale a colori puoi vedere che `echo" bbbbb "| grep -P 'b. *? b'` restituisce 2 corrispondenze.
zzxyz,

12

Il mio grep che funziona dopo aver provato cose in questo thread:

echo "hi how are you " | grep -shoP ".*? "

Assicurati di aggiungere uno spazio a ciascuna delle tue linee

(La mia era una ricerca riga per riga per sputare le parole)


3
-shoPnice mnemonic :)
Mariusz,

echo "bbbbb" | grep -shoP 'b.*?b'è un po 'di esperienza di apprendimento. L'unica cosa che ha funzionato anche per me in termini di esplicitamente pigro.
zzxyz,

12

grep

Per una partita non golosa greppotresti usare una classe di personaggi negata. In altre parole, cerca di evitare i caratteri jolly.

Ad esempio, per recuperare tutti i collegamenti ai file jpeg dal contenuto della pagina, utilizzare:

grep -o '"[^" ]\+.jpg"'

Per gestire più righe, reindirizzare prima l'input xargs. Per prestazioni, utilizzare ripgrep.


3

La risposta breve sta usando la seguente espressione regolare:

(?s)<car .*? model=BMW .*?>.*?</car>
  • (? s) - questo crea una corrispondenza su più righe
  • . *? - abbina qualsiasi personaggio, un numero di volte in modo pigro (corrispondenza minima)

Una (piccola) risposta più complicata è:

(?s)<([a-z\-_0-9]+?) .*? model=BMW .*?>.*?</\1>

Ciò consentirà di abbinare car1 e car2 nel seguente testo

<car1 ... model=BMW ...>
...
...
...
</car1>
<car2 ... model=BMW ...>
...
...
...
</car2>
  • (..) rappresenta un gruppo di acquisizione
  • \ 1 in questo contesto corrisponde al sametext come più recentemente abbinato acquisendo il gruppo numero 1

1

Mi dispiace, sono in ritardo di 9 anni, ma questo potrebbe funzionare per gli spettatori nel 2020.

Quindi supponiamo di avere una linea come "Hello my name is Jello". Ora vuoi trovare le parole che iniziano con 'H'e finiscono con 'o', con un numero qualsiasi di caratteri in mezzo. E non vogliamo linee, vogliamo solo parole. Quindi per questo possiamo usare l'espressione:

grep "H[^ ]*o" file

Questo restituirà tutte le parole. Il modo in cui funziona è questo: consentirà a tutti i caratteri invece di spazio tra i caratteri in mezzo, in questo modo possiamo evitare più parole nella stessa riga.

Ora puoi sostituire il carattere spazio con qualsiasi altro personaggio che desideri. Supponiamo che la riga iniziale fosse "Hello-my-name-is-Jello", quindi puoi ottenere parole usando l'espressione:

grep "H[^-]*o" file

0

So che è un po 'un post morto ma ho appena notato che funziona. Ha rimosso sia la pulizia che la pulizia dal mio output.

> grep -v -e 'clean\-\?up'
> grep --version grep (GNU grep) 2.20
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.