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

I am trying to add a colon after a specific sign (e.g -) only on certain occurrences. Here's an example convert:
-a 123 -b 456 -c 789 -d 333
to:
-a 123 -:b 456 -:c 789 -d 333

I tried s/\-[b,c]/-:/g but the -b and -c were replaced by -: I don't want to replace them, I want to add the colon to them.

Edit: chipmunk 2001-08-28

Replies are listed 'Best First'.
Re: place holder
by dondelelcaro (Monk) on Aug 29, 2001 at 03:07 UTC
    s/// replaces everything that matched on the left with whatever matched on the right. What you want to do is store which one of [c|d] matched, and then put that back into the match, ala
    $bleh="-a 123 -b 456 -c 789 -d 333"; $bleh=~s/-([bc])/-:$1/g; print $bleh;

    The $1 evaluates to whatever ([bc]) matched (either b or c) and then replaces everything matched on the left with whatever is appropriate on the right.
Re: place holder
by lestrrat (Deacon) on Aug 29, 2001 at 03:09 UTC
Re: place holder
by tachyon (Chancellor) on Aug 29, 2001 at 03:25 UTC

    You can find bits and not replace them using lookahead and lookbehind assertions:

    $bleh =~ s/(?<=-)(?=b|c)/:/g;

    For more details see perlman:perlre or Super Search for "lookahead assertions" in the text +/- "tachyon" as author as I know I have written a summary on this a while back.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: place holder
by eyal (Initiate) on Aug 29, 2001 at 04:04 UTC
    Just when you think you can move on, you get into another problem. 2 questions: 1. To make things even more complicated s/-(bc)/-:$1/g looks for substrings as well as strings (bc or b or c), I need it to look only for the string (bc). 2. this is a different problem, I want to split a string with only the first blank (or series of blanks) as an argument. example: split "a b c" into "a" and "b c".
      1. Many options, but basically you must account for the difference between substrings and stand-alone strings, and this appears to be whitespace in your example data, hence something like:
        s/(?<=\s)-([bc]\s)/-:$1/g;
      2. You can stop split from continuing using the 3rd argument:
        split( '\s', 'a b c', 2);
        though if there may be leading whitespace before the 'a' you'd better use the special case of splitting on a single space, which will discard any leading whitespace:
        split( ' ', '  a b c', 2);

      --
      I'd like to be able to assign to an luser

      s/-([bc])/-:$1/g; actually doesn't look for the whole string at all--[bc] is a character class, not a literal string.

      This means that your regex translates to

      • Find a dash ("-")
      • Followed by either a "b" or a "c" (save this character in $1)

      when you wanted that second line to read "the string 'bc' (save this string in $1)".

      The easy solution is to take those brackets out:

      s/-(bc)/-:$1/g;

      and for what I'm guessing is the next step (multiple strings that could match), you can use

      s/-(foo|bar|bc|whatever)/-:$1/g;

      But in fact you might be better off with tachyon's suggestion:

      s/(?<=-)(?=foo|bar|baz)/:/g; #assuming you have 5.005 or better

      The longer but more rewarding solution is to take another couple of trips through perlre when you have a moment--regexen are not the fastest thing in the world to pick up (for us mere mortals, anyway) but they reward study very nicely. :-)

      Your other question just needs the last argument to split:

      ($first, $second) = split ' ', "a b c", 2;
      and you're all set. Good luck!

      Update: fixed boneheaded mistake in split (thanks, Hofmator!)



      If God had meant us to fly, he would *never* have given us the railroads.
          --Michael Flanders

Re: place holder
by eyal (Initiate) on Aug 29, 2001 at 03:17 UTC
    Thanks, problem solved