This is turning out to be quite a tricky problem to solve with regular expressions. There's really no way of storing "state" information when doing regular expression parsing, except by accounting for in it the pattern that you write.
The best I've been able to come up with so far in terms of a single RE pattern isn't pretty. It uses alternation extensively, and basically accounts for all 6 permutations of "upper case," "lower case," and "digit" matches. Note that there are line breaks in this only because of Tek-Tips line length limit. This is really a single-line pattern:
Code:
set pat {[A-Z].*(?:[a-z].*\d|\d.*[a-z])|[a-z].*(?:\d.*[A-Z]|[A-Z].*\d)|\d.*(?:[A-Z].*[a-z]|[a-z].*[A-Z])}
*bleah* I used some Tcl 8.1+ RE features to make it a little shorter and a little more efficient. So you'll have to re-write it a bit if you're using it on a pre-8.1 interpreter.
Here's a few tests of it:
[tt]%
regexp $pat "This is 1 test."
1
%
regexp $pat "This is another"
0
%
regexp $pat "another 1"
0[/tt]
I can't say as that I'm really confident enough in it to guarantee that it will work properly in all cases, but I think it would do the job.
It's going to be easier -- and probably more efficient -- if we break it down into 3 separate REs, each testing for only one thing:
Code:
if {[regexp {\d} $str]
&& [regexp {[a-z]} $str]
&& [regexp {[A-Z]} $str]} {
puts "Valid"
} else {
puts "Invalid"
}
That's the best I could come up with so far. There's probably some glaringly obvious solution that I'm overlooking, though... - Ken Jones, President, ken@avia-training.com
Avia Training and Consulting,
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax