Как мне сопоставить любой символ в нескольких строках регулярного выражения?


358

Например, это регулярное выражение

(.*)<FooBar>

будет соответствовать:

abcde<FooBar>

Но как мне сделать так, чтобы он совпадал по нескольким строкам?

abcde
fghij<FooBar>

1
Уточнить; Первоначально я использовал Eclipse для поиска и замены в нескольких файлах. Из ответов ниже я обнаружил, что моей проблемой был инструмент, а не шаблон регулярных выражений.
Андюк

2
Ваш флаг «затмение» должен быть удален, потому что тот, кто ищет решение для затмения, найдет этот вопрос (как я), а затем найдет решение без затмения, как принятое.
Acme

2
Теперь я нахожу это в поисковой системе, потому что затмение было упомянуто. Ох уж ужас.
Брайан Олсен

Ответы:


240

Это зависит от языка, но должен быть модификатор, который вы можете добавить к шаблону регулярных выражений. В PHP это:

/(.*)<FooBar>/s

Символ s в конце заставляет точку совпадать со всеми символами, включая символы новой строки.


а что если я хотел просто новую строку, а не все символы?
Грейс

3
@Grace: используйте \ n для соответствия новой строки
Джереми Рутен

5
Флаг s (сейчас?) Недействителен, по крайней мере, в Chrome / V8. Вместо этого используйте / ([\ s \ S] *) <FooBar> / символьный класс (соответствует пробелу и не пробелу) вместо сопоставителя периода. См. Другие ответы для получения дополнительной информации.
Аллен

8
@Allen - JavaScript не поддерживает sмодификатор. Вместо этого делайте [^]*для того же эффекта.
Дерек 朕 會 功夫

1
В Ruby используйте mмодификатор
Райан Бакли

358

Попробуй это:

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

Это в основном говорит, что «любой символ или перевод строки» повторяется ноль или более раз.


5
Это зависит от языка и / или инструмента, который вы используете. Пожалуйста, дайте нам знать, что вы используете, например, Perl, PHP, CF, C #, sed, awk и т. Д.
Ben Doom

39
В зависимости от окончания вашей линии вам может понадобиться((.|\n|\r)*)<FooBar>
Potherca

3
Он сказал, что использует Eclipse. Это правильное решение на мой взгляд. У меня та же проблема, и это решило ее.
Дунайский моряк

4
Правильно - вопрос о затмении, как и о тегах. Но принятое решение - это решение PHP. Ваше решение должно быть принято ...
acme

16
Это худшее регулярное выражение для сопоставления многострочного ввода. Пожалуйста, никогда не используйте его, если вы не используете ElasticSearch. Используйте [\s\S]*или (?s).*.
Виктор Стрибовев

89

Вопрос в том, может ли .шаблон соответствовать любому персонажу? Ответ варьируется от двигателя к двигателю. Основное различие заключается в том, используется ли шаблон библиотекой регулярных выражений POSIX или не-POSIX.

Специальное примечание о : они не считаются регулярными выражениями, но .соответствуют любому символу там, так же как и движки на основе POSIX.

Еще одна заметка о а также : .соответствует любому символу по умолчанию ( демо ): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match');( tokensсодержит abcde\n fghijэлемент).

Кроме того, во всех По умолчанию в регулярных выражениях точка соответствует разрывам строк. Boost's ECMAScript грамматика позволяет отключить это с помощью regex_constants::no_mod_m( источник ).

Что касается (это основано на POSIX), используйте nопцию ( демо ):select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual

Двигатели на базе POSIX :

Простое .уже соответствует разрывам строк, нет необходимости использовать какие-либо модификаторы, см.( демо ).

( демо ),( демо ),(TRE, базовый двигатель по умолчанию R с не perl=TRUEдля базового R с perl=TRUEили для stringr / STRINGI шаблонов, использовать (?s)модификатор инлайн) ( демонстрационный ) также относиться к .таким же образом.

