Saya mencoba mencocokkan teks multi-baris menggunakan java. Ketika saya menggunakan Pattern
kelas dengan Pattern.MULTILINE
pengubah, saya dapat mencocokkan, tetapi saya tidak dapat melakukannya dengan(?m).
Pola yang sama dengan (?m)
dan menggunakanString.matches
tampaknya tidak berhasil.
Saya yakin saya kehilangan sesuatu, tetapi tidak tahu apa. Tidak terlalu bagus dalam ekspresi reguler.
Ini yang saya coba
String test = "User Comments: This is \t a\ta \n test \n\n message \n";
String pattern1 = "User Comments: (\\W)*(\\S)*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find()); //true
String pattern2 = "(?m)User Comments: (\\W)*(\\S)*";
System.out.println(test.matches(pattern2)); //false - why?
(?s)User Comments:\s*(.*)
. Dari jawaban @Amarghosh saya mendapatkan polanyaUser Comments: [\\s\\S]*
. Di antaranya ada cara yang lebih baik atau direkomendasikan atau hanya dua cara yang berbeda untuk melakukan hal yang sama?[\s\S]
sedikit lebih eksplisit ("cocok dengan karakter apa pun yang merupakan spasi putih atau non-spasi putih"),.
lebih mudah dibaca, tetapi Anda perlu mencari(?s)
atauDOTALL
pengubah untuk mengetahui apakah baris baru disertakan atau tidak. Saya lebih suka.
denganPattern.DOTALL
set bendera (ini lebih mudah dibaca dan diingat daripada(?s)
menurut saya. Anda harus menggunakan apa yang Anda rasa paling nyaman..*
denganDOTALL
lebih mudah dibaca. Saya menggunakan yang lain untuk menunjukkan bahwa masalah ini adalah perbedaan antara str.matches dan matcher.find dan bukan bendera. +1.*
denganPattern.DOTALL
, tetapi harus pergi dengan (? S) karena saya harus menggunakanString.matches
.Ini tidak ada hubungannya dengan bendera MULTILINE; apa yang Anda lihat adalah perbedaan antara
find()
matches()
metode dan metode.find()
berhasil jika kecocokan dapat ditemukan di mana saja di string target , sementaramatches()
mengharapkan regex untuk mencocokkan seluruh string .Selain itu,
MULTILINE
tidak berarti apa yang Anda pikirkan. Banyak orang tampaknya melompat ke kesimpulan bahwa Anda harus menggunakan bendera itu jika string target Anda berisi baris baru - yaitu, jika itu berisi beberapa baris logis. Saya telah melihat beberapa jawaban di sini pada SO untuk efek itu, tetapi pada kenyataannya, semua yang dilakukan flag adalah mengubah perilaku jangkar,^
dan$
.Biasanya
^
cocok dengan yang paling awal dari string target, dan$
cocok dengan yang paling akhir (atau sebelum baris baru di akhir, tapi kami akan mengesampingkannya untuk saat ini). Tetapi jika string berisi baris baru, Anda dapat memilih^
dan$
mencocokkan pada awal dan akhir dari setiap baris logis, bukan hanya awal dan akhir dari seluruh string, dengan mengatur bendera MULTILINE.Jadi lupakan apa
MULTILINE
berarti dan hanya ingat apa yang dilakukannya : mengubah perilaku^
dan$
jangkar.DOTALL
mode awalnya disebut "single-line" (dan masih dalam beberapa rasa, termasuk Perl dan .NET), dan selalu menyebabkan kebingungan yang sama. Kami beruntung bahwa para pengembang Java menggunakan nama yang lebih deskriptif dalam kasus itu, tetapi tidak ada alternatif yang masuk akal untuk mode "multiline".Di Perl, di mana semua kegilaan ini dimulai, mereka mengakui kesalahan mereka dan menyingkirkan mode "multiline" dan "single-line" di Perl 6 regex. Dalam dua puluh tahun lagi, mungkin seluruh dunia akan mengikutinya.
sumber
str.matches(regex)
berperilaku sepertiPattern.matches(regex, str)
yang mencoba untuk mencocokkan seluruh urutan input terhadap pola dan kembaliSedangkan
matcher.find()
upaya untuk menemukan urutan berikutnya dari urutan input yang cocok dengan pola dan kembaliJadi masalahnya adalah dengan regex. Coba yang berikut ini.
Jadi singkatnya,
(\\W)*(\\S)*
bagian dalam regex pertama Anda cocok dengan string kosong yang*
berarti nol atau lebih kejadian dan string yang cocok sebenarnya adalahUser Comments:
dan bukan seluruh string seperti yang Anda harapkan. Yang kedua gagal karena mencoba untuk mencocokkan seluruh string tetapi tidak bisa\\W
cocok dengan karakter non-kata, yaitu[^a-zA-Z0-9_]
dan karakter pertama adalahT
, karakter kata.sumber
User Comments: [\\s\\S]*
dan ini berhasil. (terima kasih!) Dari jawaban @Tim saya mendapatkan polanyaUser Comments:(.*)
, ini juga ok Sekarang, apakah ada cara yang disarankan atau lebih baik di antara ini, atau hanya dua cara melakukan hal yang sama?(.*)
bersama denganDOTALL
bendera lebih jelas / mudah dibaca daripada([\\s\\S]*)
Bendera multiline memberi tahu regex untuk mencocokkan pola ke setiap baris sebagai lawan dari seluruh string untuk tujuan Anda, kartu liar sudah cukup.
sumber