Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate that a string only contain lowercase letters?

I'm trying to verify that my string matches a pattern. That is, the full string can be written as that pattern. However preg_match returns true, if any substring matches that pattern. (E.g. preg_match("#[a-z]*#, "333k") returns 1, which I don't want to. In this example I'd rather verify, the whole string contains only small Latin letters.)

like image 976
user2089648 Avatar asked May 04 '13 15:05

user2089648


3 Answers

You use the start and end markers, ^ and $ respectively, to indicate beginning and end of the string in your regular expression pattern. That way you can make the expression match only the whole string, not any kind of substring. In your case it would then look like this:

preg_match("#^[a-z]*$#", "333k");

You can also, with one these markers, specify that the pattern must only match the beginning or the end of the string.

like image 65
pilsetnieks Avatar answered Nov 06 '22 16:11

pilsetnieks


I super-love regex, but not for this task -- it is needless overhead because there is a single, direct, non-regex equivalent. https://www.php.net/manual/en/function.ctype-lower.php

Code: (Demo)

$tests = [
    'Test',
    'test',
    'test1',
    '1test',
    'test!'
];
foreach ($tests as $test) {
    echo "$test: " , (ctype_lower($test) ? 'true' : 'false') , "\n";
}

Output:

Test: false
test: true
test1: false
1test: false
test!: false

p.s. For the record, an empty string returns false. I'm not sure of your logical validation requirements for this test unit.

like image 28
mickmackusa Avatar answered Nov 06 '22 16:11

mickmackusa


Note that the $ anchor also matches before the line break char sequence that is at the very end of the string (yes, even if m MULTILINE flag is not specified). See these tests, all returning a match:

if (preg_match("#^[a-z]*$#", "ok")) echo "OK!\n"; // => is OK!
if (preg_match("#^[a-z]*$#", "ok\n")) echo "OK!\n"; // => is OK!
if (preg_match("#(*ANY)^[a-z]*$#", "ok\r\n")) echo "OK!"; // => is also OK!

You may "fix" this $ behavior by using the D modifier. The PCRE-compliant PCRE_DOLLAR_ENDONLY modifier makes the $ anchor match at the very end of the string (excluding the position before the final newline in the string).

/^\d+$/D

is equal to

/^\d+\z/

and matches a whole string that consists of 1 or more digits and will not match "123\n", but will match "123".

Alternatively, to anchor the string match at the very start and end of the string you might also consider using \A and \z anchors.

preg_match('~\A[a-z]*\z~', "333k");
             ^^      ^^

The \A and \z are unambiguous start and end of string anchors in PHP regex (as their behavior does not depend on any regex modifiers, even if you specify the m MULTILINE modifier, they will keep on asserting string start/end positions). See more on PHP regex anchors in PHP documentation.

Beware of \Z though: \Z will match the whole string before the last single linebreak, whereas \z will only match at the very end of the string, that is, after all the characters there are in the string (see Whats the difference between \z and \Z in a regular expression and when and how do I use it?)

like image 41
Wiktor Stribiżew Avatar answered Nov 06 '22 16:11

Wiktor Stribiżew