Регулярное выражение для пропуска символа в группе захвата - PullRequest
35 голосов
/ 10 ноября 2008

Можно ли пропустить пару символов в группе захвата в регулярных выражениях? Я использую регулярные выражения .NET, но это не должно иметь значения.

По сути, я ищу:

[произвольный текст] AB-123 [произвольный текст]

и мне нужно захватить 'AB123' без дефиса.

Я знаю, что AB - это 2 или 3 заглавных буквы, а 123 - это 2 или 3 цифры, но это не самая сложная часть. Трудная часть (по крайней мере для меня) - пропуск дефиса.

Полагаю, я мог бы захватить и то и другое по отдельности, а затем объединить их в коде, но мне бы хотелось иметь более элегантное решение только для регулярных выражений.

Есть предложения?

Ответы [ 5 ]

45 голосов
/ 10 ноября 2008

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

17 голосов
/ 10 ноября 2008

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

match = Regex.Match( text, "([A-B]{2,3})-([0-9]{2,3})" );
matchedText = string.Format( "{0}{1}", 
    match.Groups.Item(1).Value, 
    match.Groups.Item(2).Value );

Или путем удаления дефиса в шаге, отдельном от процесса сопоставления:

match = Regex.Match( text, "[A-B]{2,3}-[0-9]{2,3}" );
matchedText = match.Value.Replace( "-", "" );
4 голосов
/ 10 ноября 2008

Ваше утверждение, что без подгруппы + конкатенации невозможно обойтись, верно.

Вы также можете поступить как Джефф-Хиллман и просто убрать плохих персонажей после факта.

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

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

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

Альтернативная идея, если вам, возможно, понадобится вернуть несколько совпадений в теле кода, - это поиск регулярных выражений на основе «обратного вызова» ваших языков, который позволяет передавать любую найденную группу в вызов функции, который может сделать подстановка строк. (Особенно удобно при замене регулярных выражений).

Не уверен, как это будет работать в .Net, но в php вы бы сделали что-то вроде (не точный код)

  function strip_reverse( $a )
  {
     $a = preg_replace("/-/", "", $a );
     return reverse($a);
  }
  $b = preg_replace_callback( "/(AB[-]?cde)/" , 'strip_reverse' , "Hello World AB-cde" ; 
1 голос
/ 21 ноября 2015

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

((AB)-(123))

Первая группа захвата AB-123, вторая AB и третья 123. Тогда все, что вам нужно сделать, это присоединиться ко второй и третьей группе с пробелом.

0 голосов
/ 27 января 2018

Довольно поздно, но, думаю, я понял это. Хотя бы один способ сделать это.

Я использовал позитивный взгляд, чтобы остановиться на знаке # в моем тексте. Я не хотел пробела или знака #, поэтому мне пришлось искать выход, чтобы «пропустить» их. Поэтому, когда я был вынужден сопоставить их снова, я поместил их в группу мусора, которую я не планировал использовать (.ie, немного сегмента), которая в коде есть. Теперь мой указатель места - это одна позиция символа после знака # (где я хочу быть, пропуская пробел и знак #). И теперь я просто сопоставляю с концом имени файла в. и игнорируйте расширение файла.

(?i)English\\(?<Series>[^ ]+) - (?<Title>.+(?= #))(?<garb1>..)(?<Number>[^.]+)(?-i)

Имя файла, на котором это использовалось:

F:\Downloads\Downloads\500 Comics CCC CBR English\Isukani - Great Girl #01.cbr
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...