上一篇从SQL的角度看了一下like保留字符和转义字符的解决方法。在Android平台下,一般是在Java层根据业务逻辑拼装SQL语句。所以需要对于like参数做转义字符的替换,然后再将后缀escape代码段拼接上去。对于转义字符的替换,有2点需要注意:
(1)对于你作为转义字符的字符本身,不要忘记在前面需要再增加一个转义字符,否则会出现错误。举如下例子
sqlite> select * from test_table;
id|name|description
0|name0|des0
1|name1|des1
2|_|%
3|a|b
4|_d|%d
5|tr|%u
6|_aa|yy
7|xyz|
8|abc%90|zz
9|abcdefg|888
10|bc%90|00
在这个table中查询name以abc%开头的数据,其中%是字面量本身。显然不能直接将abc%作为参数拼接,会得到如下错误结果:
sqlite> select * from test_table where name like 'abc%%';
id|name|description
8|abc%90|zz
9|abcdefg|888
假设我们想用a作为转义字符,但没有处理a本身,select结果错误:
sqlite> select * from test_table where name like 'abca%%' escape 'a';
id|name|description
10|bc%90|00
原因是第一个a被识别成转义字符,ab也就是转义b,b本身并非保留字符,转义之后仍然是b。拼接之后等同于select以bc%开头的name。
正确的方式是:
sqlite> select * from test_table where name like 'aabca%%' escape 'a';
id|name|description
8|abc%90|zz
(2)转义字符的替换是类似将%转成/%,即在Java字符串中将一个字符替换成两个字符,这样的话,使用String.replace()不如使用StringBuilder去逐个字符处理更合适,因为String.replace()需要将单个字符也转成字符串,另外有多个保留字符需要处理,所以String.replace()会有很多中间结果字符串。用一段代码来测试:
Log.i("TEST", "start test");
long now = System.currentTimeMillis();
for (int i = 0 ; i < 100000 ; i++) {
"abc%defghijk_lmnopq/rstuvwxyz"
.replace("/", "//")
.replace("%", "/%%")
.replace("_", "/_");
}
Log.i("TEST", "1 : " + (System.currentTimeMillis() - now));
now = System.currentTimeMillis();
for (int i = 0 ; i < 100000 ; i++) {
String s = "abc%defghijk_lmnopq/rstuvwxyz";
StringBuilder sb = new StringBuilder();
char c;
for (int j = 0; j < s.length(); j++) {
c = s.charAt(j);
if (c == '/' || c == '%' || c == '_') {
sb.append('/');
}
sb.append(c);
}
}
Log.i("TEST", "2 : " + (System.currentTimeMillis() - now));
结果:
10-25 09:38:17.488 32505 32546 I TEST : start test
10-25 09:38:18.749 32505 32546 I TEST : 1 : 1261
10-25 09:38:19.731 32505 32546 I TEST : 2 : 982
看到StringBuilder还是有优势。