为什么我的正则表达式会因某些替换而失败?

时间:2010-01-25 20:49:18

标签: regex perl

我是perl的新手,不知道如何实现以下目标。 我正在读取一个文件,并将这些行放在一个名为$ tline的变量中。接下来,我试图从$ tline中替换一些字符。 如果$ tline中有一些特殊字符,如(,?,=等),那么这个替换会失败。如何从这个变量$ tline中转义特殊字符?

if ($tline ne "") {

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

修改

对于这些混淆感到抱歉。这是我想要做的。

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

这适用于大多数情况。但是当输入文件有?在它里面,它失败了。

5 个答案:

答案 0 :(得分:7)

怎么样:

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

这将导致quotemeta应用于$var的内容,该内容将被用作模式。

答案 1 :(得分:2)

这不是一个有效的正则表达式:

$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\?\>

答案 2 :(得分:1)

您可以将所有特殊字符放在方括号(称为“字符类”)之间。以下内容将用百分号替换字符串中的所有左括号,问号和等号:

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

打印:

fo%%%o

答案 3 :(得分:0)

嗯,一种方法是将所有要替换的字符放在方括号中。像这样:

$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

正如其他人所说,你发布的代码因为忘记了最后一个/而无法运行。这是将“奇怪”字符保留在一个盒子里的另一个好理由。

答案 4 :(得分:0)

quotemeta是一个很好的函数,可以将带有特殊字符的精确文字转换为正则表达式。 \Q and \E是在正则表达式中做同样事情的好操作符。

但是,你的搜索表达并不复杂。在您的编辑中,您只是在寻找双引号和斜杠。事实上,我已经非常简化了表达式,因此它不包含单个反斜杠。因此quotemeta也不是问题\Q and \E

一旦减少,我在修改后的替换中没有看到任何会导致'?'问题的内容在$tline

简化的关键是'。','('和')'对表达式的替换部分没什么特别之处,所以这是等价的:

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

更不用说更容易阅读了。当然这更容易:

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

因为在Perl中,您可以使用s operator选择所需的分隔符。

但是有了这些,这就有用了:

use Test::More tests => 1;

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

通过测试。也许你在一条线上有多个替换的问题。可以通过以下方式解决:

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

g是最后的全局开关,表示将此替换次数与输入中的次数相同。

然而,既然我可以看到你在做什么,我建议你更加严格地规范你要搜索的内容:

$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 问题尚未明确。