简体   繁体   中英

replace part of file path via regex

I try to replace directory part of file fullname in Perl. Something like: got filename 'D:\\Texts1\\text1' in directory 'D:\\Texts1', want to replace it with 'D:\\Texts2' and then filename will be 'D:\\Texts2\\text1'.

I try this code:

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

And it does not take effect. $filename doesn't changes. I tried to use something like

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

but it also has not took effect.

There are several valid answers here, I would like to compile a comprehensive answer along with mine to make this post easier to read:

Root Cause

$i = 'D:\Texts1';

when used as a regex pattern, "\\" should be escaped - what the regex engine want is some ultimate format like: D:\\\\Texts1 . So this doesn't work, however, there are at least 4 different ways to build this format as listed below.

Also to notice, when ' is used as delimiter for match or substitution statement, variable interpolation will be disabled, which renders $filename =~ s'$i'$o'g; almost useless. so first step, change it to use / or {}

Solution 1

use quotemeta , this will effectively escape the "\\":

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

Solution 2

use \\Q .. \\E, which has similar effects as 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

Solution 3

escape the "\\" in the string explicitly, and use qr to quote the string as regex pattern.

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

Solution 4

escape to the extent that the string is ready for regex:

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

The \\ in D:\\Texts1 is the problem. You need to escape this metacharacter. For this purpose, the string should be wrapped by \\Q and \\E .

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

this doesn't interpolate

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

try using / instead of ' , like this:

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

that should work. ' prevents string interpolation, so the variable names appear as string literals. Also, make sure to use the quotemeta like you were doing before.

你需要添加\\Q

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

In fact you are experiencing a combination of two problems:

  • Single quotes, while valid as a regexp delimiter, have a special meaning: they disable variable interpolation. Thus you are searching your string for the literal pattern $i (if you have warnings enabled, you get a clue to this--it tells you that the variables $i and $o are only used once in your program).
  • As others have pointed out, you also need the \\Q...\\E construct or quotemeta() in order to avoid interpreting the special characters in your variable as regexp operators.

Updated code

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;

Be happy!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM