How can I canonicalize Windows file paths in Perl?

雨燕双飞 提交于 2019-12-08 05:22:26

问题


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

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