如何验证正则表达式?


74

我想在PHP中测试正则表达式的有效性,最好在使用前进行测试。这样做的唯一方法是实际尝试apreg_match()并查看其是否返回FALSE吗?

有没有更简单/正确的方法来测试有效的正则表达式?


7
您的意思是:stackoverflow.com/questions/172303/…吗?
2012年

如果不必使用代码,则可以转到regexr.com,然后粘贴您的正则表达式,然后输入要与之匹配的文本。
花王

您为什么不想要检查preg_match()是否为false?
rubo77

1
看来我参加聚会迟到了
巴巴

一些答案不认为MAYBE待验证的正则表达式可能来自某个应用程序的管理员用户的输入...也许该应用程序具有带有“ regex”字段的“ contact_types”表...
J. Bruni

Answers:


139
// This is valid, both opening ( and closing )
var_dump(preg_match('~Valid(Regular)Expression~', null) === false);
// This is invalid, no opening ( for the closing )
var_dump(preg_match('~InvalidRegular)Expression~', null) === false);

正如用户pozs所说,还应考虑@@preg_match()在测试环境中放在preg_match()()前面,以防止发出警告或通知。

要验证RegExp只需对其运行null (无需知道您要预先测试的数据)。如果返回显式false(=== false),则表示它已损坏。否则它是有效的,尽管它不需要匹配任何内容。

因此,无需编写自己的RegExp验证器。 浪费时间了...


1
只是一个猜测:OP说:“我想在PHP中测试正则表达式的有效性,最好在使用它之前。
JDB仍然记得Monica 2012年

7
@ Cyborgx37那又如何呢?我给他的解决方案为NULL。现在,您不需要将其用作字符串。您只需要知道模式即可查看它是否正确。如果匹配或不匹配...那是另外一回事了,取决于您的目标字符串。我说错了什么?
CodeAngry 2012年

1
我没有投票给你...只是猜测为什么有人会这么做。我认为您的回答很好。
JDB仍记得Monica

5
请注意,对于无效的正则表达式,您的代码将显示警告,这对于仅测试表达式而言是非常糟糕的-您应该preg_match()使用@
pozs

2
由于单元测试框架存在问题,并且其他禁用“ @”运算符进行测试,因此错误抑制运算符不是一个好的解决方案。解决方法是,您可以在该测试之前使用“ set_error_handler”,在测试之后使用“ restore_error_handler”;)
mabe.berlin 2012年

24

我创建了一个简单的函数,可以调用它检查预浸料

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()];
}

您可以使用以下代码调用此函数:

preg_match('/(?:\D+|<\d+>)*[!?]/', 'foobar foobar foobar');
echo is_preg_error();

另类-正则表达式在线测试器


2
这只是preg_last_error针对英语的包装。
阿林·珀卡鲁

顺便说一句,这不会真正告诉您正则表达式是否有效。考虑一下:php> preg_match(“ / aaa”,“”); PHP>回声preg_last_error(); 0
亚历克斯N.

PHP 7添加了PREG_JIT_STACKLIMIT_ERROR。请参阅文档
mbomb007 '19

15

如果要动态测试正则表达式preg_match(...) === false似乎是您唯一的选择。PHP没有使用正则表达式之前对其进行编译的机制。

另外,您可能会发现preg_last_error是有用的功能。

另一方面,如果您有一个正则表达式,并且只想在使用前知道它是否有效,则可以使用大量工具。我发现rubular.com使用起来很愉快。


6

如果您的引擎支持递归(PHP应该),则可以检查此正则表达式的噩梦,看看它是否在语法上正确。

但是,您无法在不运行算法的情况下从算法上确定它是否可以提供所需的结果。

发件人:是否存在用于检测有效正则表达式的正则表达式?

/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/

在一般情况下,这肯定行不通吗?
Mike Chamberlain

此正则表达式是递归的。因此,它不是传统意义上的正则表达式,而是在Perl兼容正则表达式引擎中工作。
ptmalcolm

2

没有实际执行正则表达式,您将无法确定它是否有效。我最近为Zend Framework实现了一个类似的RegexValidator。效果很好。

<?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;
    }
}

1

您可以通过验证的正则表达式的正则表达式,并达到一定的极限。查看此堆栈溢出答案以获取更多信息。

注意:“递归正则表达式”不是正则表达式,并且此正则表达式的扩展版本与扩展正则表达式不匹配。

更好的选择是使用preg_match和匹配NULL,如@Claudrian所说


1

因此,总而言之,对于所有遇到此问题的人,您都可以使用这样的函数来验证PHP中的正则表达式。

如果模式匹配给定的主题,则preg_match()返回1;如果不匹配,则返回0;如果发生错误,则返回FALSE。- PHP手册

/**
 * 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()];
}

可以这样使用。

if($error = invalidRegex('/foo//'))
{
    die($error);
}


0

我倾向于为您的正则表达式设置一些单元测试。这样,您不仅可以确保正则表达式确实有效,而且可以有效地进行匹配。

我发现使用TDD是开发正则表达式的有效方法,并且意味着由于您已经拥有所有可用的测试用例,因此可以简化将来对其进行扩展。

在回答这个问题,有关于设置的单元测试一个伟大的答案。


谢谢罗伯。我是TDD的粉丝,但是有问题的代码需要能够将正则表达式验证为输入(我正在验证JSON模式,其中可以包含正则表达式模式)。
罗斯·麦克法兰

0

您应该尝试将正则表达式与匹配NULL。如果结果为FALSE(=== FALSE),则错误。

在PHP> = 5.5中,可以使用以下命令自动获取内置错误消息,而无需定义自己的函数即可获取它:

preg_match($regex, NULL);
echo array_flip(get_defined_constants(true)['pcre'])[preg_last_error()];

-3

根据PCRE参考,在使用表达式之前,尚无方法测试表达式的有效性。但是我认为,如果有人使用无效的表达式,那是该应用程序中的一个设计错误,而不是运行时错误,因此您应该没事。


-1是OP的问题,它不是在使用之前而是在针对实际数据使用之前出现的。一件事是使用5MB的剪贴数据进行测试,另一件事是使用一个仅用于验证RegExp编译的空字符串进行测试。因此:在PHP中,您可以对其进行测试;在C ++中,您可以对其进行测试。在C ++ 11中,如果异常无效,则抛出异常;在PHP中,则显示显式false。任何RegExp都会在执行之前进行编译,这是错误的原因,因为在合法时,编译失败将导致编译失败,无论您要使用它的数据是否针对该RegExp。

@Claudrian:我同意,但是问题不是在针对实际数据使用之前,而是在使用之前最好-并且没有这样的方式(作为显式/专用功能)。但是我同意,如果真的要测试它,则应该针对null /空值进行测试。
pozs,2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.