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

Hi all, Regex noob so be gentle. I have a string with varying amounts of leading whitespace. Say, my $string = '   this is a string';. I'm trying to substitute any leading whitespace I find with a colon. So that this:
this is a string
Becomes this:
:::this is a string
my $string = ' this is a string'; # below replaces first whitespace char, leaves the rest $string =~ s/^\s/:/g; # below replaces first whitespace char, remotes the rest $string =~ s/^\s+/:/g;
Could someone take pity on me and point out the extremely obvious error that I'm overlooking.

Replies are listed 'Best First'.
Re: substitute leading whitespace
by japhy (Canon) on Jun 10, 2005 at 06:28 UTC
    I believe I saw this first in "Effective Perl Programming":
    $str =~ s/\G\s/:/g;
    The \G anchor means "anchor to where the last //g match left off". When no global match has been done yet, \G is synonymous to ^. Thus, each leading space is turned into a colon until a space is not found following the last one.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      luuuuurvely. Works like a charm. Thankies.
Re: substitute leading whitespace
by ikegami (Patriarch) on Jun 10, 2005 at 06:28 UTC

    It doesn't work for two reasons.

    1) When using /g, Perl won't match from the same point within the string twice, so ^ will only match on the first pass.

    2) Your use of ^ ensures that no character other than the first can possibly be replaced.

    Use \G instead of ^ to match where the last pass of /g left off. It behaves like ^ on the first pass.

    my $string = ' this is a string'; $string =~ s/\G\s/:/g; print("$string\n"); # :::this is a string

    Update: Rephrased (2) since it wasn't clear.

      ikegami, maybe I'm misunderstanding your second reason, but I don't think it is correct, because it implies that, under the /g modifier, prior substitutions affect subsequent matches, but consider the following variant of the original example:

      my $s = ' this is a string'; ( my $t = $s ) =~ s/(?<!\w)\s/X/g; print $t, $/; __END__ XXXthis is a Xstring
      If I understood your second reason correctly, according to it the printout would have been:
      X Xthis is a Xstring
      because after the first substitution the second space no longer matches the first part of the s///.

      the lowliest monk

        You've just demonstrated my first point. My second point explained why the regexp wouldn't work even in the absense of the behaviour.

        Less abstractly, I was tring to explain that matching the beginning of the string (^ when not under /m) is useless under </code>/g</code>. It's the same as if /g wasn't there. I rephrased my post to this effect.

Re: substitute leading whitespace
by kaif (Friar) on Jun 10, 2005 at 06:18 UTC

    There is more than one way to do what you would like to do. Surely somebody else will post another way. I like $string =~ s/^(\s+)/':' x length $1/e;

Re: substitute leading whitespace
by Elijah (Hermit) on Jun 10, 2005 at 06:33 UTC
    my $string = ' this is a string'; my $rep; $string =~ s/(^\s+)/$rep.=':' for(1..length($1)); "$rep"/eg; print $string;
    Something like this will do what you are looking for. Of course there are probably other ways of doing this too but this is the first that comes to my mind.
      That for could easily be replaced with the x operator. The /g modifier is useless. The quotes around $rep are useless. In other words, this is a very poor re-implementation of kaif's answer.
        As I stated it is only one way. I also posted this while kaif was posting his/hers so it is not a re-implementation of anything.

        You know it is very easy to compare two solutions and pick them apart to appear smart like so many people on this site tend to do. It awards them upvotes by the regular users of this site who can not see through their stupidity. You should try having an original idea once in a while. I think you will find it liberating. This goes for everyone who has adopted this method of gaining votes to appear intelligent. Who cares about the stupid points. Most of you seem to get confused between fantasy and reality. Status or standing at this single website gives you nothing in life. Try taking a step out and offer a solution instead of offering nothing except contempt. I welcome downvotes from anyone who disagrees, but then again you may have to accpet the fact that you are this type of person who I have outlined above.