Однако большинство инструментов на основе POSIX обрабатывают ввод построчно. Следовательно, .не соответствует разрывы строк только потому, что они не находятся в области видимости. Вот несколько примеров, как это переопределить:

  • - Существует несколько обходных путей, самый точный, но не очень безопасный sed 'H;1h;$!d;x; s/\(.*\)><Foobar>/\1/'( H;1h;$!d;x;выкладывает файл в память). Если целые строки должны быть включены, sed '/start_pattern/,/end_pattern/d' file(удаление с начала закончится с включенными совпадающими строками) или sed '/start_pattern/,/end_pattern/{{//!d;};}' file(с исключенными совпадающими строками) может быть рассмотрено.
  • - perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str"( -0удаляет весь файл в память, -pпечатает файл после применения сценария, заданного -e). Обратите внимание, что при использовании -000peбудет захвачен файл и активирован «режим абзаца», где Perl использует последовательные символы новой строки ( \n\n) в качестве разделителя записей.
  • - grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file. Здесь, zвключает в себя файл slurping, (?s)включает режим DOTALL для .шаблона, (?i)включает режим без учета регистра, \Kпропускает сопоставленный текст до сих пор, *?является ленивым квантификатором, (?=<Foobar>)соответствует местоположению ранее <Foobar>.
  • - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file(здесь Mвключается слежка за файлами). Примечание pcregrep- хорошее решение для grepпользователей Mac OS .

Смотрите демоверсии .

