Come "inverso corrispondenza" con regex?


112

Sto usando RegexBuddy ma sono comunque nei guai con questa cosa: \

Sto elaborando riga per riga un file. Ho costruito un "modello di linea" per abbinare quello che voglio.

Ora vorrei fare una corrispondenza inversa ... cioè voglio abbinare le linee dove c'è una stringa di 6 lettere, ma solo se queste sei lettere non sono Andrea , come dovrei farlo?


EDIT: scriverò il programma che usa questa regex, non so ancora se in python o php, sto facendo questa cosa prima per imparare qualche regex :) Ce ne sono diversi tipi di riga, volevo usare regex per selezionare il tipo che mi interessa. Una volta ottenute queste righe devo applicare un altro filtro solo per non far corrispondere un valore noto, mi servono tutti gli altri, non quello. Il (?! Non voluto) funziona abbastanza bene, grazie. :-)

Spero che questo chiarisca la domanda :)


In realtà sembra che potresti fare di meglio per darci un po 'più di informazioni su ciò che stai facendo e vedere se qualcuno può offrire una soluzione alternativa. In genere, il tentativo di analizzare un intero file costruendo un'espressione regolare che corrisponda a ciascuna riga è un percorso piuttosto complicato :)
Dan

Risposte:


70
(?!Andrea).{6}

Supponendo che il tuo motore regexp supporti lookahead negativi.

Modifica: ..o forse preferiresti usare [A-Za-z]{6}al posto di.{6}

Modifica (di nuovo): nota che lookahead e lookbehind non sono generalmente il modo giusto per "invertire" una corrispondenza di espressioni regolari. Le espressioni regolari non sono realmente impostate per eseguire corrispondenze negative, lo lasciano a qualunque lingua le utilizzi.


Devi aggiungere il ^ che @Vinko Vrsalovic usa in modo che non corrisponda a "ndrea \ n"
bdukes

2
. non corrisponde a \ n di default (alcune lingue [es. Perl] ti permettono di attivare quel comportamento, ma di default. corrisponde a tutto MA \ n).
Dan

1
(inoltre, l'OP non ha mai menzionato che la stringa doveva verificarsi all'inizio della linea)
Dan

1
cosa intendi per OP?
Andrea Ambu

1
Andrea: OP significa "poster originale", quindi mi riferivo a te :)
Dan

47

4
Questo non funziona. Stai pensando all'idioma Tempered Greedy Token. ma il punto deve andare dopo il lookahead, non prima. Vedi questa domanda . Ma questo approccio è comunque eccessivo per questo compito.
Alan Moore

Non so in quale lingua sia scritto, ma ha funzionato come un incantesimo nel testo Sublime per ripulire i miei dati di prova. Grazie!
Matthias dirickx

1
@AlanMoore In realtà, funzionerà quasi per questo caso d'uso. Tuttavia, se some textinizia la linea, restituirà il risultato sbagliato.
Zenexer

2
@Zenexer, questo è quello che volevo dire. Se il punto è dopo il lookahead invece che prima, funziona perfettamente.
Alan Moore

Ecco un collegamento che spiega di più. Non capisco perché ?!e non solo !.
Timo

21

Aggiornato con il feedback di Alan Moore

In PCRE e varianti simili, puoi effettivamente creare un'espressione regolare che corrisponde a qualsiasi riga che non contenga un valore:

^(?:(?!Andrea).)*$

Questo è chiamato token avido temperato . Lo svantaggio è che non funziona bene.


1
Questo è il token avido temprato in forma lunga. Basta mettere il punto (o [\s\S], il che è utile solo in JavaScript) dopo il secondo lookahead, e non è necessario il primo: ^(?:(?!Andrea).)*$.
Alan Moore

@AlanMoore Nice! Non sono riuscito a trovare alcun modello stabilito che funzionasse in questo modo, quindi ho ideato il mio. Piuttosto che accettare la tua risposta, dovresti fornirla come tua.
Zenexer

