Bagaimana cara mencocokkan karakter apa pun di beberapa baris dalam ekspresi reguler?

358

Misalnya, regex ini

(.*)<FooBar>

akan cocok:

abcde<FooBar>

Tetapi bagaimana cara saya mencocokkannya dengan banyak baris?

abcde
fghij<FooBar>
andyuk
sumber
1
Untuk memperjelas; Saya awalnya menggunakan Eclipse untuk mencari dan mengganti beberapa file. Apa yang saya temukan dengan jawaban di bawah adalah bahwa masalah saya adalah alat dan bukan pola regex.
andyuk
2
Bendera Anda "gerhana" harus dihapus maka karena orang yang mencari solusi gerhana akan menemukan pertanyaan ini (seperti yang saya lakukan) dan kemudian menemukan solusi non-gerhana seperti yang diterima.
acme
2
Sekarang saya menemukan ini di mesin pencari karena gerhana disebutkan. Oh, kengeriannya.
Brian Olsen

Jawaban:

240

Itu tergantung pada bahasa, tetapi harus ada pengubah yang dapat Anda tambahkan ke pola regex. Dalam PHP itu adalah:

/(.*)<FooBar>/s

The s di akhir menyebabkan dot untuk mencocokkan semua karakter termasuk baris.

Jeremy Ruten
sumber
dan bagaimana jika saya hanya ingin baris baru dan tidak semua karakter?
Grace
3
@ Jejak: gunakan \ n untuk mencocokkan baris baru
Jeremy Ruten
5
Bendera s (sekarang?) Tidak valid, setidaknya di Chrome / V8. Alih-alih gunakan / ([\ s \ S] *) <FooBar> / kelas karakter (ruang pertandingan dan non-ruang) alih-alih pencocokan titik. Lihat jawaban lain untuk info lebih lanjut
Allen
8
@ Allen - JavaScript tidak mendukung spengubah. Sebaliknya, lakukan [^]*untuk efek yang sama.
Derek 朕 會 功夫
1
Di Ruby, gunakan mmodifikator
Ryan Buckley
358

Coba ini:

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

Pada dasarnya kata "karakter apa pun atau baris baru" berulang kali nol atau lebih.

levik
sumber
5
Ini tergantung pada bahasa dan / atau alat yang Anda gunakan. Harap beri tahu kami apa yang Anda gunakan, misalnya Perl, PHP, CF, C #, sed, awk, dll.
Ben Doom
39
Tergantung pada akhir baris Anda, Anda mungkin perlu((.|\n|\r)*)<FooBar>
Potherca
3
Dia bilang dia menggunakan Eclipse. Ini solusi yang tepat menurut saya. Saya memiliki masalah yang sama dan ini menyelesaikannya.
Danubian Sailor
4
Benar - pertanyaannya adalah tentang gerhana dan begitu juga tag-nya. Tetapi solusi yang diterima adalah solusi PHP. Anda harus menjadi solusi yang diterima ...
acme
16
Ini adalah regex terburuk untuk mencocokkan beberapa input baris. Harap tidak pernah menggunakannya kecuali Anda menggunakan ElasticSearch. Gunakan [\s\S]*atau (?s).*.
Wiktor Stribiżew
89

Pertanyaannya adalah, bisakah .pola cocok dengan karakter apa pun ? Jawabannya bervariasi dari mesin ke mesin. Perbedaan utama adalah apakah pola tersebut digunakan oleh perpustakaan regex POSIX atau non-POSIX.

Catatan khusus tentang : mereka tidak dianggap sebagai ekspresi reguler, tetapi .cocok dengan karakter apa pun di sana, sama dengan mesin berbasis POSIX.

Catatan lain tentang dan : .cocok dengan karakter apa pun secara default ( demo ): str = "abcde\n fghij<Foobar>"; expression = '(.*)<Foobar>*'; [tokens,matches] = regexp(str,expression,'tokens','match');( tokensberisi abcde\n fghijitem).

Juga, di semua Tata bahasa regex titik tersebut cocok dengan jeda baris secara default. Tata bahasa naskah ECMAS Boost memungkinkan Anda untuk mematikannya dengan regex_constants::no_mod_m( sumber ).

Untuk (berbasis POSIX), gunakan nopsi ( demo ):select regexp_substr('abcde' || chr(10) ||' fghij<Foobar>', '(.*)<Foobar>', 1, 1, 'n', 1) as results from dual

Mesin berbasis POSIX :

