Come abbinare "qualsiasi cosa fino a questa sequenza di caratteri" in un'espressione regolare?


515

Prendete questa espressione regolare: /^[^abc]/. Questo corrisponderà a ogni singolo carattere all'inizio di una stringa, tranne a, b o c.

Se lo aggiungi *dopo - /^[^abc]*/- l'espressione regolare continuerà ad aggiungere ogni carattere successivo al risultato, fino a quando non incontra uno a, o b , o c .

Ad esempio, con la stringa di origine "qwerty qwerty whatever abc hello", l'espressione corrisponderà a "qwerty qwerty wh".

E se volessi che la stringa corrispondente fosse "qwerty qwerty whatever "

... In altre parole, come posso abbinare tutto fino a (ma non includere) la sequenza esatta "abc" ?


Cosa intendi con match but not including?
Tot

5
Voglio dire che voglio abbinare "qwerty qwerty whatever "- senza includere "abc". In altre parole, non voglio che la corrispondenza risultante sia "qwerty qwerty whatever abc".
callum,

2
In javascript puoi semplicemente do string.split('abc')[0]. Certamente non è una risposta ufficiale a questo problema, ma lo trovo più semplice di regex.
Wylliam Judd,

Risposte:


1023

Non hai specificato quale tipo di regex stai usando, ma questo funzionerà in uno dei più popolari che possono essere considerati "completi".

/.+?(?=abc)/

Come funziona

La .+? parte è la versione non avida di .+ (uno o più di qualsiasi cosa). Quando usiamo .+, il motore praticamente corrisponderà a tutto. Quindi, se c'è qualcos'altro nella regex, tornerà indietro nei passaggi cercando di abbinare la parte seguente. Questo è il comportamento avido , che significa quanto più possibile soddisfare .

Durante l'utilizzo .+?, invece di abbinare tutto in una volta e tornare indietro per altre condizioni (se presenti), il motore abbinerà i caratteri successivi per passo fino a quando la parte successiva della regex viene abbinata (di nuovo se presente). Questo è il non avido , il che significa abbinare il minor numero possibile da soddisfare .

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

Dopo che abbiamo , un'asserzione di larghezza pari a zero , uno sguardo intorno . Questa costruzione raggruppata corrisponde al suo contenuto, ma non conta come caratteri corrispondenti ( larghezza zero ). Restituisce solo se è una corrispondenza o meno ( asserzione ).(?={contents})

Quindi, in altri termini, regex /.+?(?=abc)/significa:

Abbina tutti i caratteri il meno possibile fino a quando non viene trovato un "abc", senza contare "abc".


12
Questo probabilmente non funzionerà con le interruzioni di riga, se si suppone che vengano catturate.
einord,

3
Qual è la differenza tra .+?e .*?
Robbie,

4
@ robbie0630 +significa 1 o più, dove *significa 0 o più. L'inclusione / esclusione della ?volontà lo renderà avido o non avido.
jinglesthula,

2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby,

4
Ho notato che questo non riesce a selezionare nulla se lo schema che stai cercando non esiste, invece se lo usi ^(?:(?!abc)(?!def).)*puoi fare una catena per escludere gli schemi che non vuoi e prenderà comunque tutto quanto necessario anche se lo schema non esiste
Karan Shishoo,

123

Se stai cercando di catturare tutto fino a "abc":

/^(.*?)abc/

Spiegazione:

( )catturare l'espressione contenuta tra parentesi per accesso utilizzando $1, $2ecc

^ corrisponde all'inizio della riga

.*abbina qualsiasi cosa, ?non avidamente (abbina il numero minimo di caratteri richiesti) - [1]

[1] Il motivo per cui questo è necessario è che altrimenti, nella seguente stringa:

whatever whatever something abc something abc

per impostazione predefinita, le regex sono avide , il che significa che corrisponderà il più possibile. Pertanto /^.*abc/corrisponderebbe "qualunque cosa qualunque cosa abc qualcosa". L'aggiunta del quantificatore non avido ?fa corrispondere la regex solo "qualunque cosa sia".


4
Grazie, ma l'ONE non includere l'abc nella partita. In altre parole, la corrispondenza risultante è "qualunque sia qualunque cosa abc".
callum,

1
Potresti spiegare cosa alla fine stai cercando di fare? Se il tuo scenario è: (A) Vuoi ottenere tutto ciò che porta a "abc" - usa solo le parentesi attorno a ciò che vuoi catturare. (B) Devi abbinare la stringa fino a "abc" - devi comunque controllare l'abc, quindi deve far parte della regex a prescindere. In quale altro modo puoi verificare che sia lì?
Jared Ng,

sednon sembra supportare la corrispondenza non avida, né supporta look-around ( (?=...)). Cos'altro posso fare? Esempio di comando: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"ritorna two,three, FOUR FIVE, ma mi aspetto two,three...
CodeManX

