Причина, по которой ваш код не работает, заключается в том, что /g
не выполняет повторное сканирование строки после подстановки.Он находит все неперекрывающиеся совпадения данного регулярного выражения и затем заменяет замещающую часть в.
В [abc@def"ghi"jkl'123]
существует только одно совпадение (которое является частью [abc@def"
строки, с $1 = '[abc@def'
и $2 = ''
), поэтому удаляется только первый "
.
После первого совпадения Perl сканирует оставшуюся строку (ghi"jkl'123]
) для другого совпадения, но не находит другого[
(или @
).
Я думаю, что наиболее простым решением является использование вложенной операции поиска / замены.Внешнее совпадение идентифицирует строку, в которой производится замена, а внутреннее сопоставление выполняет фактическую замену.
В коде:
s{ \[ [^\[\]\@]* \@ \K ([^\[\]]*) (?= \] ) }{ $1 =~ tr/a-zA-Z0-9//cdr }xe;
Или для замены каждого совпадения на X
:
s{ \[ [^\[\]\@]* \@ \K ([^\[\]]*) (?= \] ) }{ $1 =~ tr/a-zA-Z0-9/X/cr }xe;
Мы сопоставляем префикс [
, за которым следуют 0 или более символов, которые не являются [
или ]
или @
, за которыми следует @
.
\K
используется для обозначения виртуального начала совпадения (т. Е. Все сопоставленное до сих пор не включено в сопоставляемую строку, что упрощает подстановку).
Мы сопоставляем и фиксируем 0 или более символов, которые не [
или ]
.
Наконец, мы сопоставляем суффикс ]
в прогнозе (так что он также не является частью совпадающей строки).
Замена выполняетсякак кусок кода, а не строка (как указано флагом /e
).Здесь мы могли бы использовать $1 =~ s/[^a-zA-Z0-9]//gr
или $1 =~ s/[^a-zA-Z0-9]/X/gr
, соответственно, но поскольку каждое внутреннее совпадение является просто одним символом, также можно использовать транслитерацию.
Мы возвращаем измененную строку (как указано в/r
) и использовать его в качестве замены во внешней операции s
.