Я зіткнувся з ще гіршою проблемою при пошуку тексту для слів , як .NET
, C++
, C#
, і C
. Ви б могли подумати, що комп'ютерні програмісти знають краще, ніж називати мовою те, для чого важко писати регулярні вирази.
У всякому разі, це я дізнався (узагальнений здебільшого з http://www.regular-expressions.info , який є чудовим сайтом): У більшості ароматів регулярного вираження символи, які відповідають класу символів короткої руки, \w
є символи, які розглядаються як символи слова за межами слова. Java - виняток. Java підтримує Unicode для, \b
але не для\w
. (Я впевнений, що для цього була вагома причина).
\w
Чи означає «слово» характер. Він завжди відповідає символам ASCII [A-Za-z0-9_]
. Зверніть увагу на включення підкреслення та цифр (але не тире!). У більшості ароматів, які підтримують Unicode, \w
входить багато символів з інших сценаріїв. Існує багато непослідовностей щодо того, які персонажі включаються насправді. Як правило, букви та цифри з алфавітних сценаріїв та ідеографів включаються. Знаки пунктуації, крім знаків підкреслення та числових символів, які не є цифрами, можуть бути включені. XML Schema і XPath навіть включають усі символи в \w
. Але Java, JavaScript та PCRE відповідають лише символам ASCII \w
.
Ось чому на основі Java шукає регулярний вираз C++
, C#
або .NET
(навіть коли ви пам’ятаєте про те, щоб уникнути періоду та плюсів) накручується \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));
PS Моя подяка http://regexpal.com/, без якої світ регулярних виразів був би дуже жалюгідним!