Sekedar . sudah cocok dengan jeda baris, tidak perlu menggunakan pengubah, lihat( demo ).

Itu ( demo ),( demo ),(TRE, basis mesin bawaan R tanpa perl=TRUE, untuk basis R dengan perl=TRUEatau stringr / Stringi pola, gunakan (?s)inline pengubah) ( demo ) juga mengobati .dengan cara yang sama.

Namun , sebagian besar alat berbasis POSIX memproses input baris demi baris. Oleh karena itu, .tidak cocok dengan jeda baris hanya karena mereka tidak dalam ruang lingkup. Berikut ini beberapa contoh cara menimpa ini:

  • - Ada beberapa solusi, yang paling tepat tetapi tidak terlalu aman adalah sed 'H;1h;$!d;x; s/\(.*\)><Foobar>/\1/'( H;1h;$!d;x;menyeruput file ke dalam memori). Jika seluruh garis harus disertakan, sed '/start_pattern/,/end_pattern/d' file(menghapus dari awal akan berakhir dengan garis yang cocok disertakan) atau sed '/start_pattern/,/end_pattern/{{//!d;};}' file(dengan garis yang cocok dikecualikan) dapat dipertimbangkan.
  • - perl -0pe 's/(.*)<FooBar>/$1/gs' <<< "$str"( -0menyeruput seluruh file ke dalam memori, -pmencetak file setelah menerapkan skrip yang diberikan oleh -e). Perhatikan bahwa menggunakan -000peakan menghirup file dan mengaktifkan 'mode paragraf' di mana Perl menggunakan baris baru berurutan ( \n\n) sebagai pemisah rekaman.
  • - grep -Poz '(?si)abc\K.*?(?=<Foobar>)' file. Di sini, zmemungkinkan file (?s)slurping , memungkinkan mode DOTALL untuk .pola, (?i)mengaktifkan mode case-insensitive, \Kmenghilangkan teks yang cocok sejauh ini, *?adalah quantifier malas, (?=<Foobar>)cocok dengan lokasi sebelumnya <Foobar>.
  • - pcregrep -Mi "(?si)abc\K.*?(?=<Foobar>)" file( Mmengaktifkan file slurping di sini). Note pcregrepadalah solusi yang baik untuk greppengguna Mac OS .

Lihat demo .

Mesin non-POSIX :

  • - Gunakan spengubah pengubah PCRE_DOTALL : preg_match('~(.*)<Foobar>~s', $s, $m)( demo )
  • - Gunakan RegexOptions.Singlelinebendera ( demo ):
    - var result = Regex.Match(s, @"(.*)<Foobar>", RegexOptions.Singleline).Groups[1].Value;
    -var result = Regex.Match(s, @"(?s)(.*)<Foobar>").Groups[1].Value;
  • - Gunakan (?s)opsi sebaris:$s = "abcde`nfghij<FooBar>"; $s -match "(?s)(.*)<Foobar>"; $matches[1]
  • - Gunakan spengubah (atau (?s)versi inline di awal) ( demo ):/(.*)<FooBar>/s
  • - Gunakan re.DOTALL(atau re.S) (?s)pengubah flag atau inline ( demo ): m = re.search(r"(.*)<FooBar>", s, flags=re.S)(dan kemudian if m:, print(m.group(1)))
  • - Gunakan Pattern.DOTALLpengubah (atau inline (?s)flag) ( demo ):Pattern.compile("(.*)<FooBar>", Pattern.DOTALL)
  • - Gunakan (?s)pengubah dalam pola ( demo ):regex = /(?s)(.*)<FooBar>/
  • - Gunakan (?s)pengubah ( demo ):"(?s)(.*)<Foobar>".r.findAllIn("abcde\n fghij<Foobar>").matchData foreach { m => println(m.group(1)) }
  • - Gunakan [^]atau solusi [\d\D]/ [\w\W]/ [\s\S]( demo ):s.match(/([\s\S]*)<FooBar>/)[1]
  • ( std::regex) Gunakan [\s\S]atau solusi JS ( demo ):regex rex(R"(([\s\S]*)<FooBar>)");
  • - Gunakan pendekatan yang sama seperti dalam JavaScript ([\s\S]*)<Foobar>,. ( CATATAN : MultiLineProperti RegExpobjek kadang-kadang keliru dianggap sebagai opsi untuk memungkinkan .kecocokan lintas garis, sementara, pada kenyataannya, itu hanya mengubah ^dan $perilaku untuk mencocokkan awal / akhir garis daripada string , sama seperti di JS regex ) perilaku.)

  • - Gunakan pengubah /m MULTILINE ( demo ):s[/(.*)<Foobar>/m, 1]

  • - Base R PCRE regexps - gunakan (?s): regmatches(x, regexec("(?s)(.*)<FooBar>",x, perl=TRUE))[[1]][2]( demo )
  • - dalam stringr/ stringifungsi regex yang ditenagai dengan mesin regex ICU, juga menggunakan (?s): stringr::str_match(x, "(?s)(.*)<FooBar>")[,2]( demo )
  • - Gunakan pengubah inline (?s)di awal ( demo ):re: = regexp.MustCompile(`(?s)(.*)<FooBar>`)
  • - Gunakan dotMatchesLineSeparatorsatau (lebih mudah) meneruskan (?s)pengubah inline ke pola:let rx = "(?s)(.*)<Foobar>"
  • - Sama seperti Swift, (?s)bekerja paling mudah, tetapi di sini adalah bagaimana opsi dapat digunakan :NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionDotMatchesLineSeparators error:&regexError];
  • , - Gunakan (?s)pengubah ( demo ): "(?s)(.*)<Foobar>"(di Google Spreadsheets, =REGEXEXTRACT(A2,"(?s)(.*)<Foobar>"))