Va bene, ci sono già molte buone risposte. E ti meriti il ​​merito di aver inventato l'idioma da solo. Saluti!
Alan Moore

Perché suggerisci di usare [\S\s]? OP sta parlando di linee di corrispondenza, non contenenti la parola "Andrea". Non si tratta di controllare se l'intera stringa contiene questa parola. Mi sto perdendo qualcosa?
x-yuri

@ x-yuri penso tu abbia ragione. Probabilmente ho risposto alla domanda che avevo era che ho visitato per la prima volta questa pagina, ignorando la discrepanza. La mia connessione non è abbastanza buona per aggiornare la risposta in questo momento, però (<10 kbps)
Zenexer,

11

Che lingua stai usando? Le capacità e la sintassi dell'implementazione delle espressioni regolari sono importanti per questo.

Potresti usare la previsione. Usando python come esempio

import re

not_andrea = re.compile('(?!Andrea)\w{6}', re.IGNORECASE)

Per scomporlo:

(?! Andrea) significa "corrisponde se i successivi 6 caratteri non sono" Andrea ""; se è così allora

\ w significa un "carattere di parola" - caratteri alfanumerici. Questo è equivalente alla classe [a-zA-Z0-9_]

\ w {6} significa esattamente 6 caratteri alfanumerici.

re.IGNORECASE significa che escluderai "Andrea", "andrea", "ANDREA" ...

Un altro modo è usare la logica del programma: usa tutte le righe che non corrispondono ad Andrea e inseriscile in una seconda regex per verificare la presenza di 6 caratteri. Oppure controlla prima che siano presenti almeno 6 caratteri alfanumerici, quindi verifica che non corrisponda ad Andrea.


7

Affermazione lookahead negativa

(?!Andrea)

Questa non è esattamente una corrispondenza inversa, ma è il meglio che puoi fare direttamente con regex. Tuttavia, non tutte le piattaforme li supportano.


1
Fino a quando l'interrogante non chiarisce, non vedo che la partita deve iniziare all'inizio della linea. Allora perché il ^?
Hamish Downer

Perché ho capito che voleva controllare all'inizio della riga, modificato dato chiarimenti
Vinko Vrsalovic

5

Se vuoi farlo in RegexBuddy, ci sono due modi per ottenere un elenco di tutte le righe che non corrispondono a una regex.

Sulla barra degli strumenti del pannello Test, impostare l'ambito del test su "Riga per riga". Quando lo fai, un elemento Elenca tutte le linee senza corrispondenze apparirà sotto il pulsante Elenca tutto sulla stessa barra degli strumenti. (Se non vedi il pulsante Elenca tutto, fai clic sul pulsante Abbina nella barra degli strumenti principale.)

Nel pannello GREP, puoi attivare le caselle di controllo "basato su riga" e "inverti risultati" per ottenere un elenco di righe non corrispondenti nei file che stai esaminando.


5

(?!è utile nella pratica. Sebbene in senso stretto, guardare avanti non è un'espressione regolare definita matematicamente.

Puoi scrivere manualmente un'espressione regolare invertita.

Ecco un programma per calcolare automaticamente il risultato. Il suo risultato è una macchina generata, che di solito è molto più complessa della scrittura a mano. Ma il risultato funziona.


1

Ho appena escogitato questo metodo che potrebbe richiedere un uso intensivo dell'hardware ma funziona:

Puoi sostituire tutti i caratteri che corrispondono alla regex con una stringa vuota.

Questo è un oneliner:

notMatched = re.sub(regex, "", string)

L'ho usato perché ero costretto a usare una regex molto complessa e non riuscivo a capire come invertirne ogni parte entro un ragionevole lasso di tempo.

Questo ti restituirà solo il risultato della stringa, non gli oggetti match!


-3

In perl puoi farlo

process ($ line) if ($ line = ~! / Andrea /);


4
Quella sintassi è sbagliata. Penso che intendi process ($ line) se $ line! ~ / Andrea /
dland
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.