Почему мое регулярное выражение терпит неудачу с некоторыми заменами? - PullRequest
2 голосов
/ 25 января 2010

Я новичок в Perl и не знаю, как добиться следующего. Я читаю файл и помещаю строки в переменную с именем $ tline. Далее я пытаюсь заменить некоторый символ из $ tline. Эта замена завершается неудачно, если в $ tline есть некоторые специальные символы, такие как (,?, = И т. Д. Как экранировать специальные символы из этой переменной $ tline?

if ($tline ne "") {

   $tline =~ s/\//\%;
}

EDIT

Извините за путаницу. Вот что я пытаюсь сделать.

$tline =~ s/"\//"\<\%\=request\.getContextPath\(\)\%\>\//;

Это работает для большинства случаев. Но когда входной файл имеет? в нем оно терпит неудачу.

Ответы [ 5 ]

7 голосов
/ 26 января 2010

Как насчет:

$tline =~ s/\Q$var\E/;

Это приведет к тому, что quotemeta будет применено к содержимому $var, которое используется в качестве шаблона.

2 голосов
/ 25 января 2010

Это недопустимое регулярное выражение:

$tline =~ s/\//\%;

Это читается как perl

$tline =~ s/a/%;

Где a = /

Что вы хотелисделать, это заменить косая черта на знак процента , который вы, вероятно, хотите

$tline =~ s/\//%/;

который лучше написать так:

$tline =~ s,/,%,;

Вы, вероятно, также хотите заменить больше, чем просто первую косую черту, поэтому вам нужен флаг /g:

$tline =~ s,/,%,g;

И это именно то, что tr (транслитерация) делает:

$tline =~ tr,/,%,;

ОБНОВЛЕНИЕ Я думаю, что вам нужно просто quotemeta(), который принимает ваш ввод и экранирует метасимволы

$ perl -e'print quotemeta("</foo?>")'
\<\/foo\?\>
1 голос
/ 26 января 2010

Вы можете поместить все свои специальные символы в квадратные скобки (называемые «классом символов»). Следующее заменит все левые скобки, вопросительные знаки и знаки равенства в вашей строке на знаки процента:

my $tline = 'fo(?=o';
$tline =~ s/[(?=]/%/g;
print "$tline\n";

Печать:

fo%%%o
0 голосов
/ 26 января 2010

quotemeta - это хорошая функция для получения точного литерала со специальными символами в регулярном выражении. И \Q и \E являются хорошими операторами для того же действия внутри регулярного выражения.

Однако, ваше поисковое выражение не так уж сложно. При редактировании вы просто ищете двойную кавычку и косую черту. На самом деле, я довольно упростил ваше выражение, так что оно не содержит ни одной обратной косой черты . Так что это не проблема для quotemeta, и в этом отношении \Q и \E.

После сокращения я не вижу в вашей исправленной замене ничего, что могло бы вызвать проблему с '?' в $tline.

Ключом к упрощению является то, что '.', '(' И ')' ничего не значат для секции replace вашего выражения, так что это эквивалентно:

$tline =~ s/"\//"<%=request.getContextPath()%>\//;

Не говоря уже о том, что его легче читать. Конечно, это еще проще:

$tline =~ s|"/|"<%=request.getContextPath()%>/|;

Поскольку в Perl вы можете выбрать желаемый разделитель с помощью оператора s .

Но с любым из них это работает:

use Test::More tests => 1;

my $tline = '"/?"';
$tline =~ s|"/|"<%=request.getContextPath()%>/|;
ok( $tline =~ /getContextPath/ );

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

$tline =~ s|"/|"<%=request.getContextPath()%>/|g;

То, что g является переключателем global на конце, говоря, производите эту замену столько раз, сколько это происходит на входе.

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

$tline =~ s~\b(href|link|src)="/~$1="<%=2request.getContextPath()%>/~g;

И когда я запускаю это:

use Test::More tests => 2;

my $tline = '"/?"';
$tline =~ s/"\//"<%=request.getContextPath()%>\//;
ok( $tline =~ /getContextPath/ );
$tline = 'src="/?/?/beer"';
ok( $tline =~ s~\b(href|link|src)="/~$1="<%=request.getContextPath()%>/~g
   );

У меня два успеха.

Ваша true проблема еще не определена.

0 голосов
/ 26 января 2010

Ну, один из способов сделать это - поместить все символы, которые вы хотите заменить, в квадратные скобки. Вот так:

$string =~ s/[,?=\/]//;  # This will remove the first ',', '?', '=', or '/' from your string.

Если вы хотите удалить все «?» например, в строке используйте g в конце, например:

$string =~ s/[?]//g;

Я немного ржавый, но я считаю, что вам нужно только '\' перед \ или /, (и, конечно, другими специальными символами, такими как \ n, \ t и т. Д.). Вот так:

$string =~ s/[\\]/[\/]/g; # Switch from DOS to Unix delimiters.

$string =~ s/[\n\t]//g;   # Remove all newlines and tabs

Как уже говорили другие, код, который вы разместили, не будет работать, так как вы забыли последний /. Это еще одна веская причина хранить «странные» символы в коробке.

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