CATATAN ON(?s) :

Pada sebagian besar mesin non-POSIX, (?s)pengubah inline (atau opsi bendera tertanam) dapat digunakan untuk menegakkan .agar sesuai dengan jeda baris.

Jika ditempatkan di awal pola, (?s)ubah bahavior semua .dalam pola. Jika (?s)ditempatkan di suatu tempat setelah awal, hanya mereka yang .akan terpengaruh yang terletak di sebelah kanan kecuali jika ini adalah pola yang diteruskan ke Python re. Dalam Python re, terlepas dari (?s)lokasi, seluruh pola .terpengaruh. The (?s)Efek dihentikan menggunakan (?-s). Grup yang dimodifikasi hanya dapat digunakan untuk memengaruhi rentang pola regex tertentu (mis. Delim1(?s:.*?)\nDelim2.*Akan membuat .*?kecocokan pertama di seluruh baris baru dan yang kedua .*hanya akan cocok dengan sisa baris lainnya).

Catatan POSIX :

Dalam mesin regex non-POSIX, untuk mencocokkan arang apa pun, [\s\S]/ [\d\D]/ [\w\W]konstruksi dapat digunakan.

Dalam POSIX, [\s\S]tidak cocok dengan karakter apa pun (seperti dalam JavaScript atau mesin non-POSIX) karena urutan pelarian regex tidak didukung di dalam ekspresi braket. [\s\S]diuraikan sebagai ekspresi braket yang cocok dengan satu karakter, \atau satau S.

Wiktor Stribiżew
sumber
5
Anda harus menautkan ke ikhtisar luar biasa ini dari halaman profil Anda atau sesuatu (+1).
Jan
1
Anda mungkin ingin menambahkan ini ke item boost : Di namespace regex_constants, flag_type_'s: perl = ECMAScript = JavaScript = JScript = :: boost :: regbase :: normal = 0 yang default ke Perl. Pemrogram akan menetapkan definisi bendera dasar #define MOD regex_constants::perl | boost::regex::no_mod_s | boost::regex::no_mod_muntuk bendera regex mereka untuk mencerminkan hal itu. Dan wasit selalu pengubah inline. Di mana (?-sm)(?s).*ulang.
1
Bisakah Anda menambahkan untuk bash?
Pasupathi Rajamanickam
2
@PasupathiRajamanickam Bash menggunakan mesin regex POSIX, .cocok dengan semua karakter di sana (termasuk jeda baris). Lihat demo Bash online ini .
Wiktor Stribiżew
1
You rock - ini adalah tutorial mini paling lengkap tentang regexp (relatif) kompleks yang pernah saya lihat. Anda pantas menerima jawaban Anda! Kudos dan suara tambahan untuk dimasukkan Godalam jawaban!
Gwyneth Llewelyn
68

Jika Anda menggunakan pencarian Eclipse, Anda dapat mengaktifkan opsi "DOTALL" untuk membuat '.' cocok dengan karakter apa pun termasuk pembatas garis: cukup tambahkan "(? s)" di awal string pencarian Anda. Contoh:

