【问题标题】:replace part of file path via regex通过正则表达式替换部分文件路径
【发布时间】:2012-08-17 14:14:33
【问题描述】:

我尝试在 Perl 中替换文件全名的目录部分。 就像是: 在目录 'D:\Texts1' 中得到文件名 'D:\Texts1\text1',想用 'D:\Texts2' 替换它,然后文件名将是 'D:\Texts2\text1'。

我试试这个代码:

$filename = 'D:\Texts1\text1';
$i = 'D:\Texts1';
$o = 'D:\Texts2';
$filename =~ s'$i'$o'g;

而且没有生效。 $filename 不会改变。 我尝试使用类似的东西

$i = quotemeta('D:\Texts1');

但它也没有生效。

【问题讨论】:

  • 谢谢大家!我的错误是我尝试一次对 $i 和 $o 使用 quotemeta。但只有 $i 才需要它。
  • 其实单引号也是个问题——看我的回答。您可能在某个时候从单引号更改为另一个分隔符,这也有助于修复它。

标签: regex perl path


【解决方案1】:

这里有几个有效的答案,我想和我一起编译一个全面的答案,以使这篇文章更容易阅读:

根本原因

$i = 'D:\Texts1';

当用作正则表达式模式时,“\”应该被转义 - 正则表达式引擎想要的是某种终极格式,例如:D:\\Texts1。所以这是行不通的,但是,至少有 4 种不同的方法来构建这种格式,如下所示。

还要注意,当 ' 用作匹配或替换语句的分隔符时,变量插值将被禁用,这使得 $filename =~ s'$i'$o'g; 几乎无用.所以第一步,把它改成使用 / 或 {}

解决方案 1

使用quotemeta,这将有效地避开“\”:

$filename = 'D:\Texts1\text1';
$i = quotemeta('D:\Texts1');
$o = 'D:\Texts2';
$filename =~ s/$i/$o/g;

解决方案 2

使用\Q .. \E,效果与quotemeta类似:

$filename = 'D:\Texts1\text1';
$i = 'D:\Texts1';
$o = 'D:\Texts2';
$filename =~ s/\Q$i\E/$o/g; # or s/\Q$i/$o/g also works

解决方案 3

明确转义字符串中的“\”,并使用qr 将字符串引用为正则表达式。

$filename = 'D:\Texts1\text1';
$i = qr 'D:\\Texts1';
$o = 'D:\Texts2';
$filename =~ s/$i/$o/g;

解决方案 4

转义到字符串准备好进行正则表达式的程度:

$filename = 'D:\Texts1\text1';
$i = 'D:\\\\Texts1';
$o = 'D:\Texts2';
$filename =~ s/$i/$o/g;

【讨论】:

    【解决方案2】:

    这不会插入

    $filename =~ s'$i'$o'g;
    

    尝试使用/ 而不是',如下所示:

    $filename =~ s/$i/$o/g;
    

    应该可以。 ' 防止字符串插值,因此变量名称显示为字符串文字。另外,请确保像以前一样使用quotemeta

    【讨论】:

    • 他们应该使用正斜杠或转义他们的反斜杠。
    • s 后面可以跟任何字符,包括单引号,这成为正则表达式的分隔符。尝试:perl -p -e "s'a'b'g" 并在输入中输入一些 a。
    • 从技术上讲,你是对的,但这是非常糟糕的做法...尝试运行this,然后运行this,然后告诉我哪个有效...。
    • 这是因为单引号在这种情况下的特殊含义:它们阻止了变量插值。
    • +1 @dan1111,我刚看了here:如果使用“'”作为分隔符,则不进行插值
    【解决方案3】:

    D:\Texts1 中的 \ 是问题所在。您需要转义此元字符。为此,字符串应由\Q\E 包裹。

    $filename =~ s/\Q$i\E/$o/g;
    

    【讨论】:

    • 你知道为什么显式逃跑不起作用吗? $i = 'D:\\Texts'?
    • lzprgmr:它们本质上是一样的:perl -E 'say "OK" if q{a\b} eq q{a\\b}'
    【解决方案4】:

    您需要添加\Q:

    $filename =~s{\Q$i}{$o};
    

    【讨论】:

    • 只有一个变量。 \E 不是必需的,但我想它会更好
    【解决方案5】:

    事实上,您遇到了两个问题的组合:

    • 单引号虽然作为正则表达式分隔符有效,但具有特殊含义:它们禁用变量插值。因此,您正在字符串中搜索文字模式$i(如果您启用了警告,您会得到一个线索——它告诉您变量 $i 和 $o 在您的程序中只使用一次)。李>
    • 正如其他人所指出的,您还需要 \Q...\E 构造或 quotemeta() 以避免将变量中的特殊字符解释为正则表达式运算符。

    【讨论】:

      【解决方案6】:

      更新代码

      use strict;
      use warnings qw/all/;
      
      my $filename = 'D:\Texts1\text1';
      my $i = 'D:\\Texts1';
      my $o = 'D:\\Texts2';
      $filename =~ s/\Q$i\E/$o/;
      
      print $filename;
      

      要快乐!

      【讨论】:

      • 您真的想要替换文本的正则表达式吗?我怀疑不是。
      • 搜索替换中的引号无效,$o应该是q,而不是qr,不是正则表达式
      • @JohnCorbett 你知道为什么 $i=qr 'D:\\Texts1' 有效而 $i= 'D:\\Texts1' 无效吗?我们只是自己添加转义符,为什么使用quotemeta进行比较。
      • 在使用 \Q 和 \E 转义模式中的反斜杠后,代码将不起作用,因为反斜杠在正则表达式模式中转义为 \\
      猜你喜欢
      • 2012-10-28
      • 2019-07-25
      • 1970-01-01
      • 1970-01-01
      • 2013-09-27
      • 1970-01-01
      • 2023-02-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多