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

On my way to Perl wisdom I am stuck with a (probably simple) problem: I try to replace all characters from the beginning and end of a string with another character but not within the string. Here is an example:

$string = "---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy--------"; $string =~ s/\A-+|-+$/?/g;


The output is: ?xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy?

However what I want is to replace ever - with an ?. What am i doing wrong here?

I searched on the web but found no solution. Is this even possible with regular expressions?

Thank you in advance!

Comment on What is wrong here (Replacing Strin pieces)
Download Code
Re: What is wrong here (Replacing Strin pieces) (tr)
by Anonymous Monk on Jul 16, 2013 at 11:18 UTC
Re: What is wrong here (Replacing Strin pieces)
by rjt (Deacon) on Jul 16, 2013 at 11:22 UTC

    The -+ matches all dashes at the start/end of the string, but you're replacing them with a single ?. You need to stuff in as many question marks as there were dashes. One way out of many, using eval (/e):

    use 5.012; my $string = "---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy--------"; say $string; $string =~ s/(\A\-+|\-+$)/'?' x length $1/eg; say $string;

    Output:

    ---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy-------- ?????????xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy????????
      Thank you! I replaced with with only one ?, didn't think of that! I will also study the perlintro again. A long way to wisdom ;)
Re: What is wrong here (Replacing Strin pieces)
by choroba (Abbot) on Jul 16, 2013 at 11:23 UTC
    It is possible, but I am not sure it is comprehensible. I would not recommend it for production code:
    $string =~ s/\A(-+)|(-+)$/("?" x length $1).("?" x length $2)/eg;
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      $string =~ s/\A(-+)|(-+)$/("?" x length $1).("?" x length $2)/eg;

      That does the substitutions, but will also produce warnings if run with warnings:

      >perl -wMstrict -le "my $s = '---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy--------'; print qq{'$s'}; ;; $s =~ s{ \A (-+) | (-+) \z } { ('?' x length $1) . ('?' x length $2) }xmsge; print qq{'$s'}; " '---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy--------' Use of uninitialized value $2 in repeat (x) at -e line 1. Use of uninitialized value $1 in repeat (x) at -e line 1. '?????????xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy????????'
Re: What is wrong here (Replacing Strin pieces)
by Laurent_R (Parson) on Jul 16, 2013 at 11:54 UTC

    Do you want to replace all the dashes, or only those at the beginning and at the end of the string?

    For replacing all dashes, the tr/// function will be better (and much faster).

    In the other case (only the dashes at the beginning and at the end), then you'll need to count the number of dashes you will be removing to figure out how many questions marks to insert, which can be done in several different ways (remember that s/// returns the number of substitutions performed), but none of those I can think of in the moment is really elegant.

Re: What is wrong here (Replacing Strin pieces)
by AnomalousMonk (Abbot) on Jul 16, 2013 at 16:28 UTC

    For production code, I think I prefer something like rjt's approach, but here's a cute variation:

    >perl -wMstrict -le "my $s = '---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy--------'; print qq{'$s'}; ;; $s =~ s{ (?: \G | (?= -+ \z)) - }'?'xmsg; print qq{'$s'}; " '---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy--------' '?????????xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy????????'
Re: What is wrong here (Replacing Strin pieces)
by kcott (Abbot) on Jul 17, 2013 at 07:23 UTC

    Rather than getting bogged down with alternating between the start and end strings and then doing a repeat substitution, just capture the middle bit and tag a '?' on either end. This works with the sample string you provided:

    $ perl -Mstrict -Mwarnings -E ' my $string = "---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy-------- +"; $string =~ s/^-*(.*?)-*$/?$1?/; say $string; ' ?xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy?

    Update: Actually, that may not be what you want at all!

    I read:

    • "replace all characters ..." [plural] "... with another character" [singular]
    • "The output is: ?xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy?" [wanted output]
    • "replace ever - ..." [plural] "... with an ?" [singular]

    So, assuming I've completely misinterpreted your question, I'd recommend ++rjt's solution. However, if you still wanted something without alternations or repeating, you could use this:

    $ perl -Mstrict -Mwarnings -E ' my $string = "---------xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy-------- +"; $string =~ s/^(-*)(.*?)(-*)$/"?" x length($1) . $2 . "?" x length( +$3)/e; say $string; ' ?????????xxxxxxxxxxxxxxx------yyyyyyyyyyyyyy????????

    -- Ken