I'd like to test the validity of a regular expression in PHP, preferably before it's used. Is the only way to do this actually trying a preg_match() and seeing if it returns FALSE?
Is there a simpler/proper way to test for a valid regular expression?
-
7Do you mean something like: stackoverflow.com/questions/172303/… ?Jon– Jon2012年10月16日 23:10:58 +00:00Commented Oct 16, 2012 at 23:10
-
Why don't you want to check preg_match() against false?rubo77– rubo772012年10月19日 18:31:03 +00:00Commented Oct 19, 2012 at 18:31
-
Some answers do not consider that MAYBE the regex to be validated comes from the input of an admin user of an app... MAYBE the app has a "contact_types" table with a "regex" field...J. Bruni– J. Bruni2014年03月01日 05:25:11 +00:00Commented Mar 1, 2014 at 5:25
12 Answers 12
// This is valid, both opening ( and closing )
var_dump(preg_match('~Valid(Regular)Expression~', '') === false);
// This is invalid, no opening ( for the closing )
var_dump(preg_match('~InvalidRegular)Expression~', '') === false);
As the user pozs said, also consider putting @ in front of preg_match() (@preg_match()) in a testing environment to prevent warnings or notices.
To validate a RegExp just run it against null (no need to know the data you want to test against upfront). If it returns explicit false (=== false), it's broken. Otherwise it's valid though it need not match anything.
So there's no need to write your own RegExp validator. It's wasted time...
8 Comments
preg_match() call with @$subject in preg_match() as nulls are converted to empty strings too (preg_match('~.?~', null) === 1), so that's just a method to test a regular expression, not a method to test it before it's used (w/ or w/o real data)I created a simple function that can be called to checking preg
function is_preg_error()
{
$errors = array(
PREG_NO_ERROR => 'Code 0 : No errors',
PREG_INTERNAL_ERROR => 'Code 1 : There was an internal PCRE error',
PREG_BACKTRACK_LIMIT_ERROR => 'Code 2 : Backtrack limit was exhausted',
PREG_RECURSION_LIMIT_ERROR => 'Code 3 : Recursion limit was exhausted',
PREG_BAD_UTF8_ERROR => 'Code 4 : The offset didn\'t correspond to the begin of a valid UTF-8 code point',
PREG_BAD_UTF8_OFFSET_ERROR => 'Code 5 : Malformed UTF-8 data',
);
return $errors[preg_last_error()];
}
You can call this function using the follow code :
preg_match('/(?:\D+|<\d+>)*[!?]/', 'foobar foobar foobar');
echo is_preg_error();
Alternative - Regular Expression Online Tester
3 Comments
preg_last_error specific for the English language.If you want to dynamically test a regex preg_match(...) === false seems to be your only option. PHP doesn't have a mechanism for compiling regular expressions before they are used.
Also you may find preg_last_error an useful function.
On the other hand if you have a regex and just want to know if it's valid before using it there are a bunch of tools available out there. I found rubular.com to be pleasant to use.
Comments
You can check to see if it is a syntactically correct regex with this nightmare of a regex, if your engine supports recursion (PHP should).
You cannot, however algorithmically tell if it will give the results you want without running it.
From: Is there a regular expression to detect a valid regular expression?
/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/
2 Comments
Without actually executing the regex you have no way to be sure if it's be valid. I've recently implemented a similar RegexValidator for Zend Framework. Works just fine.
<?php
class Nuke_Validate_RegEx extends Zend_Validate_Abstract
{
/**
* Error constant
*/
const ERROR_INVALID_REGEX = 'invalidRegex';
/**
* Error messages
* @var array
*/
protected $_messageTemplates = array(
self::ERROR_INVALID_REGEX => "This is a regular expression PHP cannot parse.");
/**
* Runs the actual validation
* @param string $pattern The regular expression we are testing
* @return bool
*/
public function isValid($pattern)
{
if (@preg_match($pattern, "Lorem ipsum") === false) {
$this->_error(self::ERROR_INVALID_REGEX);
return false;
}
return true;
}
}
Comments
You can validate your regular expression with a regular expression and up to a certain limit. Checkout this stack overflow answer for more info.
Note: a "recursive regular expression" is not a regular expression, and this extended version of regex doesn't match extended regexes.
A better option is to use preg_match and match against NULL as @Claudrian said
Comments
So in summary, for all those coming to this question you can validate regular expressions in PHP with a function like this.
preg_match() returns 1 if the pattern matches given subject, 0 if it does not, or FALSE if an error occurred. - PHP Manual
/**
* Return an error message if the regular expression is invalid
*
* @param string $regex string to validate
* @return string
*/
function invalidRegex($regex)
{
if(preg_match($regex, null) !== false)
{
return '';
}
$errors = array(
PREG_NO_ERROR => 'Code 0 : No errors',
PREG_INTERNAL_ERROR => 'Code 1 : There was an internal PCRE error',
PREG_BACKTRACK_LIMIT_ERROR => 'Code 2 : Backtrack limit was exhausted',
PREG_RECURSION_LIMIT_ERROR => 'Code 3 : Recursion limit was exhausted',
PREG_BAD_UTF8_ERROR => 'Code 4 : The offset didn\'t correspond to the begin of a valid UTF-8 code point',
PREG_BAD_UTF8_OFFSET_ERROR => 'Code 5 : Malformed UTF-8 data',
);
return $errors[preg_last_error()];
}
Which can be used like this.
if($error = invalidRegex('/foo//'))
{
die($error);
}
Comments
I am not sure if it supports PCRE, but there is a Chrome extension over at https://chrome.google.com/webstore/detail/cmmblmkfaijaadfjapjddbeaoffeccib called RegExp Tester. I have not used it as yet myself so I cannot vouch for it, but perhaps it could be of use?
Comments
just use the easy way - look if the preg_match is return a false value:
//look is a regex or not
$look = "your_regex_string";
if (preg_match("/".$look."/", "test_string") !== false) {
//regex_valid
} else {
//regex_invalid
}
Comments
I'd be inclined to set up a number of unit tests for your regex. This way not only would you be able to ensure that the regex is indeed valid but also effective at matching.
I find using TDD is an effective way to develop regex and means that extending it in the future is simplified as you already have all of your test cases available.
The answer to this question has a great answer on setting up your unit tests.
1 Comment
You should try to match the regular expression against NULL. If the result is FALSE (=== FALSE), there was an error.
In PHP >= 5.5, you can use the following to automatically get the built-in error message, without needing to define your own function to get it:
// For PHP >= 8, use the built-in str_ends_with() instead of this function.
// Taken from https://www.php.net/manual/en/function.str-ends-with.php#126551
if (!function_exists('str_ends_with')) {
function str_ends_with(string $haystack, string $needle): bool {
$needle_len = strlen($needle);
return ($needle_len === 0 || 0 === substr_compare($haystack, $needle, - $needle_len));
}
}
function test_regex($regex) {
preg_match($regex, NULL);
$constants = get_defined_constants(true)['pcre'];
foreach ($constants as $key => $value) {
if (!str_ends_with($key, '_ERROR')) {
unset($constants[$key]);
}
}
return array_flip($constants)[preg_last_error()];
}
Note that the call to preg_match() will still throw a warning for invalid regular expressions. The warning can be caught with a custom error handler using set_error_handler().
2 Comments
array_flip isn't safe to use on the output from get_defined_constants(true)['pcre'] in later versions of PHP since one of the constants has a value of TRUE (boolean), and that will result in a warning being emitted.According to the PCRE reference, there is no such way to test validity of an expression, before it's used. But i think, if someone use an invalid expression, it's a design error in that application, not a run-time one, so you should be fine.