Как избежать знака доллара ($) в строке, используя регулярное выражение perl - PullRequest
16 голосов
/ 15 марта 2012

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

my %special_characters;
$special_characters{"_"} = "\\_";
$special_characters{"$"} = "\\$";
$special_characters{"{"} = "\\{";
$special_characters{"}"} = "\\}";
$special_characters{"#"} = "\\#";
$special_characters{"%"} = "\\%";
$special_characters{"&"} = "\\&";

my $string = '$foobar';
foreach my $char (keys %special_characters) {
  $string =~ s/$char/$special_characters{$char}/g;
}
print $string;

Ответы [ 3 ]

20 голосов
/ 15 марта 2012

Попробуйте это:

my %special_characters;
$special_characters{"_"} = "\\_";
$special_characters{"\\\$"} = "\\\$";
$special_characters{"{"} = "\\{";
$special_characters{"}"} = "\\}";
$special_characters{"#"} = "\\#";
$special_characters{"%"} = "\\%";
$special_characters{"&"} = "\\&";

выглядит странно, верно? Ваше регулярное выражение должно выглядеть следующим образом:

s/\$/\$/g

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

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

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

3 голосов
/ 15 марта 2012

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

s/($re)/"\\$1"/eg;

Чтобы создать регулярное выражение для всех символов, Regexp :: Assemble действительно хорошо.

use v5.10.1;
use Regexp::Assemble;

my $ra = Regexp::Assemble->new;

my @specials = qw(_ $ { } # % & );

foreach my $char ( @specials ) {
    $ra->add( "\\Q$char\\E" );
    }

my $re = $ra->re;
say "Regex is $re"; 

while( <DATA> ) {
    s/($re)/"\\$1"/eg;
    print;
    }

__DATA__
There are $100 dollars
Part #1234
Outside { inside } Outside

Обратите внимание, как в первой строке ввода Regexp :: Assemble перестроил мой шаблон.Это не просто склеенные биты частей, которые я добавил:

Regex is (?^:(?:[#$%&_]|\{|\}))
There are \$100 dollars
Part \#1234
Outside \{ inside \} Outside

Если вы хотите добавить больше символов, вы просто помещаете символ в @specials.Все остальное происходит за вас.

0 голосов
/ 15 марта 2012

$ имеет специальное значение в регулярном выражении, а именно «конец строки».Вам было бы лучше что-то вроде этого:

# escape special characters, join them into a single line
my $chars = join '', map { "\\$_" } keys %special_characters;
$string =~ s/([$chars])/$special_characters{$1}/g;

Кроме того, Perl не очень нравится "$", лучше использовать '$' (одинарные кавычки => без интерполяции)

ОБНОВЛЕНИЕ: Извините, я написал это в спешке => слишком много правок: (

...