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

How do I match a line that contains only all-cap letters and no numbers?

Replies are listed 'Best First'.
Re: Recognizing all-caps line
by Happy-the-monk (Canon) on Oct 27, 2004 at 21:27 UTC

    Try either of the following:

    $line =~ m/^[[:upper:]]+$/    # or
    $line =~ m/^\p{IsUpper}+$/

    the [: ... :] is no character class, although it looks like one.
    To make it (part of) a character class, you need another set of brackets around it.

    don't go for   m/^[A-Z]+$/   for world peace international reasons ;-)
    See   perldoc perlre   too.

    Update: You might find the double negation more convenient:

    $line !~ m/[[:^upper:]]/    # or
    $line !~ m/\P{IsUpper}/

    (think: do not match a line that contains anything that's not an uppercase letter)


    Edit: corrected a number of mistakes.
    Thanks especially to davido(++) for pointing out the ones I didn't find myself. Strange enough, while the necessity of the double brackets is not in doubt, I don't get any warnings when omitting them (perl5.8.3, Linux), the code just never tests true.
    Another Edit: I guess that's because it looks like a character class to Perl. So why did it throw errors when davido tried it?
    Another edit (and moved this discussion to the bottom of the node) -
    I tried   m/[:^upper:]/;   which bypasses warnings.
    Congratulations to us, we found a bug.

    Cheers, Sören

      Happy-the-monk has it right, that this is better done by posix character classes rather than enumerated-alphabet character classes. The problem with a [A-Z] character class is that it may exclude some perfectly legitimate upper-case characters in non-ASCII character encodings.

      The solution is POSIX character classes that do understand what constitutes an upper-case character in non-ASCII character encoding.

      There are a couple errors in Happy's response though. First, [:lower:] should be [:upper:] in order to match upper case characters, as the OP's question asked. Update: Looks like that first problem was fixed in an update.

      Second, the POSIX character class identifier has to be placed inside of a character class, leading to what might seem like a little bit of a wierd syntax, but is nevertheless necessary. Hense, the following:

      m/^[:upper:]+$/

      ... will fail to match, and will generate a warning if use warnings is active (Updated), whereas ...

      m/^[[:upper:]]$/

      will do what you want.


      Dave

Re: Recognizing all-caps line
by grinder (Bishop) on Oct 27, 2004 at 21:16 UTC

    You could start by reading the documentation. The first place to start looking would be perlre.

    Your question is a little ambiguous, because you say "all-cap letters" and "no numbers". What of the rest of the character set that is neither a letter (uppercase or not) or a digit?... Spaces, punctuation, control characters and so forth.

    Be that as it may, a nudge in the right direction would be something like:

    if( $line =~ /^[A-Z]+$/ ) { # matched } else { # did not match }

    You may have to amend the character class in order to achieve exactly what you want.

    - another intruder with the mooring of the heat of the Perl

      Read the documentation? That's crazy talk, why would anyone want to do that when they can get tech support here for free?
Re: Recognizing all-caps line
by hardburn (Abbot) on Oct 27, 2004 at 21:14 UTC
    if( ($line eq uc $line) && ($line !~ /\d/) ) { . . . }

    Update: Oops, had the match condition the wrong way around, as the replies noted.

    "There is no shame in being self-taught, only in not trying to learn in the first place." -- Atrus, Myst: The Book of D'ni.

      $line =~ /\d+/

      Nice variant. In some ways it better matches the spec than my offering, but you got the conditional the wrong way round. You want $line !~ /\d/ methinks (and the + is not necessary, one is all you need to make it fail).

      - another intruder with the mooring of the heat of the Perl

      you do, of course, mean ...
      && $line !~ /\D/
Re: Recognizing all-caps line
by olivierp (Hermit) on Oct 27, 2004 at 21:21 UTC
    perl -ne 'print "A number or a non-capital ASCII letter has been found + at position " . pos() ." . There may be more.\n" if /[a-z0-9]/g'
    HTH
    --
    Olivier
Re: Recognizing all-caps line
by TedPride (Priest) on Oct 28, 2004 at 02:08 UTC
    I'm assuming the line can contain characters that aren't letters, and that you just want to make sure there are no lowercase letters or numbers:
    while (<DATA>) { print if $_ !~ /[[:lower:]\d]/; } __DATA__ THIS LINE IS ALL CAPS THIS LINE IS CAPS WITH 012 THIS LINE has lowercase THIS LINE has lowercase and 012
    (if he'd meant that the line should only contain capital letters, he wouldn't have mentioned the no numbers part)
Re: Recognizing all-caps line
by gube (Parson) on Oct 28, 2004 at 14:59 UTC

    if you are interested you can try this also

    $str = "AdfsADSFsdaf232\nASFD\nFJADS\n"; @arr = split("\n", $str); for $arr(@arr) { if (($arr =~ /^\U$arr$/g)) { print "\n$arr"; } }