web-dev-qa-db-fra.com

Comment faire correspondre un caractère sur plusieurs lignes dans une expression régulière?

Par exemple, cette expression rationnelle

(.*)<FooBar>

correspondra à:

abcde<FooBar>

Mais comment puis-je le faire correspondre sur plusieurs lignes?

abcde
fghij<FooBar>
295
andyuk

Cela dépend de la langue, mais il devrait y avoir un modificateur que vous pouvez ajouter au motif regex. En PHP c'est:

/(.*)<FooBar>/s

Le signe s à la fin fait que le point correspond à tous les caractères , y compris les retours à la ligne.

210
Jeremy Ruten

Essaye ça:

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

Il dit essentiellement "n'importe quel caractère ou nouvelle ligne" répété zéro fois ou plus.

297
levik

Si vous utilisez la recherche Eclipse, vous pouvez activer l'option "DOTALL" pour que "." correspond à n'importe quel caractère, y compris les délimiteurs de ligne: ajoutez simplement "(? s)" au début de votre chaîne de recherche. Exemple:

(?s).*<FooBar>
66
Paulo Merson

La question est la suivante: le modèle . peut-il correspondre any caractère? La réponse varie d'un moteur à l'autre. La principale différence est de savoir si le motif est utilisé par une bibliothèque regex POSIX ou non-POSIX.

Remarque spéciale sur lua-patterns : elles ne sont pas considérées comme des expressions régulières, mais . correspond à tous les caractères présents, de la même manière que les moteurs basés sur POSIX.

Une autre note sur matlab et octave : le . correspond à tout caractère par défaut ( démo ): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match'); (tokens contient un élément abcde\n fghij).

De plus, dans toutes les grammaires regex de boost , le point correspond aux sauts de ligne par défaut. La grammaire ECMAScript de Boost vous permet de désactiver cette option avec regex_constants::no_mod_m ( source ).

Comme pour Oracle (basé sur POSIX), utilisez option n ( démo ): select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual

moteurs basés sur POSIX:

Un simple . correspond déjà à des sauts de ligne, vous n'avez pas besoin d'utiliser de modificateur, voir bash ( démo ).

Les tcl ( démo ), postgresql ( démo ), r (TRE, moteur par défaut de base R sans Perl=TRUE, pour la base R avec Perl=TRUE ou pour stringr / stringi modèles, utilisez le modificateur inline (?s)) ( démo ) traite également . de la même manière.

Cependant , la plupart des outils POSIX traitent les entrées ligne par ligne. Par conséquent, . ne correspond pas aux sauts de ligne simplement parce qu'ils ne sont pas dans la portée. Voici quelques exemples comment remplacer ceci:

  • sed - Il existe plusieurs solutions, la plus précise mais pas très sûre est sed 'H;1h;$!d;x; s/\(.*\)><Foobar>/\1/' (H;1h;$!d;x; insère le fichier en mémoire). Si des lignes entières doivent être incluses, sed '/start_pattern/,/end_pattern/d' file (supprimer du début se terminera par les lignes correspondantes incluses) ou sed '/start_pattern/,/end_pattern/{{//!d;};}' file (avec les lignes correspondantes exclues) peut être pris en compte.
  • Perl - Perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str" (-0 insère tout le fichier dans la mémoire, -p imprime le fichier après application du script donné par -e). Notez que l'utilisation de -000pe réduira le fichier et activera le 'mode paragraphe' où Perl utilise des sauts de ligne consécutifs (\n\n) comme séparateur d'enregistrement.
  • gnu-grep - grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file. Ici, z permet de lisser le fichier, (?s) active le mode DOTALL pour le modèle ., (?i) active le mode sans distinction de casse, \K omet le texte correspondant jusqu'ici, *? est un quantificateur lazy, (?=<Foobar>) correspond à l'emplacement précédent <Foobar>.
  • pcregrep - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file (M permet le slurping de fichier ici). Remarque pcregrep est une bonne solution pour les utilisateurs de Mac OS grep.

Voir les démos .