1
@CoDEmanX Probabilmente dovresti pubblicarlo come una domanda separata piuttosto che un commento, soprattutto perché riguarda specificamente sed. Detto questo, per rispondere alla tua domanda: potresti voler esaminare le risposte a questa domanda . Nota anche che nel tuo esempio, un interprete consapevole non avido tornerebbe giusto two, no two,three.
Jared Ng,

3
Ecco come dovrebbe apparire OGNI risposta regexp - esempio e spiegazione di tutte le parti ...
jave.web

54

Come sottolineato da @Jared Ng e @Issun, la chiave per risolvere questo tipo di RegEx come "abbinare tutto fino a una determinata parola o sottostringa" o "abbinare tutto dopo una determinata parola o sottostringa" è chiamata "lookaround" affermazioni a lunghezza zero . Leggi di più su di loro qui.

Nel tuo caso particolare, può essere risolto con uno sguardo positivo in avanti: .+?(?=abc)

Un'immagine vale più di mille parole. Vedi la spiegazione dei dettagli nello screenshot.

Schermata Regex101


23
.+?(?=abc)regex copia-pastable vale di più.
Tom,

Che dire di escludere gli spazi iniziali?
Royi

8

Ciò di cui hai bisogno è guardarti attorno come un'affermazione .+? (?=abc).

Vedi: Lookahead e Lookbehind Zero-Length Assertions

Sii consapevole che [abc]non è lo stesso di abc. Tra parentesi non è una stringa: ogni personaggio è solo una delle possibilità. Fuori dalle parentesi diventa la stringa.


7

Per regex in Java, e credo anche nella maggior parte dei motori regex, se si desidera includere l'ultima parte funzionerà:

.+?(abc)

Ad esempio, in questa riga:

I have this very nice senabctence

seleziona tutti i caratteri fino a "abc" e includi anche abc

usando il nostro regex, il risultato sarà: I have this very nice senabc

Prova questo: https://regex101.com/r/mX51ru/1


4

Ho finito con questa domanda StackOverflow dopo aver cercato aiuto per risolvere il mio problema ma non ho trovato alcuna soluzione :(

Quindi ho dovuto improvvisare ... dopo qualche tempo sono riuscito a raggiungere la regex di cui avevo bisogno:

inserisci qui la descrizione dell'immagine

Come puoi vedere, avevo bisogno di una cartella prima della cartella "grp-bps", senza includere l'ultimo trattino. Ed era necessario disporre di almeno una cartella dopo la cartella "grp-bps".

modificare

Versione testo per copia-incolla (cambia 'grp-bps' per il tuo testo):

.*\/grp-bps\/[^\/]+

6
Nessuna versione testuale? 🙄
kiradotee,

2

Questo avrà senso su regex.

  1. La parola esatta può essere ottenuta dal seguente comando regex:

( "(. *?)") / G

Qui, possiamo ottenere la parola esatta a livello globale che appartiene all'interno delle doppie virgolette. Ad esempio, se il nostro testo di ricerca è,

Questo è l'esempio per le parole "tra virgolette doppie"

allora otterremo "doppie citazioni" da quella frase.


Benvenuto in StackOverflow e grazie per il tuo tentativo di aiutare. Trovo tuttavia difficile vedere come ciò aiuti l'obiettivo dichiarato nella domanda. Puoi elaborare? Puoi applicarlo agli esempi forniti? Sembra che ti concentri sulla gestione di ", che per me sembra irrilevante per la domanda.
Yunnosch,

1
Ciao, ho spiegato come inserire la parola o le frasi tra i caratteri speciali. Qui la nostra domanda è anche "qualsiasi cosa fino alla sequenza di caratteri speciali". così ho provato con virgolette doppie e l'ho spiegato qui. Grazie.
Ponmurugan Mohanraj,

2

Su Python:

.+?(?=abc) funziona per il caso a riga singola.

[^]+?(?=abc)non funziona, poiché python non riconosce [^] come regex valido. Per far funzionare la corrispondenza su più righe, è necessario utilizzare l'opzione re.DOTALL, ad esempio:

re.findall('.+?(?=abc)', data, re.DOTALL)

0

Credo che tu abbia bisogno di sottoespressioni. Se ricordo bene, puoi usare le ()parentesi normali per le sottoespressioni.

Questa parte è dal manuale grep:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

Fare qualcosa come ^[^(abc)]dovrebbe fare il trucco.


Siamo spiacenti, non funziona. Mettere l'abc tra parentesi non sembra fare alcuna differenza. Sono ancora trattati come "a OR b OR c".
callum

-1

Il $ segna la fine di una stringa, in modo da qualcosa come questo dovrebbe funzionare: [[^abc]*]$dove si sta cercando qualcosa che non terminano in qualsiasi iterazione abc, ma avrebbe dovuto essere alla fine

Inoltre, se stai usando un linguaggio di scripting con regex (come php o js), hanno una funzione di ricerca che si interrompe quando incontra per la prima volta un pattern (e puoi specificare start da sinistra o start da destra, o con php, puoi fare un'implosione per rispecchiare la stringa).


-6

prova questo

.+?efg

Query:

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

produzione :

hijklmn
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.