Como faço para combinar algum personagem em várias linhas em uma expressão regular?

StackOverflow https://stackoverflow.com/questions/159118

  •  03-07-2019
  •  | 
  •  

Pergunta

Por exemplo, este regex

(.*)<FooBar>

vai corresponder:

abcde<FooBar>

Mas como faço para combinar com várias linhas?

abcde
fghij<FooBar>
Foi útil?

Solução

Depende do idioma, mas deve haver um modificador que você pode adicionar ao padrão Regex. No PHP é:

/(.*)<FooBar>/s

o s No final, faz com que o ponto corresponda tudo Personagens, incluindo novas linhas.

Outras dicas

Experimente isso:

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

Basicamente, diz "qualquer personagem ou uma nova linha" zero repetido ou mais vezes.

Se você estiver usando a pesquisa Eclipse, pode ativar a opção "Dotall" para fazer ''. Combine qualquer caractere, incluindo delimitadores de linha: basta adicionar "(? s)" no início da sua sequência de pesquisa. Exemplo:

(?s).*<FooBar>

A questão é, pode . correspondência de padrão algum personagem? A resposta varia de motor para motor. A principal diferença é se o padrão é usado por uma biblioteca POSIX ou não-Posix Regex.

Nota especial sobre : eles não são considerados expressões regulares, mas . corresponde a qualquer char lá, o mesmo que os motores baseados em Posix.

Outra nota sobre e : a . corresponde a qualquer char por padrão (demonstração): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match'); (tokens conter a abcde\n fghij item).

Além disso, em todo GRAMÁRIAS REGEX O DOT corresponde às quebras de linha por padrão. A gramática Ecmascript do Boost permite desativar isso com regex_constants::no_mod_m (fonte).

Quanto a (é baseado em Posix), use n opção (demonstração): select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual

Motores baseados em Posix:

Uma mera . Já corresponde às quebras de linha, sem necessidade de usar modificadores, veja (demonstração).

o (demonstração), (demonstração), (Tre, base R Base R motor padrão sem perl=TRUE, para base r com perl=TRUE ou para Stringr/stringi padrões, use o (?s) modificador embutido) (demonstração) também tratar . o mesmo caminho.

No entanto, a maioria das ferramentas baseadas em POSIX processam a linha de entrada por linha. Por isso, . Não corresponde às quebras da linha apenas porque elas não estão no escopo. Aqui estão alguns exemplos de como substituir isso:

  • - Existem várias soluções alternativas, o mais preciso, mas não muito seguro, é sed 'H;1h;$!d;x; s/\(.*\)><Foobar>/\1/' (H;1h;$!d;x; arrasta o arquivo na memória). Se linhas inteiras devem ser incluídas, sed '/start_pattern/,/end_pattern/d' file (Remover do início terminará com linhas correspondentes incluídas) ou sed '/start_pattern/,/end_pattern/{{//!d;};}' file (com linhas correspondentes excluídas) pode ser considerado.
  • - perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str" (-0 arrasta o arquivo inteiro na memória, -p imprime o arquivo após aplicar o script dado por -e). Observe isso usando -000pe Invocará o arquivo e ativará o 'modo de parágrafo', onde a Perl usa novas linhas consecutivas (\n\n) como o separador de registros.
  • - grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file. Aqui, z Ativa o arrasto de arquivo, (?s) Ativa o modo Dotall para o . padronizar, (?i) Ativa o modo insensível ao caso, \K omite o texto correspondido até agora, *? é um quantificador preguiçoso, (?=<Foobar>) corresponde à localização antes <Foobar>.
  • - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file (M Ativa o arquivo de arquivo aqui). Observação pcregrep é uma boa solução para Mac OS grep usuários.

Veja demos.