moteurs non basés sur POSIX:

  • php - Utilisez le modificateur smodificateur PCRE_DOTALL : preg_match('~(.*)<Foobar>~s', $s, $m) ( démo )
  • c # - Utilisez le RegexOptions.Singleline flag ( démo ):
    - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
    - var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
  • powershell - Utilisez (?s) option en ligne: $s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
  • Perl - Utilisez le modificateur s (ou la version (?s) au début) ( démo ): /(.*)<FooBar>/s
  • python - Utilisez les indicateurs re.DOTALL (ou re.S) ou le modificateur inline (?s) ( démo ): m = re.search(r"(.*)<FooBar>", s, flags=re.S) (puis if m:, print(m.group(1)))
  • Java - Utilisez le modificateur Pattern.DOTALL (ou l'indicateur en ligne (?s)) ( démo ): Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
  • groovy - Utilise le (?s) modificateur intégré au motif ( démo ): regex = /(?s)(.*)<FooBar>/
  • scala - Utilisez le modificateur (?s) ( démo ): "(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
  • javascript - Utilisez [^] ou des solutions de contournement [\d\D]/[\w\W]/[\s\S] ( démo ): s.match(/([\s\S]*)<FooBar>/)[1]
  • c ++ (std::regex) Utilisez [\s\S] ou les solutions de contournement JS ( démo ): regex rex(R"(([\s\S]*)<FooBar>)");
  • vba - Utilisez la même approche qu'en JavaScript, ([\s\S]*)<Foobar>.
  • Ruby - Utilisez /mMULTILIGNE modificateur ( démo ): s[/(.*)<Foobar>/m, 1]
  • go - Utilisez le modificateur en ligne (?s) au début ( démo ): re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
  • Swift - Utilisez dotMatchesLineSeparators ou (plus facilement) passez le modificateur inline (?s) au motif: let rx = "(?s)(.*)<Foobar>"
  • objectif-c - Comme Swift, (?s) fonctionne le plus facilement, mais voici comment l'option peut être utilisée : NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
  • re2 , google-apps-script - Utilisez le modificateur (?s) ( démo ): "(?s)(.*)<Foobar>" (dans Google Spreadsheets, =REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

NOTES ON (?s):

Dans la plupart des moteurs non POSIX, le modificateur inline (?s) (ou l'option d'indicateur intégré) peut être utilisé pour appliquer . afin de faire correspondre les sauts de ligne.

S'il est placé au début du modèle, (?s) modifie le comportement de tous les . du modèle. Si le (?s) est placé quelque part après le début, seuls les . situés à sa droite seront affectés sauf il s'agit d'un modèle passé à Python re. Dans Python re, quel que soit l'emplacement (?s), l'ensemble du motif . est affecté. L'effet (?s) est arrêté à l'aide de (?-s). Un groupe modifié peut être utilisé pour n’affecter qu’une plage spécifiée d’un motif regex (par exemple, Delim1(?s:.*?)\nDelim2.* fera correspondre le premier .*? aux nouvelles lignes et le second .* ne correspondra qu’au reste de la ligne).

note POSIX:

Dans les moteurs autres que les expressions rationnelles, les constructions [\s\S]/[\d\D]/[\w\W] peuvent correspondre à n'importe quel caractère.

Dans POSIX, [\s\S] ne correspond à aucun caractère (comme dans JavaScript ou dans un moteur autre que POSIX) car les séquences d'échappement des expressions rationnelles ne sont pas prises en charge dans les expressions entre crochets. [\s\S] est analysé comme des expressions entre crochets qui correspondent à un seul caractère, \ ou s ou S.

58
Wiktor Stribiżew

En JavaScript, utilisez /[\S\s]*<Foobar>/. Source

31
Abbas Shahzadeh

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

Le point correspond à tous sauf aux nouvelles lignes (\ r\n). Utilisez donc\s\S, qui correspondra à TOUS les caractères.

27
samwize

Dans Ruby Ruby vous pouvez utiliser le paramètre 'm 'option (multiligne):

/YOUR_REGEXP/m

Voir la documentation Regexp sur Ruby-doc.org pour plus d'informations.

18
vibaiher

on peut aussi utiliser

(.*?\n)*?

pour correspondre à tout, y compris newline sans gourmand

Cela rendra la nouvelle ligne facultative

(.*?|\n)*?
11
RAN_0915

"." ne correspond normalement pas aux sauts de ligne. La plupart des moteurs de regex vous permettent d'ajouter l'indicateur S- (également appelé DOTALL et SINGLELINE) pour que "." corresponde également aux nouvelles lignes. Si cela échoue, vous pouvez faire quelque chose comme [\S\s].

8
Markus Jarderot

Pour Eclipse travaillé expression suivante:

Foo

jadajada Bar "

Expression régulière:

Foo[\S\s]{1,10}.*Bar*
7
Gordon
/(.*)<FooBar>/s

s fait que Dot (.) correspond aux retours chariot

5
Bill

Dans l'expression régulière basée sur Java, vous pouvez utiliser [\s\S]

4
Kamahire

Utilisez RegexOptions.Singleline, cela change le sens de. inclure les nouvelles lignes

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

3
shmall

Notez que (.|\n)* peut être moins efficace que (par exemple) [\s\S]* (si les expressions rationnelles de votre langue prennent en charge de tels échappements) et que de trouver comment spécifier le modificateur qui le rend. correspondent également aux nouvelles lignes. Ou vous pouvez utiliser des alternatives POSIXy comme [[:space:][:^space:]]*.

3
tye

Solution:

Utilisez le modificateur de modèle sU pour obtenir la correspondance souhaitée en PHP.

exemple:

preg_match('/(.*)/sU',$content,$match);

La source:

http://dreamluverz.com/developers-tools/regex-match-all-including-new-linehttp://php.net/manual/en/reference.pcre. pattern.modifiers.php

2
Sian Lerk Lau

J'ai eu le même problème et résolu dans probablement pas la meilleure façon, mais cela fonctionne. J'ai remplacé tous les sauts de ligne avant mon vrai match:

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

Je manipule du HTML afin que les sauts de ligne ne m'importent pas vraiment dans ce cas.

J'ai essayé toutes les suggestions ci-dessus sans succès, j'utilise .Net 3.5 FYI

1
Slee

En Javascript, vous pouvez utiliser [^] * pour rechercher des caractères de zéro à infini, y compris les sauts de ligne.

$("#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>
1
Paul Jones

Dans le contexte de l'utilisation dans les langues, les expressions régulières agissent sur des chaînes, pas des lignes. Vous devriez donc pouvoir utiliser l'expression régulière normalement, en supposant que la chaîne d'entrée comporte plusieurs lignes.

Dans ce cas, l'expression rationnelle donnée correspondra à la chaîne entière, car "<FooBar>" est présent. Selon les spécificités de l'implémentation de regex, la valeur $ 1 (obtenue à partir de "(. *)") Sera "fghij" ou "abcde\nfghij". Comme d'autres l'ont dit, certaines implémentations vous permettent de contrôler si le "." correspondra à la nouvelle ligne, vous donnant le choix.

L'utilisation d'une expression régulière basée sur une ligne est généralement utilisée pour des opérations en ligne de commande telles que egrep.

1
nsayer

La recherche de trois lignes consécutives dans Powershell ressemble à ceci:

$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

Bizarrement, ce serait un texte unix à l’invite, mais un texte Windows dans un fichier:

$pattern = 'lineone
linetwo
linethree
'

Voici un moyen d'imprimer les fins de ligne:

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

# output
lineone\nlinetwo\nlinethree\n
0
js2010

Nous devons souvent modifier une sous-chaîne avec quelques mots-clés répartis sur les lignes précédant la sous-chaîne. Considérons un élément xml:

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

Supposons que nous voulions modifier le 81, en lui attribuant une autre valeur, disons 40. Identifiez d'abord .UID.21..UID., puis ignorez tous les caractères, y compris \n jusqu'à .PercentCompleted.. Le modèle d'expression régulière et la spécification de remplacement sont les suivants:

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>

Le sous-groupe (.|\n) est probablement le groupe manquant $3. Si nous le faisons sans capture par (?:.|\n) alors le $3 est (<PercentComplete>). Donc, le motif et replaceSpec peuvent aussi être:

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

et le remplacement fonctionne correctement comme avant.

0
user1348737

Je voulais faire correspondre un bloc si particulier en Java

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

   }
...
...
}

Si j'utilise le regExp

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

il comprenait l'accolade de fermeture pour le bloc de méthode alors j'ai utilisé

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

pour exclure l'accolade de fermeture de la correspondance avec le caractère générique.

0
Spangen

généralement . ne correspond pas aux nouvelles lignes, alors essayez ((.|\n)*)<foobar>

0
tloach