ฉันวิ่งเข้าไปในปัญหายิ่งเลวร้ายลงเมื่อค้นหาข้อความสำหรับคำพูดชอบ.NET
, C++
, และC#
C
คุณคิดว่าโปรแกรมเมอร์คอมพิวเตอร์จะรู้ดีกว่าการตั้งชื่อภาษาที่ยากต่อการเขียนนิพจน์ทั่วไป
อย่างไรก็ตามนี่คือสิ่งที่ฉันค้นพบ (สรุปส่วนใหญ่มาจากhttp://www.regular-expressions.infoซึ่งเป็นเว็บไซต์ที่ยอดเยี่ยม): ใน regex ส่วนใหญ่อักขระที่จับคู่โดยคลาสอักขระมือสั้น\w
คือ อักขระที่ถือว่าเป็นอักขระคำตามขอบเขตของคำ Java เป็นข้อยกเว้น Java รองรับ Unicode สำหรับ\b
แต่ไม่ใช่สำหรับ\w
. (ฉันแน่ใจว่ามีเหตุผลที่ดีในตอนนั้น)
\w
ย่อมาจากคำว่า "ตัวอักษร" มันจะตรงกับอักขระ ASCII [A-Za-z0-9_]
เสมอ สังเกตการรวมขีดล่างและตัวเลข (แต่ไม่ใช่เส้นประ!) ในรสชาติส่วนใหญ่ที่รองรับ Unicode จะ\w
มีอักขระจำนวนมากจากสคริปต์อื่น ๆ มีความไม่สอดคล้องกันมากเกี่ยวกับตัวละครที่รวมอยู่ โดยทั่วไปจะรวมตัวอักษรและตัวเลขจากสคริปต์ตัวอักษรและอุดมคติไว้ด้วย เครื่องหมายวรรคตอนของตัวเชื่อมต่อนอกเหนือจากเครื่องหมายขีดล่างและสัญลักษณ์ตัวเลขที่ไม่ใช่ตัวเลขอาจรวมหรือไม่มีก็ได้ XML Schema และ XPath ยังรวมสัญลักษณ์ทั้งหมดใน\w
. แต่ Java, JavaScript และ PCRE จับคู่เฉพาะอักขระ ASCII ที่มี\w
.
ซึ่งเป็นเหตุผลที่ Java-based ค้นหา regex สำหรับC++
, C#
หรือ.NET
(แม้ในขณะที่คุณจำที่จะหลบหนีและระยะเวลา pluses) \b
จะเมาโดย
หมายเหตุ: ฉันไม่แน่ใจว่าจะต้องทำอย่างไรเกี่ยวกับความผิดพลาดในข้อความเช่นเมื่อมีคนไม่เว้นวรรคหลังช่วงเวลาท้ายประโยค ฉันอนุญาต แต่ฉันไม่แน่ใจว่ามันจำเป็นต้องทำ
อย่างไรก็ตามใน Java หากคุณกำลังค้นหาข้อความสำหรับภาษาชื่อแปลก ๆ เหล่านั้นคุณต้องแทนที่\b
ด้วยก่อนและหลังช่องว่างและตัวกำหนดเครื่องหมายวรรคตอน ตัวอย่างเช่น:
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();
}
จากนั้นในการทดสอบหรือฟังก์ชันหลักของคุณ:
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));
ป.ล. ขอขอบคุณที่http://regexpal.com/โดยที่โลกของ regex จะน่าสังเวชมาก