(?s).*<FooBar>
Paulo Merson
sumber
1
Tidak di mana pun, hanya dalam rasa regex mendukung pengubah inline, dan tentu saja tidak di Ruby di mana (?s)=>(?m)
Wiktor Stribiżew
Ada sesuatu untuk bash?
Pasupathi Rajamanickam
38

Dalam banyak dialek regex, /[\S\s]*<Foobar>/akan melakukan apa yang Anda inginkan. Sumber

Abbas Shahzadeh
sumber
2
Dari tautan itu: "JavaScript dan VBScript tidak memiliki opsi untuk membuat karakter pemecah garis titik cocok. Dalam bahasa-bahasa itu, Anda dapat menggunakan kelas karakter seperti [\ s \ S] untuk mencocokkan karakter apa pun." Alih-alih. gunakan [\ s \ S] (cocokkan spasi dan bukan spasi) sebagai gantinya.
Allen
32

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

Titik cocok dengan semua kecuali baris baru (\ r \ n). Jadi gunakan \ s \ S, yang akan cocok dengan SEMUA karakter.

samwize
sumber
Ini memecahkan masalah jika Anda menggunakan Objective-C [text rangeOfString:regEx options:NSRegularExpressionSearch]. Terima kasih!
J. Costa
1
Ini berfungsi di temukan & ganti regex intelliJ, terima kasih.
barclay
Ini bekerja. Tapi itu harus menjadi kejadian pertama<FooBar>
Ozkan
18

Di Ruby Anda dapat menggunakan opsi ' m' (multiline):

/YOUR_REGEXP/m

Lihat dokumentasi Regexp di ruby-doc.org untuk informasi lebih lanjut.

vibaiher
sumber
13

kita juga bisa menggunakan

(.*?\n)*?

untuk mencocokkan semuanya termasuk baris baru tanpa serakah

Ini akan membuat baris baru opsional

(.*?|\n)*?
Nambi_0915
sumber
8

"."biasanya tidak cocok dengan jeda baris. Sebagian besar mesin regex memungkinkan Anda untuk menambahkan S-flag (juga disebut DOTALLdan SINGLELINE) untuk membuat "."juga cocok dengan baris baru. Jika itu gagal, Anda bisa melakukan sesuatu seperti [\S\s].

Markus Jarderot
sumber
8

Untuk Eclipse berfungsi sebagai berikut:

Foo

jadajada Bar "

Ekspresi Reguler:

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

s menyebabkan Dot (.) cocok dengan carriage return

Tagihan
sumber
Sepertinya ini tidak valid (Chrome): text.match (/ a / s) SyntaxError: Bendera tidak valid yang diberikan ke RegExp constructor '
Allen
Karena itu tidak didukung dalam mesin JavaScript RegEx. The sbendera ada di PCRE, paling mesin lengkap (tersedia dalam Perl dan PHP). PCRE memiliki 10 flag (dan banyak fitur lainnya) sementara JavaScript hanya memiliki 3 flag ( gmi).
Morgan Touverey Quilling
4

Dalam ekspresi reguler berbasis java yang dapat Anda gunakan [\s\S]

Kamahire
sumber
1
Bukankah seharusnya itu garis miring terbalik?
Paul Draper
Mereka pergi di akhir Ekspresi Reguler, bukan di dalam. Contoh: / blah / s
RandomInsano
Saya kira maksud Anda JavaScript, bukan Java? Karena Anda bisa menambahkan sflag ke pola di Java dan JavaScript tidak memiliki sflag.
3limin4t0r
3

Catatan yang (.|\n)*bisa kurang efisien daripada (misalnya) [\s\S]*(jika regex bahasa Anda mendukung pelarian semacam itu) dan daripada menemukan cara menentukan pengubah yang membuat. juga cocok dengan baris baru. Atau Anda dapat pergi dengan POSIX seperti alternatif [[:space:][:^space:]]*.

tye
sumber
3

Gunakan RegexOptions.Singleline, itu mengubah arti. untuk memasukkan baris baru

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

shmall
sumber
1

Dalam konteks penggunaan dalam bahasa, ekspresi reguler berlaku pada string, bukan garis. Jadi Anda harus dapat menggunakan regex secara normal, dengan asumsi bahwa string input memiliki beberapa baris.

Dalam hal ini, regex yang diberikan akan cocok dengan seluruh string, karena "<FooBar>" hadir. Bergantung pada spesifikasi implementasi regex, nilai $ 1 (diperoleh dari "(. *)") Akan berupa "fghij" atau "abcde \ nfghij". Seperti yang orang lain katakan, beberapa implementasi memungkinkan Anda untuk mengontrol apakah "." akan cocok dengan baris baru, memberi Anda pilihan.

