Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Modifying the match position after each match

by pat_mc (Pilgrim)
on Mar 23, 2010 at 20:54 UTC ( #830400=perlquestion: print w/replies, xml ) Need Help??
pat_mc has asked for the wisdom of the Perl Monks concerning the following question:

Honerable Monks -

I am stuck with a regex problem and need your help (again, I know). I simply want to replace all matches in string. I am trying to include a single quote in front of every string in between underscores that does not contain a single quote yet. Here is the code that I tried:
#! /usr/bin/perl -w use strict; use locale; my $string = "_'nada_komo_el_'sol_"; $string =~ s/(_)([^']+?)(_)/$1'$2$3/go; print $string;
This returns _'nada_'komo_el_'sol_ rather than _'nada_'komo_'el_'sol_. The second match is missed out on because the match position has already passed beyond the underscore separating komo and el. I believe that what I need is a re-assignment of pos($string) -- after each match ... only, I don't know how to include this into the regex. Your help with this would therefore be much appreciated.

Thanks in advance and best regards -


Replies are listed 'Best First'.
Re: Modifying the match position after each match
by toolic (Bishop) on Mar 23, 2010 at 21:02 UTC
    Can you simplify it to this?
    use strict; use locale; my $string = "_'nada_komo_el_'sol_"; $string =~ s/(_)([^'])/$1'$2/g; print $string; __END__ _'nada_'komo_'el_'sol_

    Update: or even:

    $string =~ s/(_)[^']/$1'/g;
      The solution you added in the update doesn't work.
      $string =~ s/(_)[^']/$1'/g;
      should be
      $string =~ s/(_)([^'])/$1'$2/g;
      That can also be written as
      $string =~ s/(_)(?=[^'])/$1'/g;
      $string =~ s/_\K(?=[^'])/'/g; # 5.10+
      No, sorry ... this won't work either. However, you could not know because my example indeed would permit the simplification you suggest. The regex cannot be simplified to (_)[^']) since a) single quotes can also occur inside a string and b) I only know that the end of the string has been reached when the next underscore is reached. Another input string might be my $string = "_na'da_komo_el_so'l_"
Re: Modifying the match position after each match
by Anonymous Monk on Mar 23, 2010 at 21:01 UTC
    use re 'debug';
    and you'll see exactly what gets matched, then you can fix your regex
      Nice idea but no ... that doesn't help. The regex is exactly what I need and requires no fixing. The problem is that multiple matches overlap in one character.
Re: Modifying the match position after each match
by 7stud (Deacon) on Mar 23, 2010 at 22:14 UTC

    Some other variations:

    use strict; use warnings; use 5.010; my $string = "_'nada_komo_el_'sol_"; $string =~ s/_'?(.)/_'$1/g; say $string; --output:-- _'nada_'komo_'el_'sol_


    use strict; use warnings; use 5.010; my $string = "_'nada_komo_el_'sol_"; my @pieces = split /_'?/, $string; say join(q{_'}, @pieces); --output:-- _'nada_'komo_'el_'sol
      I believe that I need to include executable Perl code in the regex to reduce the match position variable after each matching string. Then ALL substrings of format _[^']+?_ should be matched:
      #! /usr/bin/perl -w use strict; use locale; my $string1 = "_'nada_komo_el_'sol_"; my $string2 = "_na'da_komo_el_so'l_"; $string1 =~ s/(_)([^']+?)(_)(?{pos($string1) --})/$1'$2$3/go; $string2 =~ s/(_)([^']+?)(_)(?{pos($string2) --})/$1'$2$3/go; print "String 1: $string1 \n"; print "String 2: $string2 \n";

      But somehow, this is not working for me and I get
      --output:-- String 1: _'nada_'komo_el_'sol_ String 2: _na'da_'komo_el_so'l_
      Any ideas as to why this is happening?

      Your wisdom is much appreciated ...


        You're working much to hard:

        #! /usr/bin/perl -w use strict; use locale; for my $s ( @{[ "_'nada_komo_el_'sol_", "_na'da_komo_el_so'l_" ]} ) { print $s; $s =~ s/(_)([^'][^_]+?)/$1'$2/g; print " : $s\n"; } __END__ C:\test>junk57 _'nada_komo_el_'sol_ : _'nada_'komo_'el_'sol_ _na'da_komo_el_so'l_ : _'na'da_'komo_'el_'so'l_

        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: Modifying the match position after each match
by MidLifeXis (Monsignor) on Mar 24, 2010 at 10:51 UTC

    Two suggestions based on discussion from CB:

    while ($string =~ qr(...)) { $string = qq($1'$2); }


    $string = join('_', map { ( $_ && ( $_ !~ qr(') ) ) ? qq('$_) : $_ } split( q{_}, $string ) );

    The first, I think, is O(N^2), and the second is O(N), so depending on string size, data set size, etc, the choice might make a difference.

    My wife is walking for a cure for MS. Please consider supporting her.

Re: Modifying the match position after each match
by jacaril (Beadle) on Mar 24, 2010 at 13:59 UTC
    #! /usr/bin/perl -w use strict; use locale; my $string = "_'na'da_komo_el_'sol_"; $string =~ s/(_)'?(\w)/$1'$2/g; print "$string\n";
    Output: _'na'da_'komo_'el_'sol_ Why even bother capturing the single quotes in the string that are were you want them when you're going to insert them anyway?

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://830400]
Approved by toolic
Front-paged by MidLifeXis
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (9)
As of 2017-03-29 14:23 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (351 votes). Check out past polls.