Подтвердить что ты не робот

Как избежать специальных символов для замены в однострочном Perl?

Есть ли способ заменить строку, такую ​​как @ или * или ? или &, не нужно ставить перед ней "\"?

Пример:

perl -pe 'next if /^#/; s/\@d\&/new_value/ if /param5/' test

В этом примере мне нужно заменить @d& на new_value, но старое значение может содержать любой символ, как мне избежать только символов, которые нужно экранировать?

4b9b3361

Ответ 1

У вас есть несколько проблем:

  • Вы неправильно используете \b
  • Вы заменяете код переменными оболочки
  • Вам нужно указать метасимволы

От perldoc perlre

Граница слов ( "\ b" ) является пятном между двумя символами, имеющими "\ w" с одной стороны от него

Ни один из символов @ или & не является символами \w. Таким образом, ваш матч гарантированно провалится. Вы можете использовать что-то вроде s/(^|\s)\@d\&(\s|$)/${1}new text$2/

(^|\s) говорит, что он соответствует началу строки (^) или пробельному символу (\s).

(\s|$) говорит, что он соответствует концу строки ($) или пробельному символу (\s).

Чтобы решить вторую проблему, вы должны использовать %ENV.

Чтобы решить третью проблему, вы должны использовать escape-последовательности \Q и \E, чтобы избежать значения в $ENV{a}.

Объединяя все это, получим:

#!/bin/bash

export a='@d&'
export b='new text'

echo 'param5 @d&' | 
    perl -pe 'next if /^#/; s/(^|\s)\Q$ENV{a}\E(\s|$)/$1$ENV{b}$2/ if /param5/' 

Какая печать

param5 new text

Ответ 2

Как обсуждалось в perldoc perlre:

... Сегодня чаще используется функция quotemeta() или метакатегория "\ Q"        escape-последовательность, чтобы отключить все специальные значения метасимволов, например:

/$unquoted\Q$quoted\E$unquoted/

Остерегайтесь того, что если вы помещаете буквальные обратные косые черты (те, которые не входят в интерполированные переменные) между "\ Q" и "\ E", интерполяция с двойным цитированием обратной косой черты может        приводят к запутанным результатам. Если вам нужно использовать литеральные обратные косые черты в "\ Q...\E", обратитесь к "Gory детали разбора цитируемых конструкций" в perlop.

Вы также можете использовать ' как разделитель в операции s///, чтобы все было проанализировано буквально:

my $text = '@';
$text =~ s'@'1';
print $text;

В вашем примере вы можете сделать (отметить одиночные кавычки):

perl -pe 's/\b\[email protected]&\E\b/new_value/g if m/param5/ and not /^ *#/'

Ответ 3

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

s/\/foo\/bar\\/\/bar\/baz/

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

s{/foo/bar\\}{/bar/baz}

Здесь ваше регулярное выражение с расширенными разделителями.

s{\@d\&}{new_value}

Гораздо легче на глаз.

Ответ 4

Если вы действительно хотите избежать ввода \ s, поместите свою строку поиска в переменную, а затем используйте ее в своем регулярном выражении. В этом случае вам не нужны quotemeta или \Q ... \E. Например:

my $s = '@d&';
s/$s/new_value/g;

Если вы должны использовать это в однострочном лайнере, помните, что вам придется избегать $, если вы используете "s", чтобы содержать ваш perl-код, или выйдите из ', если вы используете ' для хранения вашего Perl-кода.

Ответ 5

Если у вас есть строка, как

my $var1 = abc$123

и вы хотите заменить его на abcd, тогда вы должны использовать \Q\E. Если вы этого не сделаете, то независимо от того, что Perl не заменяет строку.

Это единственное, что сработало для меня.

my $var2 = s/\Q$var1\E/abcd/g;