4
\$\begingroup\$

I want to write a regular expression to determine whether a given string is uppercase and sorted in non-descending order.

^A*B*C*D*E*F*G*H*I*J*K*L*M*N*O*P*Q*R*S*T*U*V*Q*X*Y*Z*$

I was just wondering if it is possible to improve the above regex.

Examples of correct strings:

AEHII
EFKLZ

Examples of wrong strings:

AbCDE
YABKL

\$\endgroup\$
3
  • 3
    \$\begingroup\$ I want to write a regular expression ... now you have 2 problems. :) What do you want to improve? A working solution for UTF-8 like ÄÖÜ? \$\endgroup\$ Jan 26, 2012 at 13:50
  • \$\begingroup\$ @userunknown No I want to know if it's possible to have a shorter solution \$\endgroup\$
    – B Faley
    Jan 26, 2012 at 14:16
  • \$\begingroup\$ @Meysam he means that your Regex might not address all problems. Example: is AÖU a correct string, or an incorrect one? What about ? And ÄA? \$\endgroup\$
    – ANeves
    Jan 27, 2012 at 17:04

3 Answers 3

6
\$\begingroup\$

There is no shorter solution. Because you are enforcing order, you must list every single entity in desired order. And because you are allowing zero to many instances of each entity, you must provide the * operator. And because you want to match the entire string, you must provide the anchors on both ends.

Could you write one that runs faster? Possibly. But shorter? I don't see how.

\$\endgroup\$
5
\$\begingroup\$

No.

There is no way to express

(xy)* | ∀(x, y) => x <= y ∧ (x, y) ∈ {A..Z}

with regular expressions in such an abstract way, at least not in popular regex usage I'm aware of. So you have to enumerate all characters explicitly.

\$\endgroup\$
4
  • \$\begingroup\$ I agree that you cannot do this for the general case, but it certainly seems like the regex provided in the question would achieve this for the specific case cited. Could you please elaborate? \$\endgroup\$
    – jdmichal
    Jan 26, 2012 at 14:36
  • \$\begingroup\$ @jdmichal: Meysam uses a shorter expression. (Ok, I correct my answer to claim 'in a shorter way') This would be possible, if it would be possible to say we have an arbitrary number of pairs of characters, such that for each first of them, the first one is smaller or equals to the following (in the meaning of first in ordering). \$\endgroup\$ Jan 26, 2012 at 15:24
  • \$\begingroup\$ @userunknown I really love this answer, but it does not address that the characters must be upper-case. \$\endgroup\$
    – ANeves
    Jan 27, 2012 at 17:06
  • \$\begingroup\$ Well - I concentrated on the part, which is not elegantly expressible with regex. Is it better now? [A-Z] is easy to express with regex. \$\endgroup\$ Feb 3, 2012 at 15:13
2
\$\begingroup\$

As already pointed out by @userunknown, there is no way to simplify your regular expression from a purist point of view.

However, if you're using Perl, here's one way to do it that doesn't involve explicitly writing out all the letters A to Z.

my $uppersorted = "^" . join("", map {"$_*"} ('A'..'Z')) . "\$";

Making that into a compiled regex:

$uppersorted = qr/$uppersorted/;

Testing it with the given input cases:

my @tests = ("AEHII", "EFKLZ", "AbCDE", "YABKL");

foreach my $test (@tests) {
    printf "%s: %s\n",
        $test,
        $test =~ $uppersorted? "YES" : "NO";
}
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.