7

mariadb 版本10.4

$query->where('column', 'REGEXP', '[[:<:]]'.$string.'[[:>:]]');

此查询仅提供整个单词的搜索,并且在没有特殊字符的情况下可以正常工作。

例子

搜索行:
foo (bar baz)
筛选:
$string = "(bar";
$query->where('column', 'REGEXP', '[[:<:]]'.$string.'[[:>:]]');
错误:
SQLSTATE[42000]: Syntax error or access violation: 1139 Got error 'missing )

现在我尝试使用addcslashesand preg_quote。我成功地转义(了字符,preg_quote但过滤器不适用于该字符串,因为过滤器适用于整个单词。

任何通过整个单词更好地过滤的建议也将不胜感激。

再举一个例子

搜索行:
foo(bar baz
筛选:
$filter = 'foo(bar';
$query->where('column', 'REGEXP', '[[:<:]]'.$string.'[[:>:]]');

如果(将被转义,则搜索将不起作用

4

3 回答 3

1

REGEXP字符串 中有很多具有特殊含义的标点符号。(只是众多之一。

如果目标是搜索(bar带有尾随“单词边界”的 4 个字符,那么其中一个字符可能会起作用——取决于MySQL/MariaDB 的版本以及从您的应用程序到服务器所需的转义:

\(bar[[:>:]]
\\(bar[[:>:]]
\\\\(bar[[:>:]]
[(]bar[[:>:]]

\(bar\b
\\(bar\\b
\\\\(bar\\\\b
[(]bar\b
[(]bar\\b
[(]bar\\\\b

无论如何,您的应用程序必须进行一些转义。鉴于此,删除标点符号可能会更好:

[[:<:]]bar[[:>:]]
\bbar\b
\\bbar\\b
\\\\bbar\\\\b

也考虑使用LIKE "(bar"

也考虑使用FULLTEXT索引

MATCH(col) AGAINST("bar" IN BOOLEAN MODE)

为了获得最佳性能,这可能是最好的(使用 FULLTEXT 索引):

MATCH(col) AGAINST("bar" IN BOOLEAN MODE)
AND col LIKE "(bar"
于 2021-07-05T21:57:53.707 回答
0

如您所见,您使用的ICU正则表达式库认为括号很特殊,并且需要斜杠转义。Usingadd_slashes()没有用,因为它会在非 ICU 的其他库需要的地方添加斜杠,并且可能会给你一个不适合它的字符串(例如,它不会转义圆括号)。

由于圆括号和方括号碰巧escapeshellcmd()都是 s​​hell 元字符,但美元符号和井号也是如此,这可能会在后面咬你。

更简单的解决方案是手动替换您需要的四个字符(实际上是三个, ( ) [,但为了完整起见......)。

$string = preg_replace(
    '#([(\\[\\])])#', 
    '\\\\\\\\\1', // Hilarious, isn't it?
    $string
);

$query->where('column', 'REGEXP', '[[:<:]]'.$string.'[[:>:]]');
于 2021-07-05T22:15:51.223 回答
0

尝试这个 :$string = '\(bar';

您可以随时在此处检查您的正则表达式模式:https ://regex101.com/

于 2021-07-01T09:50:09.307 回答