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

I need to split a string on the pattern of '),(', but have not been successful so far.

$str = '(1,"(text)", 123),(2,"(string)", 234),(...)'; @arr = split(/),(/, $str); # fail @arr = split(/\),\(/, $str); # fail
I've tried several other ways I can think of, but all failed.

Replies are listed 'Best First'.
Re: split on the pattern of '),('
by kennethk (Abbot) on Jun 07, 2012 at 19:47 UTC
    If you need to escape characters in a regular expression, you can reliably use either the quotemeta function or the delimiters \Q and \E, as described in Quote and Quote like Operators. For example, you would successfully split with my @arr = split /\Q),(\E/, $str;.

    On examining your input, it's possible you'll get more mileage from either a state machine character-wise parser, a regular expression, or my favorite in this context, multiple operations including a different basic split. Since you appear to be separating tuples, you could use my @arr = split /(?<=\))\s*,\s*(?=\()/, $str; to separate the tuples, and then deal with each one individually.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: split on the pattern of '),('
by snape (Pilgrim) on Jun 07, 2012 at 20:13 UTC

    I don't know why it is not working for you but piece of code below works for me

    my @arr = split(/\),\(/, $str);

    I have used strict and warnings and here is my entire code. It also works if you didn't use strict or warnings.

    #!/tools/bin/perl use strict; use warnings; my $str = '(1,"(text)", 123),(2,"(string)", 234),(...)'; my @arr = split(/\),\(/, $str); for(my $i = 0; $i<= $#arr; $i++){ print $arr[$i],"\n"; } exit; ##### OUTPUT #### (1,"(text)", 123 2,"(string)", 234 ...)

    Try running the above code

Re: split on the pattern of '),('
by ikegami (Patriarch) on Jun 07, 2012 at 21:23 UTC

    Assuming nesting (e.g. (3,(4,5),6)) can't happen,

    my @recs = $recs =~ / \G \( ( (?: [^()"] | "[^"]*" )* ) \) (?: , | \Z ) /xg;
      my $string = "(foo),(bar),(baz)"; my @parts = split m{ [)] [,] [(] }x, $string; print "GOT: $_\n" for @parts;

      Instead of m{ [)] [,] [(] }x you could use m{ \) , \( }x ... whichever you think is most readable. Either way, try to avoid the appearance of a million toothpicks standing on end.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
        That fails for
        $str = '(1,"(text),(text)", 123),(2,"(string)", 234),(...)';
Re: split on the pattern of '),('
by Anonymous Monk on Jun 07, 2012 at 19:36 UTC

      It is "workable" but kinda meh

      #!/usr/bin/perl -- use strict; use warnings; use Text::CSV; use Data::Dump; my $str = '(1,"(text)", 123),(2,"(string)", 234),(...)'; my $csv = Text::CSV->new( { quote_char => '"', sep_char => ',', allow_loose_escapes => 1, empty_is_undef => 1, binary => 1, auto_diag => 1, } ); $csv->parse( $str ); dd [ $csv->fields() ]; __END__ ["(1", "(text)", " 123)", "(2", "(string)", " 234)", "(...)"]
Re: split on the pattern of '),('
by AnomalousMonk (Archbishop) on Jun 08, 2012 at 07:39 UTC