Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Substituting a comma only when it is preceded and followed by a bracket

by barraclm (Initiate)
on Nov 02, 2011 at 16:54 UTC ( #935441=perlquestion: print w/ replies, xml ) Need Help??
barraclm has asked for the wisdom of the Perl Monks concerning the following question:

I have a string that looks like this:

blah blah, blah blah blah (blah, blah, blah), blah, blah

I want to change the commas inside the parentheses into something else, say a semi-colon so that the string looks like

blah blah, blah blah blah (blah; blah; blah), blah, blah

There may or may not be commas either before or after the parentheses and there could be any number of commas inside the parentheses. The text on either side and inside of the parentheses is also completely variable.

Any help would be very much appreciated.

Comment on Substituting a comma only when it is preceded and followed by a bracket
Re: Substituting a comma only when it is preceded and followed by a bracket
by BrowserUk (Pope) on Nov 02, 2011 at 16:59 UTC

    One way:

    $s = 'blah blah, blah blah blah (blah, blah, blah), blah, blah';; $s =~ s[ ( \( [^)]+ \) ) ][ ( my $x = $1 ) =~ tr[,][;]; $x ]gex;; print $s;; blah blah, blah blah blah (blah; blah; blah), blah, blah

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    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.
      It does not work for nested parentheses:
      $s='aa, aaa, aaaa, aaa, (aaa, aaa, aaa, a), aaa, aaa, (aaa, aaa, (aaa, + aa), aaa, aaa), aaa, aaa';
      The specification is unclear in this regard.
        The specification is unclear in this regard.

        I think the specification is very clear and has all the appearance of being thorough. I took it to be so.

        Whilst is doesn't mention that there won't be nested parens, it also doesn't mention that the commas might one of the Unicode variants (eg.(U+060C)). Either would be a significant fact worthy of mention.

        For example, what would you do with commas inside the outer parens, but outside the inner ones?


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.
      Thank you for this response which was both fabulously quick and which worked just perfectly. Thank you also to everyone else who contributed. For the record, thankfully, I do not have to deal with nested parentheses!

      So, being very greedy, but mainly because I want to learn and not have to resort to Perl Monks (too often), please could someone help me understand how the answer

      s[ ( \( ^)+ \) ) ][ ( my $x = $1 ) =~ tr,;; $x ]gex;;

      works.

        Does this help you?

        s[ ( ## Capture \( ## from an open paren [^)]+ ## all non-close paren chars \) ## upto the close paren ) ][ ## assign the captured text ## to a local variable so that it can be edited ## and then replace all ,s with ;s ( my $x = $1 ) =~ tr[,][;]; ## and return the modified text to replace that captured. $x ] g ## globally e ## execute the replace as code x; ## extended notation to allow whitespace and comments

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        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.
        YAPE::Regex::Explain

        Familiarity with the resources found in docs on the internet (and, in many cases, on your own machine) can help you achieve your stated goal, "...not have to resort to Perl Monks (too often)....".

        So, right at your desk, perldoc -f function_name and perldoc modulename are invaluable. But, first, it'll also be worth your time to explore perldoc perldoc, (for help on how to use perldoc) and perldoc perltoc second... for the kinds of documentation available.

Re: Substituting a comma only when it is preceded and followed by a bracket (closure)
by tye (Cardinal) on Nov 02, 2011 at 17:22 UTC
    my $l= ''; $s =~ s{([(,)])}{ my $n= ',' eq $1 && '(' eq $l ? ';' : $1; $l= $1 if ',' ne $1; $n }ge

    - tye        

      Does not work for nested parentheses *ducks*
      $s='aa, aaa, aaaa, aaa, (aaa, aaa, aaa, a), aaa, aaa, (aaa, aaa, (aaa, + aa), aaa, aaa), aaa, aaa';

        Ah, but I guess it beats BrowserUk's solution because it must be clearer that it doesn't work for nested parens else you wouldn't have left his un-replied-to for 22 minutes but replied to mine in 5 minutes when both fail for that same case. q-:

        - tye        

Re: Substituting a comma only when it is preceded and followed by a bracket
by hbm (Hermit) on Nov 02, 2011 at 18:03 UTC

    Another way (if parens aren't nested):

    $s = 'blah blah, blah blah blah (blah, blah, blah), blah, blah'; $s =~ s#,(?=[^(]*\))#;#g; print $s; blah blah, blah blah blah (blah; blah; blah), blah, blah
Re: Substituting a comma only when it is preceded and followed by a bracket
by JavaFan (Canon) on Nov 02, 2011 at 22:52 UTC
    Untested:
    my $str = do {my $i; join "", map {$_ eq '(' ? $i++ : $_ eq ')' && $i +? $i-- : $_ eq ',' && $i ? ($_ = ';') : 0; $_} split '[(,)]', $str};
    This assumes the parenthesis are balanced.

    But what should happen on:

    "(foo),(bar)"
    ? The comma here is preceded and followed by a bracket - preceded by an opening paren, and followed by a closing paren even. If such a comma should be replaced as well, one might use something like (untested):
    substr($str, index($str, "("), rindex($str, ")") - length($str)) =~ s/ +,/;/g;
Re: Substituting a comma only when it is preceded and followed by a bracket
by Logicus on Nov 03, 2011 at 01:54 UTC
    use Modern::Perl; $_= 'blah blah, blah blah blah (blah, blah, blah), blah, blah'; while($_=~ s@\(([^\)]*?)h,@\($1h;@gs){} say;
    Output : blah blah, blah blah blah (blah; blah; blah), blah, blah
    Not quite what was asked for, but it does produce the requested output :P

      Here's the proper one;

      while($_=~ s@\(([^\)]*?),@\($1;@gs){}
        Oh hang on, ok there was no check to see if the comma was followed by a bracket, so if there was no close bracket, it would replace every comma to the right of the open bracket, which technically would be incorrect because the task specified there to be a following bracket and a single bracket by itself would not count. However as long as the two brackets are there it works fine.
Re: Substituting a comma only when it is preceded and followed by a bracket
by Anonymous Monk on Nov 03, 2011 at 02:14 UTC
      No

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://935441]
Approved by Corion
Front-paged by sparkyichi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2014-10-22 00:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (112 votes), past polls