Регулярное выражение: разница между отрицательным просмотром назад и отрицанием

Из regular-expressions.info:

\b\w+(?<!s)\b. Это определенно не то же самое, что \b\w+[^s]\b. При применении к Jon's первое будет соответствовать Jon, а второе Jon' (включая апостроф). Я оставлю это на ваше усмотрение, чтобы понять, почему. (Подсказка: \b соответствует апострофу и букве s). Последнее также не будет соответствовать однобуквенным словам, таким как «а» или «я».

Можете ли вы объяснить, почему?

Кроме того, можете ли вы пояснить, что именно делает \b и почему оно совпадает между апострофом и s ?


person Benjamin Crouzier    schedule 02.09.2011    source источник


Ответы (2)


\b – это утверждение нулевой ширины, означающее границу слова. Эти позиции символов (взятые из этой ссылки) считаются границами слов:

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

Символы слов, конечно, любые \w. s — это символ слова, а ' — нет. В приведенном выше примере область между ' и s является границей слова.

Строка "Jon's" выглядит так, если выделить якоря и границы (первая и последняя \b встречаются в тех же позициях, что и ^ и $): ^Jon\b'\bs$

Отрицательное утверждение просмотра назад (?<!s)\b означает, что оно будет соответствовать границе слова только в том случае, если ей не предшествует буква s (т. е. символ последнего слова не является s). Таким образом, он ищет границу слова при определенных условиях.

Поэтому первое регулярное выражение работает так:

  1. \b\w+ соответствует первым трем буквам J o n.

  2. На самом деле между n и ' есть еще одна граница слова, как показано выше, поэтому (?<!s)\b соответствует этой границе слова, поскольку ему предшествует n, а не s.

  3. Поскольку достигнут конец шаблона, результирующее совпадение равно Jon.

Дополнительный класс символов [^s]\b означает, что он будет соответствовать любому символу, кроме буквы s, за которой следует граница слова. В отличие от приведенного выше, здесь ищется один символ, за которым следует граница слова.

Поэтому второе регулярное выражение работает так:

  1. \b\w+ соответствует первым трем буквам J o n.

  2. Поскольку ' не является буквой s (она соответствует классу символов [^s]) и за ней следует граница слова (между ' и s), она соответствует.

  3. Поскольку достигнут конец шаблона, результирующее совпадение равно Jon'. Буква s не соответствует, потому что граница слова перед ней уже совпала.

person BoltClock    schedule 02.09.2011
comment
+1, но одно замечание: ^ и $ являются особыми видами \b, неверно. \b просто совпадает с теми же позициями, что и якоря в этом случае. Если вы хотите указать места, где \b может совпадать, я думаю, что это работает лучше: \bJon\b'\bs\b. - person Alan Moore; 02.09.2011
comment
К сожалению, назад: я отредактировал свой комментарий, чтобы полностью удалить якоря (но я не настаиваю на этом ☺). - person Alan Moore; 02.09.2011
comment
@Алан Мур, ^, $ и \b считаются якорями. $ также может совпадать в нескольких местах в большинстве строк (до и после завершающего символа новой строки), даже без /m. Под /m ^ и $ могут совпадать в нескольких местах. Я считаю, что группировка \b с ^ и $ соответствует ментальной модели людей и не совсем неверна. - person ikegami; 02.09.2011
comment
@ikegami: Строго говоря, привязка является синонимом утверждения нулевой ширины, но обычно используется для обозначения подмножества ZWA, связанного с границами строк (^, $, \A , \Z, \z), и именно так я его использовал. Я также не возражаю против того, чтобы называть \b привязкой, но BC, похоже, подразумевает отношения, которых не существует (^ и $ как границы слов в особом регистре), и я хотел прояснить это. - person Alan Moore; 03.09.2011

Пример пытается продемонстрировать, что просмотр вперед и просмотр назад можно использовать для создания условий «и».


\b\w+(?<!s)\b

также может быть записано как

\b\w*\w(?<!s)\b

Это дает нам

\b\w*[^s]\b    vs    \b\w*\w(?<!s)\b

Я сделал это, чтобы мы могли игнорировать несущественное. (В этом примере \b просто отвлекают внимание.) У нас есть

[^s]    vs    \w(?<!s)

Слева мы можем сопоставить любой символ, кроме "s".

Справа мы можем сопоставить любой символ слова, кроме "s".

Кстати,

\w(?<!s)

также может быть написано

(?!s)\w      # Not followed by "s" and followed by \w
person ikegami    schedule 02.09.2011
comment
+1. Весь этот абзац в исходной статье представляет собой беспорядочную кашу, намного ниже обычного стандарта Яна. Этот момент должен был быть представлен в отдельном разделе (вместе с обсуждением q[^u] и q(?!u) на странице классов персонажей), где его можно было бы более подробно рассмотреть на лучше выбранном примере. - person Alan Moore; 02.09.2011