Motores que não são baseados em Posix:

  • - Usar s modificador Modificador PCRE_DOTALL: preg_match('~(.*)<Foobar>~s', $s, $m) (demonstração)
  • - Usar RegexOptions.Singleline bandeira (demonstração):
    - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
    - var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
  • - Usar (?s) opção embutida: $s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
  • - Usar s modificador (ou (?s) versão embutida no início) (demonstração): /(.*)<FooBar>/s
  • - Usar re.DOTALL (ou re.S) sinalizadores ou (?s) modificador embutido (demonstração): m = re.search(r"(.*)<FooBar>", s, flags=re.S) (e depois if m:, print(m.group(1)))
  • - Usar Pattern.DOTALL modificador (ou embutido (?s) bandeira) (demonstração): Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
  • - Usar (?s) Modificador de padrão (demonstração): regex = /(?s)(.*)<FooBar>/
  • - Usar (?s) modificador (demonstração): "(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
  • - Usar [^] ou soluções alternativas [\d\D] / [\w\W] / [\s\S] (demonstração): s.match(/([\s\S]*)<FooBar>/)[1]
  • (std::regex) Usar [\s\S] ou as soluções alternativas do JS (demonstração): regex rex(R"(([\s\S]*)<FooBar>)");
  • - Use a mesma abordagem que em JavaScript, ([\s\S]*)<Foobar>.
  • - Usar /m Multilina modificador (demonstração): s[/(.*)<Foobar>/m, 1]
  • - Use o modificador embutido (?s) no começo (demonstração): re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
  • - Usar dotMatchesLineSeparators ou (mais fácil) passar o (?s) Modificador embutido para o padrão: let rx = "(?s)(.*)<Foobar>"
  • - o mesmo que Swift, (?s) funciona mais fácil, mas aqui está como o a opção pode ser usada: NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
  • , - Usar (?s) modificador (demonstração): "(?s)(.*)<Foobar>" (nas planilhas do Google, =REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

Notas sobre (?s):

Na maioria dos motores não-posix, (?s) Modificador embutido (ou opção de sinalização incorporada) pode ser usada para aplicar . Para combinar quebras de linha.

Se colocado no início do padrão, (?s) muda o bahavior de todos . no padrão. Se o (?s) é colocado em algum lugar após o começo, apenas aqueles . serão afetados que estão localizados à direita a não ser que Este é um padrão passado para Python re. Em Python re, independentemente do (?s) Localização, todo o padrão . são afetados. o (?s) O efeito é parado de usar (?-s). Um grupo modificado pode ser usado para afetar apenas uma faixa especificada de um padrão regex (por exemplo Delim1(?s:.*?)\nDelim2.* fará o primeiro .*? combina com as novas linhas e a segunda .* só corresponderá ao restante da linha).

Nota posix:

Em motores não régicos, para combinar com qualquer char, [\s\S] / [\d\D] / [\w\W] construções podem ser usadas.

Em Posix, [\s\S] não está correspondendo a nenhum char (como em JavaScript ou em qualquer motor não-posix) porque as sequências de escape regex não são suportadas dentro de expressões de suporte. [\s\S] é analisado como expressões de suporte que correspondem a um único char, \ ou s ou S.

Em JavaScript, use /[\S\s]*<Foobar>/. Fonte

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

The dot matches all except newlines (\r\n). So use \s\S, which will match ALL characters.

In Ruby you can use the 'm' option (multiline):

/YOUR_REGEXP/m

See the Regexp documentation on ruby-doc.org for more information.

we can also use

(.*?\n)*?

to match everything including newline without greedy

This will make the new line optional

(.*?|\n)*?

"." normally doesn't match line-breaks. Most regex engines allows you to add the S-flag (also called DOTALL and SINGLELINE) to make "." also match newlines. If that fails, you could do something like [\S\s].

For Eclipse worked following expression:

Foo

jadajada Bar"

Regular-Expression:

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

the s causes Dot (.) to match carriage returns

In java based regular expression you can use [\s\S]

Note that (.|\n)* can be less efficient than (for example) [\s\S]* (if your language's regexes support such escapes) and than finding how to specify the modifier that makes . also match newlines. Or you can go with POSIXy alternatives like [[:space:][:^space:]]*.

Use RegexOptions.Singleline, it changes the meaning of . to include newlines

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

Solution:

Use pattern modifier sU will get the desired matching in PHP.

example:

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

Source:

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

In the context of use within languages, regular expressions act on strings, not lines. So you should be able to use the regex normally, assuming that the input string has multiple lines.

In this case, the given regex will match the entire string, since "<FooBar>" is present. Depending on the specifics of the regex implementation, the $1 value (obtained from the "(.*)") will either be "fghij" or "abcde\nfghij". As others have said, some implementations allow you to control whether the "." will match the newline, giving you the choice.

Line-based regular expression use is usually for command line things like egrep.

I had the same problem and solved it in probably not the best way but it works. I replaced all line breaks before I did my real match:

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

I am manipulating HTML so line breaks don't really matter to me in this case.

I tried all of the suggestions above with no luck, I am using .Net 3.5 FYI

In Javascript you can use [^]* to search for zero to infinite characters, including line breaks.

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

generally . doesn't match newlines, so try ((.|\n)*)<foobar>

I wanted to match a particular if block in java

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

   }
...
...
}

If I use the regExp

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

it included the closing brace for the method block so I used

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

to exclude the closing brace from the wildcard match.

Often we have to modify a substring with a few keywords spread across lines preceding the substring. Consider an xml element:

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

Suppose we want to modify the 81, to some other value, say 40. First identify .UID.21..UID., then skip all characters including \n till .PercentCompleted.. The regular expression pattern and the replace specification are:

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>

The subgroup (.|\n) is probably the missing group $3. If we make it non-capturing by (?:.|\n) then the $3 is (<PercentComplete>). So the pattern and replaceSpec can also be:

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

and the replacement works correctly as before.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top