Aku berlari ke masalah lebih buruk ketika mencari teks untuk kata-kata seperti .NET
, C++
, C#
, dan C
. Anda akan berpikir bahwa pemrogram komputer akan tahu lebih baik daripada memberi nama bahasa sesuatu yang sulit untuk menulis ekspresi reguler.
Bagaimanapun, ini adalah apa yang saya temukan (dirangkum sebagian besar dari http://www . regular-expressions.info , yang merupakan situs yang hebat): Dalam kebanyakan rasa regex, karakter yang cocok dengan kelas karakter tangan pendek \w
adalah karakter yang diperlakukan sebagai karakter kata dengan batas kata. Java adalah pengecualian. Java mendukung Unicode untuk \b
tetapi tidak untuk \w
. (Saya yakin ada alasan bagus untuk itu pada saat itu).
The \w
singkatan dari "karakter kata". Itu selalu cocok dengan karakter ASCII [A-Za-z0-9_]
. Perhatikan dimasukkannya garis bawah dan digit (tetapi tidak putus-putus!). Dalam sebagian besar rasa yang mendukung Unicode, \w
sertakan banyak karakter dari skrip lain. Ada banyak ketidakkonsistenan tentang karakter mana yang sebenarnya dimasukkan. Huruf dan angka dari skrip alfabet dan ideograf umumnya disertakan. Tanda baca konektor selain simbol garis bawah dan angka yang bukan digit mungkin atau mungkin tidak disertakan. Skema XML dan XPath bahkan menyertakan semua simbol di \w
. Tetapi Java, JavaScript, dan PCRE hanya cocok dengan karakter ASCII \w
.
Itulah sebabnya pencarian regex berbasis Java untuk C++
, C#
atau .NET
(bahkan ketika Anda ingat untuk keluar dari periode dan plus) dikacaukan oleh \b
.
Catatan: Saya tidak yakin apa yang harus dilakukan tentang kesalahan dalam teks, seperti ketika seseorang tidak memberi spasi setelah periode di akhir kalimat. Saya mengizinkannya, tetapi saya tidak yakin itu hal yang tepat untuk dilakukan.
Bagaimanapun, di Jawa, jika Anda mencari teks untuk bahasa-bahasa aneh, Anda harus mengganti \b
dengan sebelum dan sesudah spasi putih dan tanda baca. Sebagai contoh:
public static String grep(String regexp, String multiLineStringToSearch) {
String result = "";
String[] lines = multiLineStringToSearch.split("\\n");
Pattern pattern = Pattern.compile(regexp);
for (String line : lines) {
Matcher matcher = pattern.matcher(line);
if (matcher.find()) {
result = result + "\n" + line;
}
}
return result.trim();
}
Kemudian dalam tes atau fungsi utama Anda:
String beforeWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|^)";
String afterWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|$)";
text = "Programming in C, (C++) C#, Java, and .NET.";
System.out.println("text="+text);
// Here is where Java word boundaries do not work correctly on "cutesy" computer language names.
System.out.println("Bad word boundary can't find because of Java: grep with word boundary for .NET="+ grep("\\b\\.NET\\b", text));
System.out.println("Should find: grep exactly for .NET="+ grep(beforeWord+"\\.NET"+afterWord, text));
System.out.println("Bad word boundary can't find because of Java: grep with word boundary for C#="+ grep("\\bC#\\b", text));
System.out.println("Should find: grep exactly for C#="+ grep("C#"+afterWord, text));
System.out.println("Bad word boundary can't find because of Java:grep with word boundary for C++="+ grep("\\bC\\+\\+\\b", text));
System.out.println("Should find: grep exactly for C++="+ grep(beforeWord+"C\\+\\+"+afterWord, text));
System.out.println("Should find: grep with word boundary for Java="+ grep("\\bJava\\b", text));
System.out.println("Should find: grep for case-insensitive java="+ grep("?i)\\bjava\\b", text));
System.out.println("Should find: grep with word boundary for C="+ grep("\\bC\\b", text)); // Works Ok for this example, but see below
// Because of the stupid too-short cutsey name, searches find stuff it shouldn't.
text = "Worked on C&O (Chesapeake and Ohio) Canal when I was younger; more recently developed in Lisp.";
System.out.println("text="+text);
System.out.println("Bad word boundary because of C name: grep with word boundary for C="+ grep("\\bC\\b", text));
System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
// Make sure the first and last cases work OK.
text = "C is a language that should have been named differently.";
System.out.println("text="+text);
System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
text = "One language that should have been named differently is C";
System.out.println("text="+text);
System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
//Make sure we don't get false positives
text = "The letter 'c' can be hard as in Cat, or soft as in Cindy. Computer languages should not require disambiguation (e.g. Ruby, Python vs. Fortran, Hadoop)";
System.out.println("text="+text);
System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
PS Terima kasih saya kepada http://regexpal.com/ tanpa siapa dunia regex akan sangat menyedihkan!