trim为什么失效了
前言
一直以为String#trim()
是去掉字符串两边空格的。但是以下代码却与预期不同。
1 | System.out.println("测试:["+"820000 ".trim()+"]"); // ASCII码 160 的空格 |
这段数字加空格是我从最新县及县以上行政区划代码爬取的。
查看源码
很明显, 算法就是
- 从前往后, 找到第一个非空格的字符
- 从后往前, 找到第一个非空格的字符
- 使用substring截取字符串
- substring使用构造复制函数进行拷贝明显没毛病, 要我写我也差不多是这样写。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */
while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
}
public String substring(int beginIndex, int endIndex) {
int subLen = endIndex - beginIndex;
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
断点调试
给trim
加上断点, 保险起见, 每条语句加上断点。
1 | public String trim() { |
调试结果如下, 代码走到第9行, 进不去这个while
。
那明显是(val[len - 1] <= ' ')
出了问题。
1 | len (slot_1) = 10 |
这时候注意value[9]
的ASCII码为160
。
查阅ASCII码表可以知道, 空格的ASCII码应该为32
。
可是这明显是空格啊! 为什么是160呢!
为什么眼见不为实
web中有一个常识是, 要使用连续空格, 必须使用
。
如果只按住space
输入空格的话, 会被压缩为一个
空格。
很明显, 这个
的ASCII码就是160
。
而trim
方法只判断了ASCII码为32
的空格。
就算是apache的StringUtils#trim()
, 底层也是调用String#trim()
的。
后来还发现了一个ASCII码为12288
的空格, 一个汉字宽度的空格。
自己动手丰衣足食
参考源码, 进行改造
1 | public class StringHelper{ |