最近遇到一个问题, 在MySQL like查询时, 明明字符串时相同的, 但是却like不到结果, 后面经过多方面查找资料, 终于发现是字符串转义的问题, 而MySQL的LIKE的转义和普通字符串的不同。
首先来看一个测试:
mysql> SET @a='\\';SELECT @a,@a LIKE '\\\\'; +----+----------------+ | @a | @a LIKE '\\\\' | +----+----------------+ | \ | 1 | +----+----------------+
可以看出”\\\\“在LIKE中转义成”\“,LIKE的转义和平时用的字符串的转义还是有点不一样的。
查了下官方文档,对于转义字符的解释:
this is because the backslashes are stripped once by the parser and again when the pattern match is made,
leaving a single backslash to be matched against.
mysql自己的parser转义一次,然后LIKE的pattern对前面的结果再转义一次。
也就是说上例中的“\\\\”第一次转义成“\\”,第二次才是“\”。
再来看个mysql字符转义的测试
mysql> SELECT '\%','\_'; +----+----+ | \% | \_ | +----+----+ | \% | \_ | +----+----+ 1 row in set
呵呵,什么都转义(比如"\x" 转义成“x”,“\b"是回退字符),就是不转义”\%“和”\_“。而LIKE,都转义。恐怕MYSQL这样做的目的也是为了兼容LIKE吧。
总结下,LIKE转义字符串时,一共两次,第一次不转义”\%“和”\_“,第二次全部转义。转义的特殊字符可以参见 http://dev.mysql.com/doc/refman/5.1/en/string-literals.html#character-escape-sequences
LIKE的转义可以看成先替换“\\\\”为“\”,剩下的字符串用”\\“转义,剩下的字符串再用”\"转义。通常不遇见“\\”, LIKE的特殊解析是感觉不到的。
PHP版like特殊字符过滤
function likeEscape($str) { return strtr($str, array('%'=>'\\%', '_'=>'\\_', '\\'=>'\\\\\\\\')); }
注意最后的双反斜杠转成了8个反斜杠, 其实就是1转4, 只不过在PHP字符串中需要转换一次, 这里有点绕,大家仔细想想,有问题可以留言