Позитивная разностная и не захватывающая разница между группами - PullRequest
0 голосов
/ 26 апреля 2018

Если вы хотите сопоставить любой из двух шаблонов, но не захватить его, вы должны использовать группу без захвата ?::

/(?:https?|ftp)://(.+)/

Но что, если я хочу захватить '_1' в строке 'john_1.Это может быть ' 2' или '', за которым следует что-нибудь еще.Сначала я попробовал группу без захвата:

'john_1'.gsub(/(?:.+)(_.+)/, "")
=> ""

Не работает.Я говорю не захватывать один или несколько символов, а захватывать _ и все символы после него.

Вместо этого работает следующее:

'john_1'.gsub(/(?=.+)(_.+)/, "")
=> "john"

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

q (? = U) соответствует aq, за которым следует au, не делая u частью совпадения.Позитивная прогнозная конструкция представляет собой пару круглых скобок, с открывающей скобкой, за которой следуют знак вопроса и знак равенства.

Но это определение на самом деле не подходит моему примеру.Что заставляет работать «Позитивный взгляд», а не группу «Без захвата» в приведенном мной примере?

Ответы [ 3 ]

0 голосов
/ 26 апреля 2018

Захват и сопоставление - это две разные вещи.(?:expr) не захватывает expr , но все равно включается в соответствующую строку.Утверждения нулевой ширины, например, (?=expr), не фиксируют или , включают expr в сопоставляемой строке.

Возможно, некоторые примеры помогут проиллюстрировать разницу:

> "abcdef"[/abc(def)/] # => abcdef
> $1 # => def

> "abcdef"[/abc(?:def)/] # => abcdef
> $1 # => nil

> "abcdef"[/abc(?=def)/] # => abc
> $1 # => nil

Когда вы используете группу без захвата в вашем вызове String#gsub, она все еще является частью совпадения и заменяется настрока замены.

0 голосов
/ 26 апреля 2018

Давайте рассмотрим пару ситуаций.

Строка, предшествующая подчеркиванию, должна быть "john", а за подчеркиванием следует один или несколько символов

str = "john_1"

У вас есть два варианта.

Используйте положительный взгляд сзади

str[/(?<=john)_.+/]
  #=> "_1"

Положительный взгляд сзади требует, чтобы "john" появлялся непосредственно перед подчеркиванием, но это не таквозвращаемая часть совпадения.

Использовать группу захвата:

str[/john(_.+)/, 1]
  #=> "_1"

Это регулярное выражение соответствует "john_1", но "_.+" захвачено в захватегруппа 1. Изучив документацию по методу String # [] , вы увидите, что одной из форм метода является str[regexp, capture], который возвращает содержимое группы захвата capture.Здесь capture равно 1, что означает первую группу захвата.

Обратите внимание, что строка, следующая за подчеркиванием, может содержать подчеркивания: "john_1_a"[/(?<=john)_.+/] #=> "_1_a".

Если подчеркивание может быть в концев приведенных выше регулярных выражениях строки + заменить на * (что означает совпадение с нулем или более символов после подчеркивания).

Строка, предшествующая подчеркиванию, может быть чем угодно, и подчеркиваниезатем один или несколько символов

str = "john_mary_tom_julie"

Мы можем рассмотреть два случая.

Возвращаемая строка должна начинаться с первого подчеркивания

В этом случае мы могли бы написать:

str[/_.+/]
  #=> "_mary_tom_julie"

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

Возвращаемая строка должна начинаться с последнего подчеркивания

Здесь мы могли бы написать:

str[/_[^_]+\z/]
  #=> "_julie"

Это регулярное выражение соответствует подчеркиванию, за которым следует один или несколько символов, которые не являютсянедеформированнойrscores, сопровождаемый якорем конца строки (\z).

В стороне: метод String#[]

[] может показаться странным именемдля метода, но, тем не менее, это метод, поэтому его можно вызывать обычным способом:

str.[](/john(_.+)/, 1)
  #=> "_1"

Выражение str[/john(_.+)/, 1] является примером (которых в Ruby много) синтаксический сахар .При написании str[...] Ruby преобразует его в обычное выражение для методов перед его оценкой.

0 голосов
/ 26 апреля 2018

Ваш первый пример не работает, потому что группа без захвата все еще является частью общего захвата, тогда как lookbehind используется только для сопоставления, но не является частью общего захвата.

Этолегче понять, если вы получите фактические данные о совпадении:

# Non-capturing group
/(?:.+)(_.+)/.match 'john_1'
=> #<MatchData "john_1" 1:"_1">

# Positive Lookbehind
/(?=.+)(_.+)/.match 'john_1'
=> #<MatchData "_1" 1:"_1">

РЕДАКТИРОВАТЬ: я должен также отметить, что sub и gsub работают на весь захват, а не отдельные группы захвата (хотя они могут использоватьсяв замену).

'john_1'.gsub(/(?:.+)(_.+)/, 'phil\1')
=> "phil_1"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...