匹配模式,但不返回所有模式

Posted

技术标签:

【中文标题】匹配模式,但不返回所有模式【英文标题】:Match pattern, but not returning all of it 【发布时间】:2012-11-14 02:54:32 【问题描述】:

我对正则表达式很陌生。假设我有一个这样的字符串:

UPDATE table_name SET column = :column WHERE column IN(:column_32, :column_34, :column_347)

然后假设我有一个数组:

$arr = array(
    'column' => 'Test',
    'column_32' => 'Tester',
    'column_34' => 'Faux data',
    'column_347' => 'Column data'
);

我想要做的是将占位符(:column,:column_32 等)替换为数组中的相应值。问题是,str_replace 不会削减它,因为将 :column 替换为 'Test' 会导致 :column_32 变为 :Test_32 等。

所以,我开始编写一些自定义正则表达式。这是我一直在运行的测试脚本:

foreach($arr as $k => $v)
    var_dump(preg_match_all('(:'.$v.'[^_])', $str, $matches));

它匹配正确的字符串。问题是,它还返回 "," 和 ")" 作为匹配的一部分。我在这里忽略了什么吗?

【问题讨论】:

这正是 bindParam()phpPDO 中所做的。 See here; especially Example #1. 这很奇怪,因为 :xyz 语法暗示你的代码一开始就使用了这样的 bind 实现,现在你似乎想通过正则表达式破解它...... 您是否想重新发明***(又名 PDO 准备好的语句)? @acheong87 编写一个使用关联数组自动创建、准备和执​​行准备好的语句的 PDO 包装类。出于调试目的,我将用相应的值替换占位符。 你看过 PDO debugDumpParams 方法吗? php.net/manual/en/pdostatement.debugdumpparams.php 另见这个 SO 问题:***.com/questions/2411182/… 【参考方案1】:

这可能有点小技巧,但是您如何按密钥长度从最长到最短排序您的数组。然后,任何可以是另一个键的子字符串的键都将在其包含的字符串之后进行检查。所以你像这样重新排列你的数组:

$arr = array(
    'column_347' => 'Column data'
    'column_32' => 'Tester',
    'column_34' => 'Faux data',
    'column' => 'Test',
);

当然,您也可以自动执行此操作。从 PHP 5.3.0 开始是这样的:

uksort($arr, function($a, $b) 
    if(strlen($a) > strlen($b))
        return -1;
    else
        return 0;
);

低于 5.3.0 你可以使用这个(从 PHP 4.0.1 开始):

uksort($arr, create_function('$a, $b', '
    if(strlen($a) > strlen($b))
        return -1;
    else
        return 0;
'));

或者(如果你不能使用漂亮的匿名函数语法,或者如果你使用 4.0.1 之前的 PHP,这可能更可取):

function compare($a, $b) 
    if(strlen($a) > strlen($b))
        return -1;
    else
        return 0;


uksort($arr, "compare");

【讨论】:

我喜欢这个解决方案,只是因为它不需要正则表达式。【参考方案2】:

基本上,您要避免关键字后面的所有非 _ 字符。 [^_] 在你的变量意味着“找到一个不是下划线的单个字符”之后,因此你的正则表达式正确地抓住了逗号和右括号。

您为什么不尝试查找标识符?例如,搜索:column_347 就可以了。您可能希望在占位符之后搜索单词边界,以告诉您的正则表达式“如果此(例如列)不是一个完整的单词,请不要停止。

这是通过将[^_] 替换为作为单词边界的\b 而获得的。 This link 展示了它是如何工作的,注意正则表达式只匹配第一个“列”

【讨论】:

【参考方案3】:

这不能回答您的正则表达式问题,但我还是想提供 PDO 实现:

<?php

    $sql = 'UPDATE table_name SET column = :column WHERE column IN(:column_32, :column_34, :column_347)'

    $arr = array(
        'column' => 'Test',
        'column_32' => 'Tester',
        'column_34' => 'Faux data',
        'column_347' => 'Column data'
    );

    $sth = $dbh->prepare($sql);

    foreach ($arr as $k => $v) 
        $sth->bindParam(':' . $k, $v);
    

    $sth->execute();

?>

如果您正在使用其他人的代码并且不知道PDO,那么这可能是正确的方法,原因有很多(包括防止注入攻击)。但是,如果您知道 PDO 并希望有一个替代的、基于正则表达式的实现,那么 @m.buettner 和 @Gabber 都会提供合理的建议。

【讨论】:

@WtotheX - 抱歉,我在发布此答案时没有看到您的评论。所以你不仅知道PDO,而且实际上增强它;凉爽的。我会留下这个答案,以防有 其他人正在重新发明***并可能偶然发现这个问题。

以上是关于匹配模式,但不返回所有模式的主要内容,如果未能解决你的问题,请参考以下文章

返回字符串中模式的所有非重叠匹配

正则表达式:匹配模式后跟一个空格但不匹配2个或更多空格或EOF

匹配所有“错误:”但不匹配“错误:0”[重复]

列出与R中的完整路径模式匹配的所有文件

朴素模式匹配算法(C语言)

模式匹配中断