Penggunaan ekspresi reguler berbasis garis biasanya untuk hal-hal baris perintah seperti egrep.

tidak doa
sumber
1

Saya memiliki masalah yang sama dan menyelesaikannya mungkin bukan cara terbaik tetapi berhasil. Saya mengganti semua jeda baris sebelum melakukan pertandingan yang sebenarnya:

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

Saya memanipulasi HTML sehingga jeda baris tidak terlalu berarti bagi saya dalam hal ini.

Saya mencoba semua saran di atas tanpa hasil, saya menggunakan. Net 3.5 FYI

Lengan
sumber
Saya menggunakan .NET juga dan (\s|\S)sepertinya melakukan trik untuk saya!
Vamshi Krishna
@VamshiKrishna Di .NET, gunakan (?s)untuk membuat .cocok dengan karakter apa pun. Jangan gunakan (\s|\S)itu akan memperlambat kinerja.
Wiktor Stribiżew
1

Di Javascript, Anda dapat menggunakan [^] * untuk mencari karakter nol hingga tak hingga, termasuk jeda baris.

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

Paul Chris Jones
sumber
0

umumnya. tidak cocok dengan baris baru, jadi cobalah((.|\n)*)<foobar>

tloach
sumber
3
Tidak, jangan lakukan itu. Jika Anda perlu mencocokkan apa pun termasuk pemisah baris, gunakan pengubah DOTALL (alias / s atau SingleLine). Tidak hanya peretasan (. | \ N) membuat regex kurang efisien, bahkan tidak benar. Paling tidak, itu harus cocok dengan \ r (carriage return) serta \ n (linefeed). Ada karakter pemisah garis lain juga, meskipun jarang digunakan. Tetapi jika Anda menggunakan bendera DOTALL, Anda tidak perlu khawatir tentang mereka.
Alan Moore
1
\ R adalah pertandingan bebas platform untuk baris baru di Eclipse.
Opyate
@ Salin Anda harus memposting ini sebagai jawaban karena permata kecil ini sangat berguna.
jeckhart
Anda bisa mencoba ini sebagai gantinya. Ini tidak akan cocok dengan kurung bagian dalam dan juga mempertimbangkan opsional \r.:((?:.|\r?\n)*)<foobar>
ssc-hrep3
0

Saya ingin mencocokkan blok if tertentu di java

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

   }
...
...
}

Jika saya menggunakan regExp

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

itu termasuk kurung kurawal untuk blok metode jadi saya gunakan

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

untuk mengecualikan kurung kurawal dari pertandingan wildcard.

Spangen
sumber
0

Seringkali kita harus memodifikasi substring dengan beberapa kata kunci yang tersebar di seluruh baris sebelum substring. Pertimbangkan elemen xml:

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

Misalkan kita ingin memodifikasi 81, ke beberapa nilai lain, katakan 40. Pertama identifikasi .UID.21..UID., lalu lewati semua karakter termasuk \nsampai .PercentCompleted.. Pola ekspresi reguler dan spesifikasi ganti adalah:

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>

Subkelompok (.|\n)mungkin adalah grup yang hilang $3. Jika kita membuatnya tidak menangkap pada (?:.|\n)saat $3itu (<PercentComplete>). Jadi polanya dan replaceSpecbisa juga:

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

dan penggantian berfungsi dengan benar seperti sebelumnya.

pengguna1348737
sumber
0

Biasanya mencari tiga baris berturut-turut di Powershell akan terlihat seperti:

$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

Anehnya, ini akan menjadi teks unix saat diminta, tetapi jendela teks dalam file:

$pattern = 'lineone
linetwo
linethree
'

Berikut cara untuk mencetak akhir baris:

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

# output
lineone\nlinetwo\nlinethree\n
js2010
sumber
-2

Pilihan 1

Salah satu caranya adalah dengan menggunakan sflag (seperti jawaban yang diterima):

/(.*)<FooBar>/s

Demo 1

pilihan 2

Cara kedua adalah dengan menggunakan mflag (multiline) dan salah satu dari pola berikut:

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

atau

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

atau

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

Demo 2

Sirkuit RegEx

jex.im memvisualisasikan ekspresi reguler:

masukkan deskripsi gambar di sini

Emma
sumber