Come posso abbinare qualsiasi personaggio su più righe in un'espressione regolare?


358

Ad esempio, questa regex

(.*)<FooBar>

corrisponderà:

abcde<FooBar>

Ma come faccio ad abbinarlo su più righe?

abcde
fghij<FooBar>

1
Chiarire; Inizialmente stavo usando Eclipse per trovare e sostituire più file. Quello che ho scoperto dalle risposte qui sotto è che il mio problema era lo strumento e non il modello regex.
Andyuk,

2
La tua bandiera "eclissi" dovrebbe essere rimossa perché una persona alla ricerca di una soluzione di eclissi troverà questa domanda (come ho fatto io) e quindi troverà una soluzione non-eclissi come accettata.
Acme,

2
Ora sto trovando questo nel motore di ricerca perché è stato menzionato eclissi. Oh l'orrore.
Brian Olsen,

Risposte:


240

Dipende dalla lingua, ma dovrebbe esserci un modificatore che puoi aggiungere al modello regex. In PHP è:

/(.*)<FooBar>/s

La s alla fine fa sì che il punto corrisponda a tutti i caratteri, comprese le nuove linee.


e se volessi solo una nuova linea e non tutti i personaggi?
Grace,

3
@Grace: usa \ n per abbinare una nuova riga
Jeremy Ruten

5
Il flag s non è (ora?) Non valido, almeno in Chrome / V8. Invece usa / ([\ s \ S] *) <FooBar> / classe di caratteri (confronta spazio e non spazio) invece del periodo corrispondente. Vedi altre risposte per maggiori informazioni.
Allen

8
@Allen - JavaScript non supporta il smodificatore. Invece, fai [^]*per lo stesso effetto.
Derek 朕 會 功夫 il

1
In Ruby, usa il mmodificatore
Ryan Buckley,

358

Prova questo:

((.|\n)*)<FooBar>

In pratica dice "qualsiasi personaggio o una nuova riga" ripetuto zero o più volte.


5
Questo dipende dalla lingua e / o dallo strumento che stai utilizzando. Fateci sapere cosa state usando, ad esempio Perl, PHP, CF, C #, sed, awk, ecc.
Ben Doom,

39
A seconda dei finali di cui potresti aver bisogno((.|\n|\r)*)<FooBar>
Potherca

3
Ha detto che sta usando Eclipse. Questa è la soluzione corretta secondo me. Ho lo stesso problema e questo l'ha risolto.
Danubian Sailor,

4
Esatto: la domanda riguarda eclissi e lo stesso vale per i tag. Ma la soluzione accettata è una soluzione PHP. La tua soluzione dovrebbe essere accettata ...
acme

16
Questa è la peggiore regex per l'abbinamento di più righe di input. Non utilizzarlo mai, a meno che non si stia utilizzando ElasticSearch. Usa [\s\S]*o (?s).*.
Wiktor Stribiżew,

89

La domanda è: può un .modello adattarsi a qualsiasi personaggio? La risposta varia da motore a motore. La differenza principale è se il pattern viene utilizzato da una libreria regex POSIX o non POSIX.

Nota speciale su : non sono considerati espressioni regolari, ma .corrispondono a qualsiasi carattere lì, come i motori basati su POSIX.

Un'altra nota su e : .corrisponde a qualsiasi carattere predefinito ( demo ): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match');( tokenscontiene un abcde\n fghijoggetto).

Inoltre, in tutto Le grammatiche regex del punto corrispondono alle interruzioni di riga per impostazione predefinita. La grammatica ECMAScript di Boost ti consente di disattivarlo con regex_constants::no_mod_m( sorgente ).

Quanto a (è basato su POSIX), utilizzare l' nopzione ( demo ):select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual

Motori basati su POSIX :

Un semplice .abbina già le interruzioni di riga, non è necessario utilizzare alcun modificatore, vedi( demo ).

Il ( demo ),( demo ),(TRE, motore predefinito di base R con no perl=TRUE, per base R con perl=TRUEo per schemi stringr / stringi , utilizzare il (?s)modificatore inline) ( demo ) anche trattare .allo stesso modo.

