代码之家  ›  专栏  ›  技术社区  ›  Shamik

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

  •  2
  • Shamik  · 技术社区  · 15 年前

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

    if ($tline ne "") {
    
       $tline =~ s/\//\%;
    }
    

    编辑

    对不起,我有点困惑。这就是我要做的。

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

    这对大多数情况都有效。但是当输入文件有?在这方面,它是失败的。

    5 回复  |  直到 15 年前
        1
  •  7
  •   Sinan Ünür    15 年前

    怎么样:

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

    这将导致 quotemeta 适用于 $var 它被用作模式。

        2
  •  2
  •   Evan Carroll    15 年前

    这不是有效的regex:

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

    它被这样读给Perl

    $tline =~ s/a/%;
    

    在哪里? a = /

    你想做的是替换 前斜杠 用一个 百分率符号 你可能想要

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

    最好这样写:

    $tline =~ s,/,%,;
    

    您可能还希望替换的不仅仅是第一个正斜杠,因此您希望 /g 旗帜:

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

    而且,这正是什么 tr (音译)做:

    $tline =~ tr,/,%,;
    

    更新 我想你想要的是一个简单的 quotemeta() 它接受您的输入,并且regex转义元字符

    $ perl -e'print quotemeta("</foo?>")'
    \<\/foo\?\>
    
        3
  •  1
  •   toolic    15 年前

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

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

    印刷品:

    fo%%%o
    
        4
  •  0
  •   Axeman maxelost    15 年前

    quotemeta 是一个很好的函数,可以将带有特殊字符的精确文字转换为regex。和 \Q and \E 是在regex中执行相同操作的好运算符。

    但是,您的搜索表达式并没有那么复杂。在您的编辑中,您只需要查找双引号和斜线。事实上,我已经把你的表达式简化了,所以它不包含一个 反斜线 . 所以这不是问题 夸特梅塔 也不是为了那件事 Q \ 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
       );
    

    我成功了两次。

    你的 问题尚未明确。

        5
  •  0
  •   brian d foy    15 年前

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

    $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
    

    正如其他人所说,由于您忘记了最后一个/,您发布的代码将无法工作。这是另一个很好的理由把“奇怪”的字符放在一个盒子里。