Что такое граница слова в регулярных выражениях?

Я использую регулярные выражения 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 ответов

Решение

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

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

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

Моя точка зрения просто ориентирована на понимание. Логика этого следует изучить из других ответов.

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

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

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

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

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

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

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

re.sub("\ba","e", myString.strip())

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

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

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

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

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

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

Я столкнулся с еще худшей проблемой при поиске текста для таких слов, как .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));

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

Ссылка: Освоение регулярных выражений (Джеффри Э. Ф. Фридл) - О'Рейли

\b эквивалентно (?<!\w)(?=\w)|(?<=\w)(?!\w)

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

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 своего рода избил меня до удара, так что он получил голос.

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

--?\b\d+\b

проверить работоспособность DEMO

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

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

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

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

Когда вы используете \\b(\\w+)+\\b это означает точное совпадение со словом, содержащим только символы слова ([a-zA-Z0-9])

в вашем случае например настройка \\b в начале регулярного выражения примет -12(с пробелом) но опять не примет -12(без пробела)

для справки, чтобы поддержать мои слова: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

Я думаю, что это граница (то есть следование за символом) последнего совпадения или начала или конца строки.

Другие вопросы по тегам