Что такое граница слова в регулярных выражениях? - PullRequest
95 голосов
/ 25 августа 2009

Я использую регулярные выражения Java в Java 1.6 (среди прочего, для разбора числового вывода) и не могу найти точное определение \b («граница слова»). Я предполагал, что -12 будет «целочисленным словом» (соответствует \b\-?\d+\b), но, похоже, это не работает. Буду признателен за информацию о способах сопоставления разделенных пробелами чисел.

Пример:

Pattern pattern = Pattern.compile("\\s*\\b\\-?\\d+\\s*");
String plus = " 12 ";
System.out.println(""+pattern.matcher(plus).matches());
String minus = " -12 ";
System.out.println(""+pattern.matcher(minus).matches());
pattern = Pattern.compile("\\s*\\-?\\d+\\s*");
System.out.println(""+pattern.matcher(minus).matches());

Возвращает:

true
false
true

Ответы [ 12 ]

75 голосов
/ 25 августа 2009

Граница слова, в большинстве диалектов регулярных выражений, - это позиция между \w и \W (не-слово char), или в начале или конце строки, если она начинается или заканчивается (соответственно) словом символ ([0-9A-Za-z_]).

Итак, в строке "-12" она будет соответствовать до 1 или после 2. Тире не является символом слова.

22 голосов
/ 25 августа 2009

Граница слова может встречаться в одной из трех позиций:

  1. Перед первым символом в строке, если первый символ является символом слова.
  2. После последнего символа в строке, если последний символ является символом слова.
  3. Между двумя символами в строке, где один является символом слова, а другой - не символом слова.

Символы слова являются буквенно-цифровыми; знак минус нет. Взято из Regex Tutorial .

11 голосов
/ 25 августа 2009

Граница слова - это позиция, которой предшествует либо символ слова, за которым не следует один, либо за ним следует символ слова, а перед ним не следует.

6 голосов
/ 18 ноября 2010

Я говорю о том, что границы регулярного выражения \b в действительности здесь .

Короче говоря, они условны . Их поведение зависит от того, с кем они рядом.

# same as using a \b before:
(?(?=\w) (?<!\w)  | (?<!\W) )

# same as using a \b after:
(?(?<=\w) (?!\w)  | (?!\W)  )

Иногда это не то, что вы хотите. Смотрите мой другой ответ для уточнения.

4 голосов
/ 16 декабря 2013

Я столкнулся с еще более серьезной проблемой при поиске в тексте таких слов, как .NET, C++, C# и C. Можно подумать, что программисты будут знать лучше, чем называть язык чем-то, для чего трудно писать регулярные выражения.

Во всяком случае, это то, что я обнаружил (обобщенный в основном из http://www.regular -expressions.info , который является отличным сайтом): в большинстве разновидностей регулярных выражений символы, которые соответствуют коротким класс символов руки \w - это символы, которые обрабатываются как символы слова по границам слова. Ява является исключением. Java поддерживает Unicode для \b, но не для \w. (Я уверен, что в то время для этого была веская причина).

\w означает «символ слова». Он всегда соответствует символам ASCII [A-Za-z0-9_]. Обратите внимание на включение подчеркивания и цифр (но не тире!). В большинстве разновидностей, которые поддерживают Unicode, \w включает много символов из других сценариев. Существует много несоответствий относительно того, какие символы на самом деле включены. Буквы и цифры из букв алфавита и иероглифов, как правило, включены. Знаки препинания, отличные от символов подчеркивания и цифр, которые не являются цифрами, могут быть включены или не включены. XML-схема и 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));

P.S. Благодарю http://regexpal.com/, без которого мир регулярных выражений будет очень несчастным!

4 голосов
/ 25 августа 2009

Ознакомьтесь с документацией по граничным условиям:

http://java.sun.com/docs/books/tutorial/essential/regex/bounds.html

Проверьте этот образец:

public static void main(final String[] args)
    {
        String x = "I found the value -12 in my string.";
        System.err.println(Arrays.toString(x.split("\\b-?\\d+\\b")));
    }

Когда вы распечатываете, обратите внимание, что вывод такой:

[Я нашел значение - в моей строке.]

Это означает, что символ "-" не воспринимается как находящийся на границе слова, поскольку он не считается символом слова. Похоже, @brianary своего рода избил меня до удара, так что он получил голос.

3 голосов
/ 11 февраля 2019

Я хотел бы объяснить Алан Мур ответ

Граница слова - это позиция, которой предшествует либо символ слова, за которым не следует ни один, либо за ним следует символ слова, а перед ним не следует.

Предположим, у меня есть строка "Это a c a t, а она a wesome", и я должен заменить все вхождения буква «а» только в том случае, если эта буква существует в «Границе слова» , т. е. буква a внутри «кошки» не должна заменяться.

Так что я буду выполнять регулярное выражение (в Python ) как

re.sub("\ba","e", myString.strip()) // заменить a на e

поэтому вывод будет Это е кошка е и она е офигенно

3 голосов
/ 01 июня 2018

В процессе изучения регулярных выражений я действительно застрял в метасимволе \b. Я действительно не понимал его значения, когда я спрашивал себя ", что это такое, что это такое ". После нескольких попыток использования веб-сайта я наблюдаю розовые вертикальные черточки в каждом начале слова и в конце слова. Я понял его значение в то время. Теперь это точно слово (\w) - граница .

Я считаю, что они исключительно ориентированы на понимание. Логика этого должна быть рассмотрена из других ответов.

enter image description here

1 голос
/ 08 ноября 2018

Граница слова \ b используется, когда одно слово должно быть символом слова, а другое - не словом. Регулярное выражение для отрицательного числа должно быть

--?\b\d+\b

проверка работоспособности ДЕМО

1 голос
/ 25 августа 2009

Я считаю, что ваша проблема связана с тем, что - не является символом слова. Таким образом, граница слова будет соответствовать после -, и поэтому не будет захватывать его. Границы слова совпадают перед первым и последним символом слова в строке, а также в любом месте, где перед ним стоит символ слова или неслова, а после - наоборот. Также обратите внимание, что граница слова - это совпадение с нулевой шириной.

Одна из возможных альтернатив -

(?:(?:^|\s)-?)\d+\b

Это будет соответствовать любым числам, начиная с пробела и необязательного тире, и заканчивая границей слова. Он также будет соответствовать числу, начинающемуся с начала строки.

...