Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Another for those who love the Regular Expression questions...

by Hot Pastrami (Monk)
on Aug 14, 2000 at 23:35 UTC ( [id://27815]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings and hello, my dear friends!

This morning I finally ordered "Mastering Regular Expressions," so perhaps I can begin a less failure-riddled campaign in learning the uglies of Regular Expressions. It won't arrive for a week, though, so I wonder if soebody wouldn't mind fielding this one in the interim:

Let's say I have the following string:
$string = qq|Are "Perl Monks" required to swear an "Oath of Celibacy?" +|;
...and I need to break it down as such:
[0] Are [1] Perl Monks [2] required [3] to [4] swear [5] an [6] Oath of Celibacy?
It basically needs to be split on spaces, but keep quoted strings together. I'm sure there is an alarmingly simple solution which my unspeakable ignorance has caused me to overlook, and perhaps one of you could point it out in some embarrassing way. You'll have my gratitude, as always.

Alan "Hot Pastrami" Bellows
-Sitting calmly with scissors-

Replies are listed 'Best First'.
Re: Another for those who love the Regular Expression questions...
by merlyn (Sage) on Aug 14, 2000 at 23:37 UTC
      Say, you're right! Except it's in Text::ParseWords rather than Shell::ParseWords, but you pointed me in the right direction. I owe you a beer, man.

      Alan "Hot Pastrami" Bellows
Re: Another for those who love the Regular Expression questions...
by turnstep (Parson) on Aug 14, 2000 at 23:58 UTC
    Here's one way:
    $x=0; $in=0; $string =~ s#(")?([^" ]+)(")?# if ($in) { print $2; if ($3) { print "\n"; $in=0; } else { print " "; } } else { print "[".$x++."] $2"; if ($in=$1) { print " ";} else { print "\n"; } } #egx;

    Could be more compact probably, but I left it "apart" for easier viewing. :)

      That's pretty good, but what if I tried to escape a quote with a backslash?
      qq|look, these "words" are \"quoted\"!|; # results # [0] look, [1] these [2] words are quoted [3] !
      It's probably a recursive check, which makes it very tough to do as a regex. (Hey, I'm not complaining about your solution, just making sure that people realize a regex won't catch all cases here!)

        Oh sure, change the data after the question has been answered! :)

RE: Another for those who love the Regular Expression questions...
by tye (Sage) on Aug 15, 2000 at 00:13 UTC

    I wasn't going to reply after merlyn took all the fun out of it by pointing at somebody else's wheel. (: Beside, the first thing that popped into my head required that you have a character that you knew wasn't in the string (a sure sign of a bad hack). Then I had a flash...

    s#"([^"]*)"# my $i= $1; $i =~ tr/ /"/ #ge; my @list= grep { tr/"/ / || 1 } split / +/;

    Note that this has several disadvantages over a good module:

    • You can't escape quotes (neither inside nor out).
    • Unmatched quotes are silently processed in a rather strange way.
    • tabs do not separate fields.
    • Only one type of quoting is supported.

    So it is probably still a bad hack.

            - tye (but my friends call me "Tye")
(Ovid) Re: Another for those who love the Regular Expression questions...
by Ovid (Cardinal) on Aug 15, 2000 at 00:07 UTC
    Here's my hand at it:
    while ($string =~ /([^"]*)"([^"]*)"(.*)/g) { push @result, ((split " ", $1), $2); $string = $3; } push @result, split " ", $string if $string;
    Cheers,
    Ovid
Re: Another for those who love the Regular Expression questions...
by cwest (Friar) on Aug 15, 2000 at 04:31 UTC
    For the record, I know this won't catch escaped quotes, but.. it solves the problem at hand.

    I did this just to show that a quick hack is possible, even in a one liner... I love map.

    my $string = q|Are "Perl Monks" required to swear an "Oath of Celibacy +?"|; my @broken = map { /"([^"]+)"/ ? $1 : split } split /\s?([^"]+")\s?/, + $string; print "[$_] $broken[$_]\n" foreach 0 .. $#broken;
    Enjoy!
    --
    Casey
    
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Another for those who love the Regular Expression questions...
by Maqs (Deacon) on Aug 15, 2000 at 13:41 UTC
    @parts = grep /\w/, (split /\"([^\"]*)\"|\s/, $string);


    /Maqs.
A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://27815]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2024-03-28 14:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found