How can I canonicalize Windows file paths in Perl?

拜拜、爱过 提交于 2019-12-06 14:58:16

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%

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

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.

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.

[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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!