Как я могу использовать 's ///', если моя строка содержит '/'? - PullRequest
5 голосов
/ 01 августа 2011

Я использую Perl 5.10.6 на Mac 10.6.6. Я хочу выполнить простой поиск и замену файла, поэтому я попытался:

my $searchAndReplaceCmd = "perl -pi -e 's/\\Q${localTestDir}\\E//g' ${testSuiteFile}";
system( $searchAndReplaceCmd );

но проблема выше в том, что переменная $localTestDir содержит разделители каталогов ("/"), и это приводит к неправильному использованию регулярного выражения ...

Не найдено слово, где ожидался оператор на линии -e 1, рядом "S / \ Q / дома / Селен"

Обратная косая черта найдена там, где ожидается оператор при -e строка 1 рядом с синтаксической ошибкой "Live \" в -e строка 1 рядом "S / \ Q / дома / Селен"

Шаблон поиска не заканчивается в строке -e 1.

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

Ответы [ 4 ]

6 голосов
/ 01 августа 2011

Кажется, что $localTestDir начинается с /.

Исправить, изменив разделитель регулярных выражений на что-то отличное от /:

my $searchAndReplaceCmd = "perl -pi -e 's!\\Q${localTestDir}\\E!!g' ${testSuiteFile}";

С perldoc perlrequick:

$x = "A 39% hit rate";
$x =~ s!(\d+)%!$1/100!e;       # $x contains "A 0.39 hit rate"

Последний пример показывает, что s/// может использовать другие разделители, такие как s!!! и s{}{} и даже s{}//. Если используются одинарные кавычки s''', то регулярное выражение и замена рассматриваются как строки в одинарных кавычках.

2 голосов
/ 01 августа 2011

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

\Q ... \E должен переопределять специальные символы в вашей строке, поэтому / "не должно быть" проблемой. От perlre :

\Q          quote (disable) pattern metacharacters till \E

Вот альтернативное (непроверенное) решение perl. Если вы хотите быть более уверенным, замените разделитель / на что-то другое, например s### (вы можете использовать любой символ в качестве разделителя).

use strict;
use warnings;
use File::Copy;

open my $fh, '<', $testSuiteFile or die $!;
open my $out, '>', $testSuiteFile . ".bak" or die $!;

while (<$fh>) {
    s/\Q${localTestDir}\E//g;
    print $out $_;
}

move($testSuiteFile . ".bak", $testSuiteFile) or die $!;

Или используйте Tie :: File

use strict;
use warnings;
use Tie::File;

tie, my @file, 'Tie::File', $testSuiteFile or die $!;

for (@file) {
        s/\Q${localTestDir}\E//g;
}
untie @file;
1 голос
/ 01 августа 2011

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

Так что s / \ / abc / \ / xyz / будет работать, хотя и не очень читабельно.

0 голосов
/ 02 августа 2011

Проблема в том, что замена $localTestDir происходит слишком рано.

Вот подход, который позволяет вам использовать / для переопределителей:

system('perl', '-pi',
       '-e', 'BEGIN { $dir = shift(@ARGV) };',
       '-e', 's/\\Q$dir\\E//g',
       $localTestDir,
       $suiteTestFile
);

Обратите внимание, что это также защищает содержимое $suiteTestFile от интерпретации оболочкой.

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