34

Is there a good way of test if a string is a regex or normal string in PHP?

Ideally I want to write a function to run a string through, that returns true or false.

I had a look at preg_last_error():

<?php
preg_match('/[a-z]/', 'test');
var_dump(preg_last_error());
preg_match('invalid regex', 'test');
var_dump(preg_last_error());
?>

Where obviously first one is not an error, and second one is. But preg_last_error() returns int 0 both times.

Any ideas?

9
  • 2
    Maybe you could use a regex for the test ^^ Commented May 28, 2012 at 0:52
  • 2
    'invalid regex' is a valid regex - in fact, any string that doesn't involve the regex special characters will be a valid regex. Try '[' instead. Commented May 28, 2012 at 0:52
  • 3
    To those that care: '[' is not a valid regex, therefore not all strings are valid regexs. Commented May 28, 2012 at 0:54
  • 2
    @AasmundEldhuset, 'invalid regex' is actually not a valid regex, PHP returns Warning: preg_match() [function.preg-match]: Delimiter must not be alphanumeric or backslash in D:\xampp\htdocs\overheard\test.php on line 5. Commented May 28, 2012 at 1:01
  • 1
    @ThiefMaster: Except that will make a valid regex invalid. Commented May 28, 2012 at 1:07

5 Answers 5

20

The simplest way to test if a string is a regex is:

if( preg_match("/^\/.+\/[a-z]*$/i",$regex))

This will tell you if a string has a good chance of being intended to be as a regex. However there are many string that would pass that check but fail being a regex. Unescaped slashes in the middle, unknown modifiers at the end, mismatched parentheses etc. could all cause problems.

The reason preg_last_error returned 0 is because the "invalid regex" is not:

  • PREG_INTERNAL_ERROR (an internal error)
  • PREG_BACKTRACK_LIMIT_ERROR (excessively forcing backtracking)
  • PREG_RECURSION_LIMIT_ERROR (excessively recursing)
  • PREG_BAD_UTF8_ERROR (badly formatted UTF-8)
  • PREG_BAD_UTF8_OFFSET_ERROR (offset to the middle of a UTF-8 character)
Sign up to request clarification or add additional context in comments.

2 Comments

Yes this is correct! Had this kind of figured out, just didn't know how to do it properly! However, using track_errors worked!
Note also, this only works for regexes with / delimiters.
18

Here is a good answer how to:

https://stackoverflow.com/a/12941133/2519073

if(@preg_match($your_pattern, '') === false){
    //pattern is broken
}else{
    //pattern is real
}

// or as a function:
function isValidRegex(string $regex): bool
{
    return @preg_match($regex, '') !== false;
}

2 Comments

Better solutions the rest 2, as track_errors is deprecated with PHP 7.2
Only one suggestion - the 2nd parameter should be a string (e.g. an empty string). In newer PHP versions that would cause a deprecation error (although the @ mutes it anyway, but I wouldn't rely on it): 3v4l.org/5YI6t
10

The only easy way to test if a regex is valid in PHP is to use it and check if a warning is thrown.

ini_set('track_errors', 'on');
$php_errormsg = '';
@preg_match('/[blah/', '');
if($php_errormsg) echo 'regex is invalid';

However, using arbitrary user input as a regex is a bad idea. There were security holes (buffer overflow => remote code execution) in the PCRE engine before and it might be possible to create specially crafted long regexes which require lots of cpu/memory to compile/execute.

3 Comments

It's not arbitrary user input, rather, rows taken from a database table that will only be added through direct code (for link generation). But yes, this worked :) Thanks!
Why is this better than just checking the output of preg_match?
track_errors is deprecated as of PHP 7.2
9

Why not just use...another regex? Three lines, no @ kludges or anything:

// Test this string
$str = "/^[A-Za-z ]+$/";

// Compare it to a regex pattern that simulates any regex
$regex = "/^\/[\s\S]+\/$/";

// Will it blend?
echo (preg_match($regex, $str) ? "TRUE" : "FALSE");

Or, in function form, even more pretty:

public static function isRegex($str0) {
    $regex = "/^\/[\s\S]+\/$/";
    return preg_match($regex, $str0);
}

This doesn't test validity; but it looks like the question is Is there a good way of test if a string is a regex or normal string in PHP? and it does do that.

5 Comments

I presume it's because you can't detect all regexes with a regex - the best this can do is decide whether it looks kinda like a regex or not.
For the regex-lovers, the answer to this question might be interesting...
Does not work with flags? Sample '/(\n)}[\s\n\r]*$/s'
this answer does not support modifiers
..nor does it support any other delimiter than /. E.g. ``#/some/path/#` is a valid regex using hash marks, which is very common when matching paths. And since it's using regex matching anyway, might as well go with the false-return approach.
0

Since regex must be always surrounded only with one of three boundary characters /, @, #, and trailing characters may only be allowed modifiers, we can use quick test:

if (preg_match('/^[\/@#](.+)[\/@#imsxADSUXJun]+$/', $pattern, $match) ){
   // .. do stuff, $match[0] contains full regex
}

This does not guarantee proper REGEX syntax in any way, but helps with quick detection.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.