Почему мое регулярное выражение также захватывает EOLN? - PullRequest
1 голос
/ 11 марта 2020

Я пытаюсь написать командный файл для автоматизации массового редактирования некоторых Pascal источников. У меня есть исходные файлы со случайной строкой, подобной этой:

     //{## identifier} Inc (Index) ; { a comment }    // another comment

, и я хочу изменить их все на:

     {$ifdef identifier} Inc (Index) ; { a comment }    // another comment {$endif}

Ниже приведен тестовый пакетный файл, который я использую.

:: File TestRXRepl.bat
:: ===================     

@echo     //{##   identifier} Inc (Index) ; { a comment }    // another comment >t.pas
@set "FindRegExp=(\ *)\/\/\{\#\#\ *([a-z,0-9,_]+)\}(\ *)(.*)"
@set "ReplRegExp=\1{$ifdef \2}\3\4 {$endif}"

rxrepl --file t.pas --output t.out --search "%FindRegExp%" --replace "%ReplRegExp%"
@type t.pas
@type t.out

Предполагается, что регулярное выражение:

  • захватывает начальный отступ (группа 1)
  • match //{##
  • пропуск любого пробелы
  • захват идентификатора (группа 2)
  • match }
  • захват отступа исходного кода (группа 3)
  • захват строки исходного текста из затем до конца строки (группа 4)

Все работает, кроме обработки конца строки. Группа 4 должна захватывать все от начала строки источника до конца строки, но, похоже, включает конец строки, в результате чего {endif} записывается в следующую строку , т.е. я получаю:

{$ifdef identifier} Inc (Index) ; { a comment }    // another comment
{$endif}

вместо:

{$ifdef identifier} Inc (Index) ; { a comment }    // another comment {$endif}

Я использую инструмент RXRepl . У него есть опция --eol, которая звучит так, как будто она может быть полезной, но я не могу изменить поведение при ее использовании.

(Примечания)

  • Я знаю, что оба результата синтаксически правильный, но это не главное ;-)
  • Группы 3 и 4 можно объединить.
  • он не обрабатывает другие пробельные символы.
  • Я знаю, что существуют более классные способы сопоставления идентификатора.

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

1 Ответ

1 голос
/ 11 марта 2020

Кажется, проблема в том, что ваш . соответствует символу новой строки, что означает, что действует опция PCRE2_DOTALL. (Я не знаю, почему это так, возможно, rxrepl всегда устанавливает эту опцию по умолчанию.)

Один из возможных способов обойти это - завершить группу 4 в совпадении регулярного выражения с помощью (.*\S), используя \S тип символа , который будет соответствовать любому символу, не являющемуся пробелом, и исключит символы новой строки.

Но, вероятно, лучший способ исправить это, используя последовательность \N , которая описана в руководстве как:

Экранирующая последовательность \N имеет то же значение, что и ". "метасимвол, когда PCRE2_DOTALL не установлен, но установка PCRE2_DOTALL не меняет значения \N.

Так что просто использование (\N*) для группы 4 в вашем матче будет соответствовать всему, что в настоящее время соответствует, за исключением завершающего символа новой строки.

В вашем скрипте просто обновите эту строку:

@set "FindRegExp=(\ *)\/\/\{\#\#\ *([a-z,0-9,_]+)\}(\ *)(\N*)"
...