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

Dear Perl experts,

the statement in my script
s/A/a/; replaces first occurance of A to a, and

s/A/a/g; replaces all occurance of A to a,

but i want to replace all the occurances except the first one.

please advise.

20040904 Edit by castaway: Changed title from 'regular exp.'

Replies are listed 'Best First'.
Re: replace all but first
by BrowserUk (Patriarch) on Sep 03, 2004 at 13:41 UTC
    my $s='aAaAaAaAaAaAAAAaaa'; substr( $s, 1+index( $s, 'A' ) ) =~ s[A][a]g; print $s; aAaaaaaaaaaaaaaaaa

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: replace all but first
by Roy Johnson (Monsignor) on Sep 03, 2004 at 14:30 UTC
    One way:
    /A/g; s/\G(.*?)A/$1a/g;
    Another way:
    s{(?<=A)(.*)}{my $rest=$1; $rest=~tr/A/a/; $rest}e;
    Without regex:
    substr($_, index($_, 'A')+1) =~ tr/A/a/;
    And, combining techniques:
    /A/g; substr($_, ++pos) =~ tr/A/a/;

    Caution: Contents may have been coded under pressure.
Re: replace all but first
by QM (Parson) on Sep 03, 2004 at 16:00 UTC
    I liked EdwardG's solution, but here's a less expert one:
    1 while s/^([^A]*A[^A]*)A/$1a/;

    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

Re: replace all but first
by terra incognita (Pilgrim) on Sep 03, 2004 at 16:46 UTC
    Here is my solution. It is no where as elegant and short as the previous ones. Comments on where I can improve this code and what practices I should stay away from are appreciated.
    use strict; #OPEN FILE A.txt for READING (CHECK FOR FAILURES) open (INFILE, "<","A.txt" ) or die "Could not open file A.txt: $!"; #OPEN FILE B.txt for WRITING (CHECK FOR FAILURES) open (OUTFILE, ">","B.txt" ) or die "Could not open file B.txt: $!"; my $prev_country = ""; my $line; my @myarray; my $country; my $company; while ($line = <INFILE>) { # SPLIT THE FILE BETWEEN COUNTRY AND COMPANY @myarray = split /></,$line; $country = $myarray[0]; # CHECK TO SEE IF THE CURRENT COUNTRY MATCHS THE PREVIOUS COUNTRY if ($prev_country ne $country) { #IF NEW COUNTRY PRINT WHOLE LINE print OUTFILE "$line"; $prev_country = ($country); next; } # IF SAME COUNTRY PRINT ONLY COMPANY $company = $myarray[1]; print OUTFILE "\t<$company"; } close OUTFILE; close INFILE;
      Not bad, but to keep it a little more re-usable and flexible (suppose, for instance, more tags/values are added later), you can do away with the $company and $country variables altogether, and do:

      ... @myarray = split /></,$line; if ( $prev ne $myarray[0] ) { $prev = $myarray[0]; } else { $myarray[0] = "<TAB"; } $line = join '><', @myarray; print OUTFILE, $line; ...
      This also takes care of the fact that I think the original author meant <TAB> literally. If I'm wrong, insert this after the join:

      $line =~ s/<TAB>/\t/;
Re: replace all but first
by DigitalKitty (Parson) on Sep 04, 2004 at 08:39 UTC
Re: replace all but first
by Grygonos (Chaplain) on Sep 03, 2004 at 13:43 UTC

    Firstly, there isn't much information you've given us. The layout of the file may be helpful. Secondly, I would reccomend using tr rather than s (see perlop). Since you are not replacing, but rather transliterating. However, if you wanted to replace a with ABBA (haha) then you would want to use the s operator.

      This is what i am trying to do

      my text file has
      <cnt>Germany</cnt><cmp>ALLIANZ INSURANCE</cmp>
      <cnt>Germany</cnt><cmp>ALLIANZ PARKWAY</cmp>
      <cnt>Germany</cnt><cmp>ALLIED DOMECQ</cmp>

      i want to replace it as
      <cnt>Germany</cnt><cmp>ALLIANZ INSURANCE</cmp>
      <TAB><cmp>ALLIANZ PARKWAY</cmp>
      <TAB><cmp>ALLIED DOMECQ</cmp>

      i.e. i want to replace "<cnt>Germany</cnt>" to "<TAB>" from its second occurance

        use strict; use warnings; my %seen; while ( <DATA> ) { next unless /^(<cnt>([^<]+)<\/cnt>)(.*)$/; print $seen{$2}++ ? "<TAB>$3\n" : "$1$3\n"; } __DATA__ <cnt>France</cnt><cmp>ACCOR</cmp> <cnt>France</cnt><cmp>AGF</cmp> <cnt>France</cnt><cmp>AIR LIQUIDE</cmp> <cnt>Germany</cnt><cmp>ALLIANZ INSURANCE</cmp> <cnt>Germany</cnt><cmp>ALLIANZ PARKWAY</cmp> <cnt>Germany</cnt><cmp>ALLIED DOMECQ</cmp> <cnt>United Kingdom</cnt><cmp>LEICESTER CITY FOOTBALL CLUB</cmp> <cnt>United Kingdom</cnt><cmp>SPENCER GEARS</cmp>
        If it's not going to appear twice on the same line:
        my $seen=0; while(<DATA>) { if ($seen) { s{<cnt>Germany</cnt>}{<TAB>} } else { $seen ||= m{<cnt>Germany</cnt>} } print; } __DATA__ <cnt>Germany</cnt><cmp>ALLIANZ INSURANCE</cmp> <cnt>Germany</cnt><cmp>ALLIANZ PARKWAY</cmp> <cnt>Germany</cnt><cmp>ALLIED DOMECQ</cmp>

        Caution: Contents may have been coded under pressure.
        $data =~ s{(<cnt>Germany</cnt>)}{$seen++?'<TAB>':$1}ge;