Beefy Boxes and Bandwidth Generously Provided by pair Networks Frank
Perl: the Markov chain saw

Extract sequence of UC words?

by Anonymous Monk
on Aug 18, 2008 at 13:45 UTC ( #704929=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm try to extract a sequence of upper case words. Using the following code works for just one word though. How do I modify my regex telling it to grab all instances of UC words in a row?
my $data = 'this is a TEST SENTENCE Foo Bar'; my $uc_string = $1 if ($data =~ /([A-Z]+)\b/); # This grabs 'TEST' but not 'TEST SENTENCE' ???

Comment on Extract sequence of UC words?
Download Code
Re: Extract sequence of UC words?
by amarquis (Curate) on Aug 18, 2008 at 13:56 UTC

    It grabs only one word because you are matching for a sequence of upper case letters only. To have it match 'TEST SENTENCE' you'll have to have it match upper case letters OR spaces.

    But wait! The regex will then actually match ' TEST SENTENCE ' (including the space before and after the capitalized sequence). So what you really need is to make a match of:

    1. One upper case letter
    2. Any number of upper case letters/spaces
    3. One upper case letter

    The requirement to match a beginning and ending upper case letter will also make it not match just the 'F' of 'Foo'.

    Edit: gaal is smarter than I, heh.

      Thanks, I modified it like so:
        | and + inside a character class aren't special, they're just regular characters, so your regex would match "FO O|B+++A R". /[A-Z ]+/ (which is what I think you probably meant) won't work either.

        Bonus points will be given if you tell us why!

        Update: BrowserUK has already seen what was missing. You missed out AnonyMonk

        Note that the regex expression  [A-Z\|\s+] defines a set of characters that includes the '|' ('pipe') character. Within a character set, the pipe has no special meaning; i.e., it is not the regex alternation metacharacter.
Re: Extract sequence of UC words?
by gaal (Parson) on Aug 18, 2008 at 13:57 UTC

    Though you should note that A-Z misses out on accented characters. This is a little more i18n-friendly (not tested):

    use charnames ":full"; \b([\p{IsUpper}\s]+)\b

      This doesn't work because the space in the character class means it matches the first single space in the line and returns that. You need to ensure that the match starts with an UPPER alpha, and then continues with UPPER alpha or space:

      print $data =~ m/(\b[A-Z][A-Z ]+\b)/;; TEST SENTENCE

      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.

        Thou art wise brother BrowserUk. I was just about to comment that I see a lot of non-working solutions;-) Alas my votes for today are gone.

        Thanks for the correction!

        Unfortunately this would also match "TEST SENTENCE " (note the trailing whitespace).

        The following test illustrates another method:

        #!/usr/bin/perl -w my $data = <<'EOF'; This is a sentence. THIS \ IS A SENTENCE. This is \ a SEQUENCE OF UPPER WORDS and \ this is not. EOF while ( $data =~ m/(\b(?:[A-Z]+(?:\s+[A-Z]+)*)+\b)/g ) { print "Upper Sentence: \"$1\"\n"; }


        Upper Sentence: "THIS IS A SENTENCE" Upper Sentence: "SEQUENCE OF UPPER WORDS"
Re: Extract sequence of UC words?
by massa (Hermit) on Aug 18, 2008 at 14:27 UTC
    Use the /g modifier.
    $ perl -Mutf8 -mopen=:locale -e ' my $data = "this is a TEST SENTENCE Foo Bar GRUB jo аз co"; my @uc_strings = $data =~ /\b\p{Lu}+\b/g; print "@uc_strings\n"; ' TEST SENTENCE GRUB аз
    []s, HTH, Massa (κς,πμ,πλ)
Re: Extract sequence of UC words?
by broomduster (Priest) on Aug 18, 2008 at 14:30 UTC
    Do you really mean "a sequence of upper case words"? Or do you mean "all of the upper case words in a string"? To see what I'm getting, consider:
    my $data = 'THIS IS a TEST SENTENCE Foo BAR';
    If you mean "a sequence of upper case words", the answer would be the following three strings (maybe not including the last, if your definition of sequence means "strictly more than one"):
    Other responses in this thread point you at a solution for this.

    OTOH, if you mean all upper case words (and want to collect them separately), then you want the following five words:

    In that case, look into the g modifier for regular expressions and how to capture multiple matches into an array (using parens to capture the matches you like; see perlretut for a nice introduction). The basic idea (you need to supply the right regex for your needs) is:
    my @uc_words = $data =~ /(appropriate_regex_goes_here)/g;
Re: Extract sequence of UC words?
by JavaFan (Canon) on Aug 18, 2008 at 16:22 UTC
    What I would use depends on your definition of "word" and "sequence". Clearly, in your example, "TEST" and "SENTENCE" are capitalized words. But is "STRATFORD-UPON-AVON" a capitalized word? How about "HE'S"? Is that a capitalized word? Or a sequence of capitalized words? What about "This is a TEST. THE test ends here."? Is "TEST. THE" a sequence of words?
Re: Extract sequence of UC words?
by logie17 (Friar) on Aug 18, 2008 at 16:38 UTC
    I think you're close but you'll probably have better luck using /g modifier in list context. The following gets the results for me:
    my @uc_string = ($data =~ /(\b[A-Z]+\b)/g);
    s;;5776?12321=10609$d=9409:12100$xx;;s;(\d*);push @_,$1;eg;map{print chr(sqrt($_))."\n"} @_;

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (13)
As of 2014-04-16 20:55 GMT
Find Nodes?
    Voting Booth?

    April first is:

    Results (434 votes), past polls