Як я можу зіставити будь-який символ у кількох рядках у звичайному виразі?


356

Наприклад, це регулярний вираз

(.*)<FooBar>

відповідатиме:

abcde<FooBar>

Але як змусити його збігатися по декількох рядках?

abcde
fghij<FooBar>

1
Для уточнення; Я спочатку використовував Eclipse для пошуку та заміни в декількох файлах. Що я виявив у відповідях нижче, це те, що моєю проблемою був інструмент, а не виразний зразок.
андюк

2
Ваш прапор "затемнення" слід видалити, тому що той, хто шукає рішення затемнення, знайде це питання (як я), а потім знайде рішення не затемнення як прийняте.
акме

2
Зараз я знаходжу це в пошуковій системі, бо згадувалося затемнення. О жах.
Брайан Олсен

Відповіді:


240

Це залежить від мови, але має бути модифікатор, який ви можете додати до шаблону регулярних виразів. У PHP це:

/(.*)<FooBar>/s

S в кінці приводить точку , щоб відповідати все символи , включаючи символ нового рядка.


а що, якби я хотів лише новий рядок, а не всіх символів?
благодать

3
@Grace: використовуйте \ n, щоб відповідати новій лінії
Джеремі Рутен

5
Прапор s (зараз?) Недійсний, принаймні в Chrome / V8. Замість цього використовуйте / ([\ s \ S] *) <FooBar> / символ класу (відповідність простору та непробілу] замість відповідника періоду. Див. Інші відповіді для отримання додаткової інформації.
Аллен

8
@Allen - JavaScript не підтримує sмодифікатор. Натомість зробіть [^]*для того ж ефекту.
Дерек 朕 會 功夫

1
У Ruby використовуйте mмодифікатор
Ryan Buckley

357

Спробуйте це:

((.|\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).*.
Wiktor Stribiżew

88

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

Особлива примітка о : вони не вважаються регулярними виразами, але .відповідають будь-яким символам, таких як двигуни на основі POSIX.

Ще одна примітка і : .відповідає будь-якому знаку за замовчуванням ( демо ): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match');( tokensмістить abcde\n fghijелемент).

Також у всіх граматики з регулярними виразами крапки розбивають рядки за замовчуванням. Граматика ECMAScript Boost дозволяє вимкнути це 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 :

Простий .вже відповідає розривам рядків, не потрібно використовувати будь-які модифікатори, див( демонстрація ).

The ( демонстрація ),( демонстрація ),(TRE, базовий двигун за замовчуванням без 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файлів, (?s)увімкнено режим DOTALL для .шаблону, увімкнення режиму (?i)нечутливості до регістру, \Kвідмовлення від відповідного тексту досі, *?ледачий кількісний показник, (?=<Foobar>)відповідає розташуванню раніше<Foobar> .
  • - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file( Mтут вмикається розбиття файлів). Примітка pcregrep- це гарне рішення для grepкористувачів ОС Mac .

Дивіться демонстрацію .

Двигуни на основі 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)вбудований модифікатор ( демонстрацію ):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 regex ) поведінка.)

  • - Використовуйте модифікатор /m MULTILINE ( демонстрацію ):s[/(.*)<Foobar>/m, 1]

  • - Bage R PCRE regexps - використання (?s): regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2]( демонстрація )
  • - у функціях in stringr/ stringiregex, які працюють з двигуном регулярного генерування ICU, також використовується (?s): stringr::str_match(x, "(?s)(.*)<FooBar>")[,2]( демонстрація )
  • - Використовуйте вбудований модифікатор (?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), оскільки послідовності виведення регулярних виразів не підтримуються у виразах дужок. [\s\S]аналізується як брекет виразів , які відповідають один символ, \або , sабо S.


5
Ви маєте посилання на цей чудовий огляд зі своєї сторінки профілю чи щось (+1).
січня

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
Ви можете також додати баш, будь ласка?
Pasupathi Rajamanickam

2
@PasupathiRajamanickam Bash використовує механізм регулярного вибиття POSIX, який .відповідає будь-яким знакам там (включаючи розриви рядків). Дивіться цю Інтернет-демонстрацію Bash .
Wiktor Stribiżew

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

68

Якщо ви використовуєте пошук Eclipse, ви можете ввімкнути опцію "DOTALL", щоб зробити "." відповідати будь-якому символу, включаючи роздільники рядків: просто додайте "(? s)" на початку пошуку. Приклад:

(?s).*<FooBar>

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

Що-небудь для баш?
Pasupathi Rajamanickam

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, дякую.
barclay

Це працює. Але це має бути першим явищем<FooBar>
Оскан


13

ми також можемо використовувати

(.*?\n)*?

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

Це зробить новий рядок необов’язковим

(.*?|\n)*?

8

"."зазвичай не відповідає розривам рядків. Більшість двигунів Sрегексу дозволяє додавати -flag (також називається DOTALLта SINGLELINE), щоб "."також відповідати новим рядкам . Якщо це не вдасться, ви можете зробити щось подібне [\S\s].


8

Для Eclipse працював наступний вираз:

Foo

jadajada Bar "

Регулярні вирази:

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

5
/(.*)<FooBar>/s

s викликає, що точка (.) збігається з поверненнями каретки


Здається, це недійсно (Chrome): text.match (/ a / s) SyntaxError: Недійсні прапори, що надходять до конструктора RegExp '
Аллен

Тому що він не підтримується в JavaScript RegEx двигунах. Ці sпрапори існує в PCRE, найбільш повний двигун (доступний в Perl і PHP). PCRE має 10 прапорів (та багато інших функцій), тоді як у JavaScript є лише 3 прапори ( gmi).
Morgan Touverey Quilling

4

У регулярному виразі на базі Java ви можете використовувати [\s\S]


1
Не повинні вони бути нахилами?
Пол Дрейпер

Вони йдуть наприкінці регулярного виразу, а не в. Приклад: / blah / s
RandomInsano

Я думаю, ви маєте на увазі JavaScript, а не Java? Оскільки ви можете просто додати sпрапор до шаблону на Java, а у JavaScript немає цього sпрапора.
3limin4t0r

3

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


3

Використовуйте RegexOptions.Singleline, це змінює значення. для включення нових рядків

Regex.Replace (вміст, searchText, substituText, 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)це, щоб уповільнити продуктивність.
Wiktor Stribiżew

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 (linefeed). Існують і інші символи розділення рядків, хоча вони рідко використовуються. Але якщо ви використовуєте прапор DOTALL, вам не доведеться турбуватися про них.
Алан Мур

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

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