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

Hi,

I have an input file with 5 columns separated by single space. The first column is of width n (4 in this case). The second column is of width m (4 in this case). The rest of the columns are of variable width. I need to change the ith character (2 in this case) in second column (i<m) make it 'Y' say AND APPEND it as a third column.

Input file
col1 col2 col3 col4 col5 1234 5678 9012 3456 7890
Output file
col1 col2 cYl2 col3 col4 col5 1234 5678 5Y78 9012 3456 7890
The following program does it just fine.
use strict; use warnings; my $line; while($line=<>){ chomp $line; $line =~ s/(.{5})(.{4})(.*)/$1$2 $2$3/; $line =~ s/(.{11}).(.*)/$1Y$2/; print $line."\n"; }
My question is, is it possible to accomplish this in one s/// command? We can use \1 and \2 etc to reference the pattern we just matched, but I can't figure out how to do it here. Is it even possible?

Thanks for any help with this.

Replies are listed 'Best First'.
Re: Search patern within pattern in a single substitute command
by BrowserUk (Patriarch) on Mar 04, 2011 at 01:06 UTC

    Here's one way:

    #! perl -sw use strict; s[(?:\S+ ){2}\K((.).(..))][$2Y$3 $1], print while <DATA>; =output C:\test>junk56 col1 col2 cYl3 col3 col4 col5 1234 5678 9Y12 9012 3456 7890 =cut __DATA__ col1 col2 col3 col4 col5 1234 5678 9012 3456 7890

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Very cool. Your output doesn't quite match the OP's, but with this slight adjustment, we do:
      use warnings; use strict; s[.{5}\K((.).(..))][$1 $2Y$3], print while <DATA>; __DATA__ col1 col2 col3 col4 col5 1234 5678 9012 3456 7890
      prints:
      col1 col2 cYl2 col3 col4 col5 1234 5678 5Y78 9012 3456 7890
      Looking back now, I knew nested pattern ((.).(..)) and should have thought about it here. It turned out to be the key. What does the \K mean? If I don't include it I get o/p
      col2 cYl2 col3 col4 col5 5678 5Y78 9012 3456 7890
      W/o \K the following works too, but I would like to understand \K
      s[(.{5})((.).(..))(.*)][$1$2 $3Y$4$5], print while <DATA>;
      This is something I would have written if I had thought about the nested pattern in the first place....
        What does the \K mean?

        from Perldoc perlre: "Character Classes and other Special Escapes"

        \K Keep the stuff left of the \K, don't include it in $&

        It says that the bit of the regex preceding it is only used to locate the part of the string to be replaced, but isn't a part of the substitution. It just saves the need for an extra capture.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Search pattern within pattern in a single substitute command
by toolic (Bishop) on Mar 04, 2011 at 01:02 UTC
    is it possible to accomplish this in one s/// command?
    Yes, but it is hideously ugly, and you shouldn't do it this way (update... do it BrowserUk's way):
    use warnings; use strict; while (my $line = <DATA>){ chomp $line; $line =~ s/(.{5})(.{4})/$1 . $2 . ' ' . substr($2, 0, 1) . 'Y' . s +ubstr($2, 2, 2)/e; print $line . "\n"; } __DATA__ col1 col2 col3 col4 col5 1234 5678 9012 3456 7890
    prints:
    col1 col2 cYl2 col3 col4 col5 1234 5678 5Y78 9012 3456 7890