Що таке границя слів у регулярному виразі?


137

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

Чи можете ви розмістити невеликий приклад із вхідним та очікуваним результатом?
Код Брент пише

Example Pattern pattern = Pattern.compile ("\\ s * \\ b \\ -? \\ d + \\ s *"); Рядок плюс = "12"; System.out.println ("" + pattern.matcher (плюс) .matches ()); Рядок мінус = "-12"; System.out.println ("" + pattern.matcher (мінус) .matches ()); pattern = Pattern.compile ("\\ s * \\ -? \\ d + \\ s *"); System.out.println ("" + pattern.matcher (мінус) .matches ()); дає: true false true
peter.murray.rust

Відповіді:


97

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

Отже, у рядку "-12"вона збігатиметься до цифр 1 або після 2. Тире не є символом слова.


35
Correctamundo. \b- твердження нульової ширини, яке відповідає, якщо є \wна одній стороні, або є \Wз іншого, або позиція є початком або кінцем рядка. \wдовільно визначається як "ідентифікатор" символів (alnums та підкреслення), а не як щось особливо корисне для англійської мови.
варення

100% правильно. Вибачте за те, що ви не просто коментували своє. Я натиснув заяву, перш ніж побачив вашу відповідь.
Brent Writes Code

5
заради розуміння, можна переписати регулярний вираз \bhello\bбез використання \b(використовуючи \w, \Wі інші)?
Девід Портабелла

5
Сорт: (^|\W)hello($|\W)за винятком того, що він не захоплював би жодних символів, що не містять слова, до та після, так це було б більше схожим (^|(?<=\W))hello($|(?=\W))(за допомогою тверджень lookahead / lookbehind).
бріанарія

6
@brianary Трохи простіше: (?<!\w)hello(?!\w).
Девід Найпе

28

Межа слів може відбуватися в одному з трьох позицій:

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

Символи слова буквено-цифрові; знак мінус - ні. Взято з підручника Regex .


21

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

Мій погляд - просто орієнтований на величезне розуміння. Логіку, що стоїть за нею, слід вивчити з інших відповідей.

введіть тут опис зображення


3
Дуже хороший сайт, щоб зрозуміти, що таке межі слів і як відбуваються відповідники
vsingh

2
Ця публікація заслуговує на заслугу за показ, а не розповідь. Картина вартує тисячі слів.
M_M

13

Межа слів - це положення, яке передує символу слова, а за ним не слідує, або супроводжується символом слова, а не передує його.


8

Я говорю про те, що \bнасправді тут є межі виразного стилю .

Коротка історія полягає в тому, що вони умовні . Їх поведінка залежить від того, що вони поруч.

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

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

Іноді це не те, чого ти хочеш. Дивіться мою іншу відповідь для розробки.


7

Я хотів би пояснити , Алан Мур відповідь «пд.ш.

Межа слів - це положення, яке передує символу слова, а за ним не супроводжується символом слова, а за ним не передує.

Припустимо, у мене є рядок "Це a c a t, а вона - дивовижна", і я повинен замінити всі випадки (й) буквою "a", лише якщо ця літера існує на "Межі слова" , тобто літера aвсередині "кота" не повинна бути замінена.

Тому я виконаю регулярний вираз (в Python ) як

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

тому вихід буде це eз в т - eе вона ewesome


5

Я зіткнувся з ще гіршою проблемою при пошуку тексту для слів , як .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/, без якої світ регулярних виразів був би дуже жалюгідним!


Я намагався зрозуміти, чому я не міг відповідати, C#але тепер ясніше
Mugoma J. Okomba

4

Ознайомтеся з документацією щодо граничних умов:

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


2

Межа слів \ b використовується там, де одне слово має бути символом слова, а інше - несловним символом. Регулярне вираження для від'ємного числа повинно бути

--?\b\d+\b

перевірити працюючу DEMO


1

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

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

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

Це буде відповідати будь-яким числам, починаючи з символу пробілу та необов'язкового тире, і закінчуючи межею слова. Він також буде відповідати номеру, що починається на початку рядка.


0

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


1
Ви думаєте про \G: відповідає початку рядка (як \A) у першій спробі збігу; після цього він відповідає тій позиції, де закінчився попередній матч.
Алан Мур

0

коли ви використовуєте \\b(\\w+)+\\bце означає точну відповідність слову, що містить лише символи слова([a-zA-Z0-9])

у вашому випадку, наприклад, налаштування \\b на початку regex прийме -12(з пробілом), але знову не прийме -12(без пробілу)

для довідки на підтримку моїх слів: https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.