Как искать и заменять (подставлять) с помощью ключей и значений хэша

Я думаю, что моя проблема очень похожа на эту: Как использовать переменную в замещающей части оператора подстановки Perl? Разница в том, что $find и $replace являются ключами и значениями хеша, который я использую.

while(($find,$replace) = each %hash){
$string_to_check =~ s/$find/$replace/e;
}

Вот пример для одной пары ключ-значение в моем хэше

ключ: ^/abc(/.*)?$

стоимость: www.abc.website.com$1

Здесь я получаю замену, но $1 не будет заменен содержимым (/.*)

С s///ee вместо s///e я получаю:

Bareword found where operator expected at (eval 1) line 1, near "//xyz"
(Missing operator before xyz?)
Use of uninitialized value in substitution iterator at ./script line 46, <FH1> line 3470.

... и поэтому совпадающие части заменяются пустой строкой.

Я предполагаю, что

while(($find,$replace) = each %hash)

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

$replace='"foo $foo bar"';

Это правильно?

Извините за мой английский и спасибо за вашу помощь заранее. (Я новичок в Perl и программировании в целом.)


person user982809    schedule 06.10.2011    source источник


Ответы (2)


Чтобы оценить $1, хранящийся в $replace, вам нужно будет использовать eval. Обратите внимание, что eval может представлять угрозу безопасности, поэтому убедитесь, что вы контролируете содержимое %hash.

while (my ($find, $replace) = each %hash) {
    eval "\$string_to_check =~ s{$find}{$replace}";
}
person AFresh1    schedule 06.10.2011
comment
Вот и все! Спасибо за ответ. Теперь мне нужно выяснить, почему это работает — я не знал об «eval». - person user982809; 07.10.2011
comment
Еще раз спасибо! Я видел eval в другом потоке (с похожей проблемой), но я думал, что это то же самое, что и s///e. Но это имеет значение. Спасибо! Через 2 дня поисков я нашел его ;) - person user982809; 07.10.2011
comment
Я недавно узнал, что вполне может быть более безопасный способ, чем eval. String::Interpolate::< href="http://search.cpan.org/~djerius/String-Interpolate-RE-0.03/lib/String/Interpolate/RE.pm" rel="nofollow noreferrer">RE, который у меня есть еще не пользовался, но звучит прикольно. - person AFresh1; 07.10.2011

Вместо $1 в вашей замене используйте \1. Это обратная ссылка на первую совпавшую группу. Я думаю, что в этом случае вы также можете полностью отказаться от /e.

person Cfreak    schedule 06.10.2011
comment
Спасибо за ваш ответ. Я изменил его на \1, но он также не заменит его содержимым (/.*) - так что теперь я получаю abc.website.com\1 - person user982809; 06.10.2011