Двигатели без POSIX :

  • - Используйте sмодификатор PCRE_DOTALL модификатор : preg_match('~(.*)<Foobar>~s', $s, $m)( демо )
  • - Используйте RegexOptions.Singlelineфлаг ( демо ):
    - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
    -var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
  • - Используйте (?s)встроенную опцию:$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
  • - Используйте sмодификатор (или (?s)встроенную версию в начале) ( демо ):/(.*)<FooBar>/s
  • - Используйте re.DOTALL(или re.S) флаги или (?s)встроенный модификатор ( демо ): m = re.search(r"(.*)<FooBar>", s, flags=re.S)(а затем if m:, print(m.group(1)))
  • - Использовать Pattern.DOTALLмодификатор (или встроенный (?s)флаг) ( демо ):Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
  • - Использовать (?s)модификатор in-pattern ( демо ):regex = /(?s)(.*)<FooBar>/
  • - Использовать (?s)модификатор ( демо ):"(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
  • - Использование [^]или обходные пути [\d\D]/ [\w\W]/ [\s\S]( демо ):s.match(/([\s\S]*)<FooBar>/)[1]
  • ( std::regex) Используйте [\s\S]или обходные пути JS ( демо ):regex rex(R"(([\s\S]*)<FooBar>)");
  • - Используйте тот же подход, что и в JavaScript ([\s\S]*)<Foobar>. ( Примечание : MultiLineсвойство RegExpобъекта иногда ошибочно считается вариант , чтобы .матч через разрывы строк, в то время как, на самом деле, он изменяет только ^и $поведение , чтобы соответствовать начало / конец строки , а не строки , так же , как и в JS регулярное выражение ) поведение.)

  • - Использовать модификатор /m MULTILINE ( демо ):s[/(.*)<Foobar>/m, 1]

  • - База R регулярных выражений PCRE - использование (?s): regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2]( демо )
  • - функции in stringr/ stringiregex, работающие на движке ICU regex, также используют (?s): stringr::str_match(x, "(?s)(.*)<FooBar>")[,2]( demo )
  • - Используйте встроенный модификатор (?s)в начале ( демо ):re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
  • - Используйте dotMatchesLineSeparatorsили (проще) передайте (?s)встроенный модификатор в шаблон:let rx = "(?s)(.*)<Foobar>"
  • - Так же, как Swift, (?s)работает проще всего, но вот как эта опция может быть использована :NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
  • , - Использовать (?s)модификатор ( демо ): "(?s)(.*)<Foobar>"(в таблицах Google, =REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

ЗАМЕЧАНИЯ ПО(?s) :

В большинстве не POSIX-движков (?s)встроенный модификатор (или опция встроенного флага) может использоваться для принудительного .сопоставления разрывов строк.

Если поместить в начало шаблона, (?s)изменяет поведение всех .в шаблоне. Если(?s) он расположен где-то после начала, .будут затронуты только те , которые расположены справа от него, если только это не шаблон, переданный Python re. В Python re, независимо от (?s)местоположения, .затрагивается весь шаблон . (?s)Эффект перестал использовать (?-s). Модифицированная группа может использоваться, чтобы влиять только на указанный диапазон шаблона регулярного выражения (например Delim1(?s:.*?)\nDelim2.*, первое .*?совпадение будет выполнено через новые строки, а второе .*совпадет только с остальной частью строки).

POSIX примечание :

В не-POSIX регулярных выражениях для соответствия любому символу могут использоваться конструкции [\s\S]/ [\d\D]/ [\w\W].

В POSIX [\s\S]не соответствует ни одному символу (как в JavaScript или любом не-POSIX-движке), потому что escape-последовательности regex не поддерживаются в выражениях в скобках.[\s\S]анализируется как выражения в скобках, которые соответствуют одному символу, \или sили S.


5
Вы должны дать ссылку на этот отличный обзор со страницы своего профиля или что-то (+1).
Jan

1
Возможно, вы захотите добавить это к элементу boost : в пространстве имен regex_constants, flag_type_'s: perl = ECMAScript = JavaScript = JScript = :: boost :: regbase :: normal = 0, который по умолчанию равен Perl. Программисты установят определение базового флага #define MOD regex_constants::perl | boost::regex::no_mod_s | boost::regex::no_mod_mдля своих флагов регулярных выражений, чтобы отразить это. А арбитор всегда встроенные модификаторы. Где (?-sm)(?s).*сбрасывает.

1
Вы также можете добавить для Баш, пожалуйста?
Пасупати Раджаманикам

2
@PasupathiRajamanickam Bash использует механизм регулярных выражений POSIX, который .соответствует любому символу (включая разрывы строк). Посмотрите это онлайн демо Bash .
Виктор Стрибьев

1
Вы качаетесь - это самый исчерпывающий мини-учебник по (относительно) сложному регулярному выражению, который я когда-либо видел. Вы заслуживаете того, чтобы ваш ответ стал принятым! Слава и дополнительные голоса за включение Goв ответ!
Гвинет Ллевелин

68

Если вы используете поиск Eclipse, вы можете включить опцию "DOTALL", чтобы сделать '.' соответствует любому символу, включая разделители строк: просто добавьте «(? s)» в начале строки поиска. Пример:

(?s).*<FooBar>

1
Не где-нибудь, только в регулярных выражениях, поддерживающих встроенные модификаторы, и, конечно, не в Ruby где (?s)=>(?m)
Wiktor Stribiżew

Что-нибудь для Баш?
Пасупати Раджаманикам

38

Во многих диалектах регулярных выражений /[\S\s]*<Foobar>/будет делать то, что вы хотите. Источник


2
По этой ссылке: «JavaScript и VBScript не имеют возможности сделать символы разрыва строки, совпадающие с точкой. В этих языках вы можете использовать класс символов, например [\ s \ S], для соответствия любому символу». Вместо. используйте вместо этого [\ s \ S] (совпадение пробелов и не пробелов).
Аллен

32

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

Точка соответствует всем кроме новых строк (\ r \ n). Поэтому используйте \ s \ S, который будет соответствовать ВСЕМ символам.


Это решит проблему, если вы используете Objective-C [text rangeOfString:regEx options:NSRegularExpressionSearch]. Спасибо!
Дж. Коста

1
Это работает в поиске и замене IntelliJ, спасибо.
Барклай

Это работает. Но это должно быть первое появление<FooBar>
Озкан


13

мы также можем использовать

(.*?\n)*?

чтобы соответствовать всем, включая перевод строки без жадных

Это сделает новую строку необязательной

(.*?|\n)*?

8

"."обычно не соответствует переводу строки. Большинство движков регулярных выражений позволяет добавлять Sфлаг (также называемый DOTALLи SINGLELINE), чтобы "."также соответствовать символам новой строки. Если это не поможет, вы можете сделать что-то вроде [\S\s].


8

Для Eclipse сработало следующее выражение:

Foo

Джададжада Бар "

Регулярные выражения:

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

5
/(.*)<FooBar>/s

s приводит к тому, что точка (.) совпадает с возвратом каретки


Похоже, это недопустимо (Chrome): text.match (/ a / s) SyntaxError: Недопустимые флаги, предоставленные конструктору RegExp 's'
Аллен

Потому что это не поддерживается в движках JavaScript RegEx. Эти sфлаги существует в PCRE, наиболее полный двигатель (доступен в Perl и PHP). PCRE имеет 10 флагов (и множество других функций), в то время как JavaScript имеет только 3 флага ( gmi).
Морган Тувери Квиллинг

4

В регулярном выражении на основе Java вы можете использовать [\s\S]


1
Разве это не должны быть обратные слеши?
Пол Дрэйпер

Они идут в конце регулярного выражения, а не в
дюйме

Я полагаю, вы имеете в виду JavaScript, а не Java? Поскольку вы можете просто добавить sфлаг к шаблону в Java, а JavaScript не имеет sфлага.
3limin4t0r

3

Обратите внимание, что это (.|\n)*может быть менее эффективно, чем (например) [\s\S]*(если регулярные выражения вашего языка поддерживают такие экранированные символы), и чем найти способ определения используемого модификатора. также соответствуйте новым строкам. Или вы можете пойти с POSIXy альтернативы, как [[:space:][:^space:]]*.


3

Используйте RegexOptions.Singleline, это меняет значение. включить переводы строки

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



1

В контексте использования в языках регулярные выражения действуют на строки, а не на строки. Таким образом, вы сможете нормально использовать регулярные выражения, предполагая, что входная строка имеет несколько строк.

В этом случае данное регулярное выражение будет соответствовать всей строке, поскольку присутствует «<FooBar>». В зависимости от особенностей реализации регулярного выражения, значение $ 1 (полученное из «(. *)») Будет либо «fghij», либо «abcde \ nfghij». Как уже говорили другие, некоторые реализации позволяют вам контролировать, стоит ли "." будет соответствовать новой строке, предоставляя вам выбор.

Использование регулярных выражений на основе строки обычно используется для таких вещей, как egrep.


1

У меня была та же проблема, и я решил ее, вероятно, не лучшим образом, но она работает. Я заменил все разрывы строк, прежде чем я сделал свой реальный матч:

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

Я манипулирую HTML, поэтому разрывы строк не имеют для меня большого значения в этом случае.

Я попробовал все предложения выше без удачи, я использую .Net 3.5 FYI


Я тоже использую .NET и, (\s|\S)кажется, добился цели!
Вамши Кришна

@VamshiKrishna В .NET используйте (?s)для .сопоставления любых символов. Не используйте (\s|\S)это замедлит производительность.
Виктор Стрибьев,

1

В Javascript вы можете использовать [^] * для поиска от нуля до бесконечных символов, включая разрывы строк.

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

в общем . не соответствует переводу строки, поэтому попробуйте((.|\n)*)<foobar>


3
Нет, не делай этого. Если вам нужно сопоставить что-либо, включая разделители строк, используйте модификатор DOTALL (aka / s или SingleLine). Мало того, что взлом (. | \ N) делает регулярное выражение менее эффективным, это даже не правильно. По крайней мере, он должен соответствовать \ r (возврат каретки), а также \ n (перевод строки). Есть и другие символы разделителя строк, хотя они используются редко. Но если вы используете флаг DOTALL, вам не нужно беспокоиться о них.
Алан Мур

1
\ R - независимое от платформы совпадение для новых строк в Eclipse.
Опять

@opyate Вы должны опубликовать это как ответ, так как этот маленький драгоценный камень невероятно полезен.
Джекхарт

Вы можете попробовать это вместо этого. Он не будет соответствовать внутренним скобкам, а также рассмотрит необязательные \r.:((?:.|\r?\n)*)<foobar>
ssc-hrep3

0

Я хотел, чтобы соответствовать конкретный, если блок в Java

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

   }
