问题
Update:
I can make this a simpler problem to solve:
I want to figure out what the correct regex would be to substitute any single occurrence of a back slash with two back slashes.
I want to turn this:
vlc.plugin.path = C:\Program Files\JekyllV0.9.2\\VLC_1.0.0\\plugins
into:
vlc.plugin.path = C:\\Program Files\\JekyllV0.9.2\\VLC_1.0.0\\plugins
Original question:
I want to change the following in a file using a Perl Regex:
- all occurrences of a single back slash to two back slashes
- all occurrences of a single forward slash to two back slashes
I tried the following:
perl" -p -i.orig -e "s#\\#\\\\#g" -e "s#/#\\\\#g" %VIDEOLOG_PROPERTIES_FILE%
where %VIDEOLOG_PROPERTIES_FILE% contains:
vlc.plugin.path = C:\Program Files\JekyllV0.9.2/VLC_1.0.0/plugins
回答1:
For the basic replace:
perl -p -i.orig -e "s#[/\\]#\\\\#g" %VIDEOLOG_PROPERTIES_FILE%
To replace only slashes and backslashes that do not appear adjacent to another instance of the same character:
perl -p -i.orig -e "s#(?<!/)/(?!/)#\\\\#g; s#(?<\\)\\(?!\\)#\\\\#g" %VIDEOLOG_PROPERTIES_FILE%
回答2:
You want File::Spec->canonpath.
Update:: Actually, that was the wrong recommendation. That will work for internal function calls etc but it will write single backslashes to the file. However, the following will work better:
#!/usr/bin/perl
use strict;
use warnings;
use Config::INI::Reader;
my $config = Config::INI::Reader->read_handle(\*DATA);
my $var1 = $config->{_}->{'vlc.plugin.path1'};
my $var2 = $config->{_}->{'vlc.plugin.path2'};
for my $v ($var1, $var2) {
$v =~ s! (?: [\\]{1,2} ) | (?:/) !\\\\!gx;
print "$v\n";
}
__DATA__
vlc.plugin.path1 = C:\Program Files\JekyllV0.9.2\\VLC_1.0.0\\plugins
vlc.plugin.path2 = C:\Program Files\JekyllV0.9.2/VLC_1.0.0/plugins
Output:
C:\\Program Files\\JekyllV0.9.2\\VLC_1.0.0\\plugins C:\\Program Files\\JekyllV0.9.2\\VLC_1.0.0\\plugins
回答3:
I'm pretty sure Perl blindly concatenates all its -e
arguments, so those are being squashed into s#\\#\\\\#gs#/#\\\\#g
, and then the second regex looks like a comment.
It works for me if I change it to -e 's#\\#\\\\#g; s#/#\\\\#g'
.
Of course, you could do this with a single regex, since you're using the same replacement both times.
回答4:
It doesn't work, because perl doesn't handle two -e
flags--without a semicolon "between" the two commands. You have to write it as below (if you lose the d-quote right after 'perl', that is.)
perl -p -i.orig -e "s#\\#\\\\#g;" -e "s#/#\\\\#g" %VIDEOLOG_PROPERTIES_FILE%
I do something similar, but because Perl supports '/'
on the PC, my preference is for forward slashes. So I use the following :
s![\\/]+!/!g;
Thus it can be easily turned around to
s![\\/]+!\\\\!g;
Now a word about why I do that: sometimes people can't figure out whether or not they should put a slash on the beginning or end of parts of paths that will be concatenated. At times you end up with even double forward slashes. (But not if you use File::Spec.) thus it's good to handle those kinds of collisions. Especially because it's going to be a path, we want to take however many slashes of whatever kind and turn them into the kind we like.
Additionally, I even do this:
s!([\\/]+([.][\\/]+)?)+!/!g
Because it captures those cases where it's the same cluster of slashes separated by a dot which does nothing, because path-wise /
<=> (/+.)+
for those programs and scripts that handle the dots in path names, while the other programs will error out.
回答5:
[21:09:00][mgrad@zuza-3:~]$ perl -pe 's#\/#\/\/#g; s#\\#\\\\#g' test.txt
vlc.plugin.path = C:\\Program Files\\JekyllV0.9.2//VLC_1.0.0//plugins
来源:https://stackoverflow.com/questions/1308152/how-can-i-canonicalize-windows-file-paths-in-perl