Ich lief in einem noch schlimmeren Problem , wenn der Text der Suche nach Wörtern wie .NET
, C++
, C#
, und C
. Sie würden denken, dass Computerprogrammierer es besser wissen würden, als eine Sprache zu benennen, für die es schwierig ist, reguläre Ausdrücke zu schreiben.
Wie auch immer, das habe ich herausgefunden (hauptsächlich zusammengefasst unter http://www.regular-expressions.info , was eine großartige Seite ist): In den meisten Arten von Regex sind Zeichen, die mit der Kurzzeichen-Zeichenklasse übereinstimmen, \w
die Zeichen, die durch Wortgrenzen als Wortzeichen behandelt werden. Java ist eine Ausnahme. Java unterstützt Unicode für, \b
aber nicht für \w
. (Ich bin sicher, es gab damals einen guten Grund dafür).
Das \w
steht für "Wortzeichen". Es stimmt immer mit den ASCII-Zeichen überein [A-Za-z0-9_]
. Beachten Sie die Aufnahme des Unterstrichs und der Ziffern (aber nicht des Bindestrichs!). In den meisten Varianten, die Unicode unterstützen, \w
sind viele Zeichen aus anderen Skripten enthalten. Es gibt viele Inkonsistenzen darüber, welche Zeichen tatsächlich enthalten sind. Buchstaben und Ziffern aus alphabetischen Schriften und Ideogrammen sind in der Regel enthalten. Andere Interpunktionszeichen als der Unterstrich und die numerischen Symbole, die keine Ziffern sind, können enthalten sein oder auch nicht. XML Schema und XPath enthalten sogar alle Symbole in \w
. Java, JavaScript und PCRE stimmen jedoch nur mit ASCII-Zeichen überein \w
.
Aus diesem Grund wird die Java-basierte Regex-Suche nach C++
( C#
oder .NET
auch wenn Sie daran denken, dem Punkt und den Pluspunkten zu entkommen) von der verschraubt\b
.
Hinweis: Ich bin mir nicht sicher, was ich gegen Fehler im Text tun soll, z. B. wenn jemand nach einem Punkt am Ende eines Satzes kein Leerzeichen setzt. Ich habe es zugelassen, bin mir aber nicht sicher, ob es unbedingt das Richtige ist.
Wenn Sie in Java nach Text für diese seltsam benannten Sprachen suchen, müssen Sie die \b
Bezeichner vor und nach Leerzeichen und Satzzeichen ersetzen . Beispielsweise:
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();
}
Dann in Ihrem Test oder Ihrer Hauptfunktion:
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 Mein Dank geht an http://regexpal.com/, ohne den die Regex-Welt sehr elend wäre!