...
...
}

Если я использую regExp

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

он включал закрывающую скобку для блока метода, поэтому я использовал

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

исключить закрывающую скобку из совпадения с подстановочными знаками.


0

Часто нам приходится изменять подстроку с несколькими ключевыми словами, разбросанными по строкам, предшествующим подстроке. Рассмотрим элемент xml:

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

Предположим, что мы хотим изменить значение 81 до некоторого другого значения, скажем, 40. Сначала определите .UID.21..UID., а затем пропустите все символы, в том числе и \nдо .PercentCompleted.. Шаблон регулярного выражения и спецификация замены:

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>

Подгруппа (.|\n), вероятно, является отсутствующей группой $3. Если мы сделаем это без захвата, (?:.|\n)то $3есть (<PercentComplete>). Таким образом, шаблон replaceSpecтакже может быть:

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

и замена работает правильно, как и раньше.


0

Обычно при поиске трех последовательных строк в Powershell это выглядит так:

$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

Как ни странно, это будет текст UNIX в приглашении, но текст Windows в файле:

$pattern = 'lineone
linetwo
linethree
'

Вот способ распечатать окончания строк:

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

# output
lineone\nlinetwo\nlinethree\n

-2

Опция 1

Один из способов - использовать sфлаг (так же, как принятый ответ):

/(.*)<FooBar>/s

Демо 1

Вариант 2

Второй способ - использовать mфлаг (многострочный) и любой из следующих шаблонов:

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

или

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

или

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

Демо 2

RegEx Circuit

jex.im визуализирует регулярные выражения:

введите описание изображения здесь

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.