在PHP中模拟LIKE(Simulating LIKE in PHP)

2019-06-26 05:19发布

有没有办法用相同的语法来模拟SQL的LIKE操作者在PHP? ( %_通配符和通用$escape转义字符)? 使得具有:

$value LIKE $string ESCAPE $escape

你可以有一个返回的PHP评价不使用数据库的功能? (认为$value$string$escape值已经设定)。

Answer 1:

OK,非常有趣,在这里游戏后就是我想出了:

function preg_sql_like ($input, $pattern, $escape = '\\') {

    // Split the pattern into special sequences and the rest
    $expr = '/((?:'.preg_quote($escape, '/').')?(?:'.preg_quote($escape, '/').'|%|_))/';
    $parts = preg_split($expr, $pattern, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

    // Loop the split parts and convert/escape as necessary to build regex
    $expr = '/^';
    $lastWasPercent = FALSE;
    foreach ($parts as $part) {
        switch ($part) {
            case $escape.$escape:
                $expr .= preg_quote($escape, '/');
                break;
            case $escape.'%':
                $expr .= '%';
                break;
            case $escape.'_':
                $expr .= '_';
                break;
            case '%':
                if (!$lastWasPercent) {
                    $expr .= '.*?';
                }
                break;
            case '_':
                $expr .= '.';
                break;
            default:
                $expr .= preg_quote($part, '/');
                break;
        }
        $lastWasPercent = $part == '%';
    }
    $expr .= '$/i';

    // Look for a match and return bool
    return (bool) preg_match($expr, $input);

}

我不能打破它,也许你可以找到的东西,会的。 其中矿从@ nickb的不同的主要途径是矿“解析”(ISH)输入表达式成标记,以产生正则表达式,而不是在原位将其转化为正则表达式。

第3个函数的自变量应该是相当自我解释。 第四,您可以通过PCRE修饰符来影响用于比赛的最后正则表达式。 我把这个主要的原因是为了让你通过i所以它是不区分大小写-我想不出任何其他修饰,这将是安全的使用,但可能不是的情况。 每下面的评论已删除

函数返回一个布尔值,指示是否$input文本相匹配的$pattern与否。

下面是它的键盘

编辑哎呀,坏了,现在是固定的。 新键盘

编辑删除了第四个参数,并且所有的匹配不区分大小写的每下面的注释

编辑对小情侣修复/改进:

  • 串断言的添加开始/结束所产生的正则表达式
  • 最后加入令牌的跟踪,以避免重复.*? 在正则表达式生成的序列


Answer 2:

这基本上是你将如何实现这样的事情:

$input = '%ST!_ING_!%';
$value = 'ANYCHARS HERE TEST_INGS%';

// Mapping of wildcards to their PCRE equivalents
$wildcards = array( '%' => '.*?', '_' => '.');

// Escape character for preventing wildcard functionality on a wildcard
$escape = '!';

// Shouldn't have to modify much below this

$delimiter = '/'; // regex delimiter

// Quote the escape characters and the wildcard characters
$quoted_escape = preg_quote( $escape);
$quoted_wildcards = array_map( function( $el) { return preg_quote( $el); }, array_keys( $wildcards));

// Form the dynamic regex for the wildcards by replacing the "fake" wildcards with PRCE ones
$temp_regex = '((?:' . $quoted_escape . ')?)(' . implode( '|', $quoted_wildcards) . ')';

// Escape the regex delimiter if it's present within the regex
$wildcard_replacement_regex = $delimiter . str_replace( $delimiter, '\\' . $delimiter, $temp_regex) . $delimiter;

// Do the actual replacement
$regex = preg_replace_callback( $wildcard_replacement_regex, function( $matches) use( $wildcards) { return !empty( $matches[1]) ? preg_quote( $matches[2]) : $wildcards[$matches[2]]; }, preg_quote( $input)); 

// Finally, test the regex against the input $value, escaping the delimiter if it's present
preg_match( $delimiter . str_replace( $delimiter, '\\' . $delimiter, $regex) . $delimiter .'i', $value, $matches);

// Output is in $matches[0] if there was a match
var_dump( $matches[0]);

这就形成了基于动态正则表达式$wildcards$escape ,以便与他们的PCRE等效替换所有的“假”通配符,除非“假”通配符与转义字符,在这种情况下,没有替代由前缀。 为了做到这一点替补, $wildcard_replacement_regex创建。

$wildcard_replacement_regex看起来像这个曾经的一切一切都说过和做过:

/((?:\!)?)(%|_)/

因此,使用两个捕捉组(可选)抢转义字符和通配符之一。 这使我们能够进行测试,看它是否抓住回调的转义字符。 如果它能够通配符之前得到转义字符, $matches[1]将包含转义字符。 如果没有, $matches[1]将是空的。 这就是我如何确定是否与它的PCRE等效替换通配符,或者只是息事宁人preg_quote() -ing它。

你可以用它玩的键盘 。



Answer 3:

您可以使用正则表达式,例如: preg_match



Answer 4:

其他的例子是对我的口味有点太复杂(和痛苦我的干净的代码眼),所以我重新实现这个简单的方法的功能:

public function like($needle, $haystack, $delimiter = '~')
{
    // Escape meta-characters from the string so that they don't gain special significance in the regex
    $needle = preg_quote($needle, $delimiter);

    // Replace SQL wildcards with regex wildcards
    $needle = str_replace('%', '.*?', $needle);
    $needle = str_replace('_', '.', $needle);

    // Add delimiters, beginning + end of line and modifiers
    $needle = $delimiter . '^' . $needle . '$' . $delimiter . 'isu';

    // Matches are not useful in this case; we just need to know whether or not the needle was found.
    return (bool) preg_match($needle, $haystack);
}

修饰符 :

  • i :忽略套管。
  • s :请点元字符匹配任何东西,包括换行符。
  • u :UTF-8的兼容性。


文章来源: Simulating LIKE in PHP