Tuttavia , la maggior parte degli strumenti basati su POSIX elabora l'input riga per riga. Quindi, .non corrisponde alle interruzioni di riga solo perché non rientrano nell'ambito. Ecco alcuni esempi su come sovrascrivere questo:

  • - Esistono diverse soluzioni alternative, la più precisa ma non molto sicura è sed 'H;1h;$!d;x; s/\(.*\)><Foobar>/\1/'( H;1h;$!d;x;assorbe il file in memoria). Se devono essere incluse intere righe, sed '/start_pattern/,/end_pattern/d' file(la rimozione dall'inizio termina con le righe corrispondenti incluse) o sed '/start_pattern/,/end_pattern/{{//!d;};}' file(con le righe corrispondenti escluse) può essere preso in considerazione.
  • - perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str"( -0assorbe l'intero file in memoria, -pstampa il file dopo aver applicato lo script fornito da -e). Si noti che l'utilizzo -000peridurrà il file e attiverà la "modalità paragrafo" in cui Perl utilizza newline consecutive ( \n\n) come separatore dei record.
  • - grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file. Qui, zabilita (?s)lo slurping dei file, abilita la modalità DOTALL per il .modello, (?i)abilita la modalità senza distinzione tra maiuscole e minuscole, \Komette il testo corrispondente finora, *?è un quantificatore pigro, (?=<Foobar>)corrisponde alla posizione precedente <Foobar>.
  • - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file( Mabilita lo slurping dei file qui). Nota pcregrepè una buona soluzione per gli greputenti di Mac OS .

Guarda le demo .

Motori non basati su POSIX :

  • - Usa il smodificatore modificatore PCRE_DOTALL : preg_match('~(.*)<Foobar>~s', $s, $m)( demo )
  • - Usa RegexOptions.Singlelineflag ( demo ):
    - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
    -var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
  • - Usa (?s)l'opzione in linea:$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
  • - Usa il smodificatore (o la (?s)versione incorporata all'inizio) ( demo ):/(.*)<FooBar>/s
  • - Usa re.DOTALL(o re.S) flag o (?s)modificatore inline ( demo ): m = re.search(r"(.*)<FooBar>", s, flags=re.S)(e poi if m:, print(m.group(1)))
  • - Usa Pattern.DOTALLmodificatore (o (?s)flag incorporato ) ( demo ):Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
  • - Usa il (?s)modificatore in-pattern ( demo ):regex = /(?s)(.*)<FooBar>/
  • - Usa (?s)modificatore ( demo ):"(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
  • - Utilizzo [^]o soluzioni alternative [\d\D]/ [\w\W]/ [\s\S]( demo ):s.match(/([\s\S]*)<FooBar>/)[1]
  • ( std::regex) Utilizzare [\s\S]o le soluzioni alternative JS ( demo ):regex rex(R"(([\s\S]*)<FooBar>)");
  • - Utilizzare lo stesso approccio in JavaScript, ([\s\S]*)<Foobar>. ( NOTA : a volte si ritiene erroneamente che la MultiLineproprietà RegExpdell'oggetto sia l'opzione per consentire la .corrispondenza tra le interruzioni di riga, mentre, in realtà, cambia solo il comportamento ^e $per far coincidere l'inizio / la fine delle righe anziché le stringhe , come in JS regex ) comportamento.)

  • - Usa il modificatore /m MULTILINE ( demo ):s[/(.*)<Foobar>/m, 1]

  • - Base R PCRE regexps - uso (?s): regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2]( demo )
  • - le funzioni in stringr/ stringiregex che sono alimentate con il motore regex ICU, usano anche (?s): stringr::str_match(x, "(?s)(.*)<FooBar>")[,2]( demo )
  • - Usa il modificatore inline (?s)all'avvio ( demo ):re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
  • - Utilizzare dotMatchesLineSeparatorso (più semplice) passare il (?s)modificatore in linea al modello:let rx = "(?s)(.*)<Foobar>"
  • - Come Swift, (?s)funziona nel modo più semplice, ma ecco come può essere utilizzata l' opzione :NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
  • , - Usa (?s)modificatore ( demo ): "(?s)(.*)<Foobar>"(in Google Spreadsheets, =REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

NOTE SU(?s) :

Nella maggior parte dei motori non POSIX, è (?s)possibile utilizzare il modificatore inline (o l'opzione flag incorporata) per applicare le .interruzioni di riga.

Se posizionato all'inizio del modello, (?s)cambia il comportamento di tutti .nel modello. Se (?s)viene posizionato da qualche parte dopo l'inizio, .saranno interessati solo quelli che si trovano alla sua destra a meno che questo non sia uno schema passato a Python re. In Python re, indipendentemente dalla (?s)posizione, l'intero modello .è interessato. L' (?s)effetto viene interrotto usando (?-s). Un gruppo modificato può essere utilizzato per influenzare solo un intervallo specificato di un modello regex (ad es. Delim1(?s:.*?)\nDelim2.*Farà la prima .*?corrispondenza tra le nuove linee e la seconda .*corrisponderà solo al resto della linea).

Nota POSIX :

Nei motori regex non POSIX, per abbinare qualsiasi carattere, [\s\S]/ [\d\D]/ [\w\W]costrutti possono essere utilizzati.

In POSIX, [\s\S]non corrisponde alcun carattere (come in JavaScript o qualsiasi motore non POSIX) perché le sequenze di escape regex non sono supportate all'interno delle espressioni parentesi. [\s\S]viene analizzato come espressioni di parentesi che corrispondono a un singolo carattere \o soppure S.


5
Dovresti collegarti a questa eccellente panoramica dalla pagina del tuo profilo o qualcosa del genere (+1).
Jan

1
Puoi aggiungerlo all'elemento boost : nello spazio dei nomi regex_constants, flag_type_'s: perl = ECMAScript = JavaScript = JScript = :: boost :: regbase :: normal = 0 che per impostazione predefinita è Perl. I programmatori imposteranno una definizione di flag di base #define MOD regex_constants::perl | boost::regex::no_mod_s | boost::regex::no_mod_mper i loro flag di regex per riflettere ciò. E l'arbitor è sempre i modificatori in linea. Dove si (?-sm)(?s).*ripristina.

1
Puoi anche aggiungere per bash per favore?
Pasupathi Rajamanickam,

2
@PasupathiRajamanickam Bash utilizza un motore regex POSIX, che .corrisponde a qualsiasi carattere lì (comprese le interruzioni di riga). Guarda questa demo online di Bash .
Wiktor Stribiżew il

1
Fai rock - questo è il mini-tutorial più completo su regexp (relativamente) complessi che io abbia mai visto. Ti meriti che la tua risposta diventi quella accettata! Complimenti e voti extra per l'inclusione Gonella risposta!
Gwyneth Llewelyn,

68

Se stai usando la ricerca Eclipse, puoi abilitare l'opzione "DOTALL" per creare '.' corrisponde a qualsiasi carattere inclusi i delimitatori di riga: aggiungi "(? s)" all'inizio della stringa di ricerca. Esempio:

(?s).*<FooBar>

1
Non da nessuna parte, solo nei sapori regex che supportano modificatori in linea, e certamente non in Ruby dove (?s)=>(?m)
Wiktor Stribiżew,

Qualcosa per bash?
Pasupathi Rajamanickam,

38

In molti dialetti regex, /[\S\s]*<Foobar>/farà esattamente quello che vuoi. fonte


2
Da quel link: "JavaScript e VBScript non hanno un'opzione per far combaciare i punti con i caratteri di interruzione di riga. In quelle lingue, puoi usare una classe di caratteri come [\ s \ S] per abbinare qualsiasi carattere." Invece di. usa invece [\ s \ S] (confronta spazi e non spazi).
Allen

32

([\s\S]*)<FooBar>

Il punto corrisponde a tutti tranne alle nuove righe (\ r \ n). Quindi usa \ s \ S, che corrisponderà a TUTTI i caratteri.


Questo risolve il problema se si utilizza Objective-C [text rangeOfString:regEx options:NSRegularExpressionSearch]. Grazie!
J. Costa,

1
Questo funziona grazie alla ricerca e sostituzione di regex di intelliJ, grazie.
barclay

Questo funziona Ma deve essere la prima occorrenza di<FooBar>
Ozkan,


13

possiamo anche usare

(.*?\n)*?

per abbinare tutto compreso newline senza avidità

Ciò renderà la nuova linea opzionale

(.*?|\n)*?

8

"."normalmente non corrisponde alle interruzioni di riga. La maggior parte dei motori regex ti consente di aggiungere il S-flag (chiamato anche DOTALLe SINGLELINE) per far "."corrispondere anche i newline. Se fallisce, potresti fare qualcosa del genere [\S\s].


8

Per Eclipse ha funzionato la seguente espressione:

foo

jadajada Bar "

Espressione regolare:

Foo[\S\s]{1,10}.*Bar*

5
/(.*)<FooBar>/s

la s fa sì che Dot (.) corrisponda ai ritorni a capo


Sembra che questo non sia valido (Chrome): text.match (/ a / s) SintassiError: Flag non validi forniti al costruttore RegExp 's'
Allen

Perché non è supportato nei motori RegEx di JavaScript. I sflag esistono in PCRE, il motore più completo (disponibile in Perl e PHP). PCRE ha 10 flag (e molte altre funzionalità) mentre JavaScript ha solo 3 flag ( gmi).
Morgan Touverey Quilling,

4

Nell'espressione regolare basata su Java puoi usare [\s\S]


1
Quelle non dovrebbero essere barre rovesciate?
Paul Draper,

Vanno alla fine dell'espressione regolare, non all'interno di. Esempio: / blah / s
RandomInsano,

Immagino che intendi JavaScript, non Java? Dato che puoi semplicemente aggiungere il sflag al modello in Java e JavaScript non ha il sflag.
3limin4t0r

3

Nota che (.|\n)*può essere meno efficiente di (ad esempio) [\s\S]*(se le regex della tua lingua supportano tali escape) e di trovare come specificare il modificatore che rende. abbinare anche le nuove righe. Oppure puoi scegliere POSIX come alternative [[:space:][:^space:]]*.


3

Usa RegexOptions.Singleline, cambia il significato di. per includere newline

Regex.Replace (contenuto, searchText, replaceText, RegexOptions.Singleline);



1

Nel contesto dell'uso all'interno delle lingue, le espressioni regolari agiscono sulle stringhe, non sulle linee. Quindi dovresti essere in grado di usare normalmente il regex, supponendo che la stringa di input abbia più righe.

In questo caso, la regex fornita corrisponderà all'intera stringa, poiché è presente "<FooBar>". A seconda delle specifiche dell'implementazione di regex, il valore $ 1 (ottenuto da "(. *)") Sarà "fghij" o "abcde \ nfghij". Come altri hanno già detto, alcune implementazioni consentono di controllare se il "." corrisponderà alla nuova riga, dandoti la scelta.

L'uso di espressioni regolari basate su linea è in genere per cose da riga di comando come egrep.


1

Ho avuto lo stesso problema e risolto probabilmente non nel modo migliore ma funziona. Ho sostituito tutte le interruzioni di riga prima di fare la mia vera partita:

mystring= Regex.Replace(mystring, "\r\n", "")

Sto manipolando HTML, quindi in questo caso le interruzioni di riga non contano davvero per me.

Ho provato tutti i suggerimenti di cui sopra senza fortuna, sto usando .Net 3.5 FYI


Sto usando anche .NET e (\s|\S)sembra fare il trucco per me!
Vamshi Krishna,

@VamshiKrishna In .NET, usa (?s)per far .corrispondere qualsiasi carattere. Non utilizzare (\s|\S)ciò rallenterà le prestazioni.
Wiktor Stribiżew,

1

In Javascript puoi usare [^] * per cercare da zero a infiniti caratteri, comprese le interruzioni di riga.

$("#find_and_replace").click(function() {
  var text = $("#textarea").val();
  search_term = new RegExp("[^]*<Foobar>", "gi");;
  replace_term = "Replacement term";
  var new_text = text.replace(search_term, replace_term);
  $("#textarea").val(new_text);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="find_and_replace">Find and replace</button>
<br>
<textarea ID="textarea">abcde
fghij&lt;Foobar&gt;</textarea>


0

generalmente . non corrisponde a newline, quindi prova((.|\n)*)<foobar>


3
No, non farlo. Se devi abbinare qualsiasi cosa, inclusi i separatori di linea, usa il modificatore DOTALL (aka / s o SingleLine). L'hack (. | \ N) non solo rende il regex meno efficiente, non è nemmeno corretto. Almeno, dovrebbe corrispondere a \ r (ritorno a capo) e \ n (avanzamento riga). Esistono anche altri caratteri di separazione delle linee, anche se usati raramente. Ma se usi la bandiera DOTALL, non devi preoccuparti di loro.
Alan Moore,

1
\ R è la corrispondenza indipendente dalla piattaforma per le nuove linee in Eclipse.
opyate,

@opyate Dovresti pubblicare questo come risposta in quanto questo piccolo gioiello è incredibilmente utile.
jeckhart,

Potresti provare questo invece. Non corrisponderà alle parentesi interne e considererà anche l'opzione facoltativa \r.:((?:.|\r?\n)*)<foobar>
ssc-hrep3

0

Volevo abbinare un blocco if particolare in Java

   ...
   ...
   if(isTrue){
       doAction();

   }
...
...
}

Se uso regExp

if \(isTrue(.|\n)*}

includeva la parentesi graffa di chiusura per il blocco del metodo, quindi l'ho usato

if \(!isTrue([^}.]|\n)*}

per escludere la parentesi graffa di chiusura dalla corrispondenza dei caratteri jolly.


0

Spesso dobbiamo modificare una sottostringa con alcune parole chiave sparse tra le righe che precedono la sottostringa. Considera un elemento xml:

<TASK>
  <UID>21</UID>
  <Name>Architectural design</Name>
  <PercentComplete>81</PercentComplete>
</TASK>

Supponiamo di voler modificare 81, ad un altro valore, diciamo 40. Prima identifica .UID.21..UID., quindi salta tutti i caratteri incluso \ntill .PercentCompleted.. Il modello di espressione regolare e la specifica di sostituzione sono:

String hw = new String("<TASK>\n  <UID>21</UID>\n  <Name>Architectural design</Name>\n  <PercentComplete>81</PercentComplete>\n</TASK>");
String pattern = new String ("(<UID>21</UID>)((.|\n)*?)(<PercentComplete>)(\\d+)(</PercentComplete>)");
String replaceSpec = new String ("$1$2$440$6");
//note that the group (<PercentComplete>) is $4 and the group ((.|\n)*?) is $2.

String  iw = hw.replaceFirst(pattern, replaceSpec);
System.out.println(iw);

<TASK>
  <UID>21</UID>
  <Name>Architectural design</Name>
  <PercentComplete>40</PercentComplete>
</TASK>

Il sottogruppo (.|\n)è probabilmente il gruppo mancante $3. Se lo rendiamo non-cattura (?:.|\n)allora $3è (<PercentComplete>). Quindi il modello e replaceSpecpuò anche essere:

pattern = new String("(<UID>21</UID>)((?:.|\n)*?)(<PercentComplete>)(\\d+)(</PercentComplete>)");
replaceSpec = new String("$1$2$340$5")

e la sostituzione funziona correttamente come prima.


0

In genere la ricerca di tre righe consecutive in Powershell sarebbe simile a:

$file = get-content file.txt -raw

$pattern = 'lineone\r\nlinetwo\r\nlinethree\r\n'     # "windows" text
$pattern = 'lineone\nlinetwo\nlinethree\n'           # "unix" text
$pattern = 'lineone\r?\nlinetwo\r?\nlinethree\r?\n'  # both

$file -match $pattern

# output
True

Stranamente, questo sarebbe unix text al prompt, ma il testo di Windows in un file:

$pattern = 'lineone
linetwo
linethree
'

Ecco un modo per stampare le terminazioni di riga:

'lineone
linetwo
linethree
' -replace "`r",'\r' -replace "`n",'\n'

# output
lineone\nlinetwo\nlinethree\n

-2

opzione 1

Un modo sarebbe usare la sbandiera (proprio come la risposta accettata):

/(.*)<FooBar>/s

Demo 1

opzione 2

Un secondo modo sarebbe quello di usare la mbandiera (multilinea) e uno dei seguenti modelli:

/([\s\S]*)<FooBar>/m

o

/([\d\D]*)<FooBar>/m

o

/([\w\W]*)<FooBar>/m

Demo 2

Circuito RegEx

jex.im visualizza le espressioni regolari:

inserisci qui la descrizione dell'immagine

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.