1

I want a variable that allow letters and only, not digits.

And that variable can be at any position in the string.

Look at this,

$pattern = '~user/(:var)~';

$pattern = str_replace('(:var)', '([a-zA-Z])', $pattern);

// Note, the variable contain both numbers and letters
$test = 'user/dave123';

$r = preg_match($pattern, $test); 

var_dump($r); //1 Success (I don't want this)

All I want is,

If a variable contain letters only, then preg_match() should return 1, but if that one contains at least one digit, then preg_match() should immediately return 0,

What regex should be defined instead of ([a-zA-Z]) and why ([a-zA-Z]) matches both numbers and letters!?

Yang
  • 8,580
  • 8
  • 33
  • 58

4 Answers4

6

The regular expression is matching this substring of your test value: user/d.

If you want to check against the whole string, add start (^) and end ($) anchors to your pattern:

$pattern = '~^user/(:var)$~';

To check against the start/end of a string OR another delimiter such as /, it would look like this:

$pattern = '~(?:^|/)user/(:var)(?:$|/)~';

This will force it to consider the entire value up until either the end of the string or the next /... preventing partial matches like you encountered in your question.

(The ?: indicates a non-capturing group, which means that the extra () groups won't end up in your resulting list of matches)

You'll also need to allow the [a-zA-Z] class to repeat with +, or it will only match single-character usernames:

$pattern = str_replace('(:var)', '([a-zA-Z]+)', $pattern);
Community
  • 1
  • 1
jcsanyi
  • 8,133
  • 2
  • 29
  • 52
  • Well, `(:var)` can be at any position, not only in the in the end, therefore I cannot rely on `$` – Yang Jun 17 '13 at 04:31
  • `/post/(:var)/comment/(:var)/replyid/(:var)`, how about this? – Yang Jun 17 '13 at 04:34
  • Thanks for clarification, it works as expected! I'm writing a router that accept both static and dynamic `URI` segments, so I'm still having troubles with `(:var)` in random position in the `URI` string. Couldn't please direct me in the right direction, what can be done about it? – Yang Jun 17 '13 at 05:14
  • @metal_fan, if this particular problem is solved, it's probably simpler to post a new question with an updated example incorporating what you learned in this question, and illustrating the problems you're still having. – jcsanyi Jun 17 '13 at 05:18
3

You need to give starting the ending using ^ and $ respectively.

'~^user/(:var)$~'

It matches because, you have user, dave in your string.

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
1

Your pattern means "one of any character between a-z or A-Z", which is why it matches. It doesn't offer a check to see if it is the only thing that matches, and it will not match repeated characters.

Instead of that approach, why not try something simpler. Since all you want to know is if the string contains a number or not:

$haystack = 'user/dave123';
foreach(range(0,9) as $i) {
    if (strpos($haystack,$i) === FALSE)) {
         return 1;
    }
}
return 0;

This will stop at the first number that is found.

Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
0

It's possible that the pattern is matching against the first character in the string and no against the whole string. To match against the whole string, try

"/^[a-z]+$/i"

which should give you a case insensitive letter only match on the whole string (^ and $ are start of string and end of string delimiter characters).

There are also some handy inbuilt PHP functions like ctype_alpha() which do exactly the same thing.

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
  • Not possible, inevitable. ;) I'm assuming the space between the `]` and `+` was a typo because the regex makes no sense with it there. You left out the opening `/`, too. – Alan Moore Jun 17 '13 at 05:29
  • BTW, the OP is now saying the match won't always occur at the end of the string, so the `$` won't do. – Alan Moore Jun 17 '13 at 05:34