FFSparky has asked for the wisdom of the Perl Monks concerning the following question:

I'm rusty and sure I'm missing something simple...
In trying to convert the following working code:
$var = "C:\\Dir1\\Dir2\\Dir3\\KeepMe"; $var =~ s/C:\\Dir1\\Dir2\\Dir3//; print "\$var: $var\n";
Result: $var: \KeepMe

To instead be dynamis and use variables in the regex:
$find="C:\\Dir1\\Dir2\\Dir3"; $replace=''; $var = "C:\\Dir1\\Dir2\\Dir3\\KeepMe"; $var =~ s/$find/$replace/eeg; print "\$var: $var\n";
I get an unexpected Result: $var: C:\Dir1\Dir2\Dir3\KeepMe

Thanks in advance for your wisdom!

Replies are listed 'Best First'.
Re: Help with regex using variables
by haukex (Archbishop) on May 16, 2023 at 07:24 UTC

    I would recommend using a module for manipulating paths. File::Spec is a core module, meaning you normally don't have to install it, and Path::Class is basically a nicer interface for it that gives you objects with lots of nice features.

    use File::Spec::Functions qw/abs2rel/; my $path = "C:\\Dir1\\Dir2\\Dir3\\KeepMe"; my $base = "C:\\Dir1\\Dir2\\Dir3"; print abs2rel($path, $base), "\n"; # prints "KeepMe" # - or - use Path::Class qw/dir file/; my $path = dir('C:\\','Dir1','Dir2','Dir3','KeepMe'); my $base = dir('C:\\','Dir1','Dir2','Dir3'); print $path->relative($base), "\n"; # prints "KeepMe"

    This code assumes it is being run on a Windows system - if you are instead manipulating Windows pathnames on a Linux or Mac system, there are ways to do that with the above modues as well.

    s/$find/$replace/eeg

    BTW, why are you using /eeg here? It doesn't seem necessary. (Plus, I would also anchor the regex to the beginning of the string with ^, just in case.)

    Update: You asked the same question 11 years ago: Help with Regular Expressions

      Similarly, I would use File::Spec to construct the paths and do away with all the escaping which will be taken care by Perl in a portable way:

      use File::Spec; my $path = File::Spec->catfile("C:", "Dir1", "Dir2", "Dir3", "KeepMe") +; my $base = File::Spec->catdir("C:", "Dir1", "Dir2", "Dir3"); # or my $base = File::Spec->catdir("C:", "Dir1", "Dir2", "Dir3"); my $path = File::Spec->catfile($base, "KeepMe");
Re: Help with regex using variables
by kcott (Archbishop) on May 16, 2023 at 16:07 UTC

    G'day FFSparky,

    You seem to have a number of problems.

    • Don't use interpolating double-quotes and then try to manually escape characters within the quoted string (e.g. "C:\\Dir1\\Dir2\\Dir3"); it's tedious, fiddly and error-prone. Instead, use non-interpolating single-quotes and don't make any manual modifications (e.g. 'C:\Dir1\Dir2\Dir3').
    • The $search part of s/$search/$replace/ interpolates. Let Perl escape characters here with quotemeta: s/\Q$search/$replace/. Note that you're still not doing tedious, fiddly and error-prone manual modifications.
    • The '/eeg' modifiers on the s/// are completely unnecessary. See "perlre: Modifiers" and "perlop: Regexp Quote-Like Operators: s/PATTERN/REPLACEMENT/msixpodualngcer".

    Consider this example script (pm_11152209_re_backslashes.pl) which is portable:

    #!/usr/bin/env perl use strict; use warnings; my $search = 'C:\Dir1\Dir2\Dir3'; my $replace = ''; my $var = 'C:\Dir1\Dir2\Dir3\KeepMe'; $var =~ s/\Q$search/$replace/; print "\$var[$var]\n";

    On Cygwin:

    ken@titan ~/tmp $ perl -v This is perl 5, version 36, subversion 0 (v5.36.0) built for cygwin-th +read-multi ... ken@titan ~/tmp $ ./pm_11152209_re_backslashes.pl $var[\KeepMe]

    On Win10:

    C:\cygwin64\home\ken\tmp>perl -v This is perl 5, version 26, subversion 3 (v5.26.3) built for MSWin32-x +64-multi-thread ... C:\cygwin64\home\ken\tmp>perl pm_11152209_re_backslashes.pl $var[\KeepMe]

    — Ken

      Ken, Thanks again for your wisdom, and especially taking the time in pointing out the many errors of my rusty PERL coding! Your provided example works perfect! Regards, Greg
Re: Help with regex using variables
by jwkrahn (Abbot) on May 16, 2023 at 06:15 UTC
    $find="C:\\Dir1\\Dir2\\Dir3"; $replace=''; $var = "C:\\Dir1\\Dir2\\Dir3\\KeepMe"; $var =~ s/$find/$replace/eeg; print "\$var: $var\n";

    The first line interpolates the double quoted string, converting "\\" to '\'.

    The fourth line also interpolates the string.

    Try using either $find='C:\\Dir1\\Dir2\\Dir3'; or better yet use $find = qr/C:\\Dir1\\Dir2\\Dir3/;.

    Naked blocks are fun! -- Randal L. Schwartz, Perl hacker
      Try using either $find='C:\\Dir1\\Dir2\\Dir3';

      No, that's the exact same as "C:\\Dir1\\Dir2\\Dir3", since single-quoted strings still interpolate a few characters, backslashes being one of them.

      The fourth line also interpolates the string.

      Not only does it interpolate, it will also interpret any characters special to regexes as such. Your qr// suggestion is good, as an alternative I would suggest s/\Q$find\E/$replace/ to escape the string (see quotemeta).

Re: Help with regex using variables
by Anonymous Monk on May 19, 2023 at 15:42 UTC
    maybe Im missing something here, but if you want just the filename, how about
    s#.+\\##;
    ?