心灵鸡汤
当你还是一只猫的时候,记着你的目标要成为一只虎。当你成为一只虎的时候,别忘了你曾经是一只猫。心态要高,姿态要低。不要看轻别人,更不要高估自己
# 一:场景
首先看下面这段代码,以及先猜想一下运行结果。
public class Test {
public static void main(String[] args) {
String string = "广州xxxx有限公司 ";
String print = "【%s】 \t length:%d \n";
System.out.printf(print, string.trim(), string.length());
System.out.printf(print, string, string.length());
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
运行结果:
# 二:char
一个 char
保存一个Unicode字符,无论中英文。可以使用 \u + 4位十六进制数
来表示一个Unicode字符。例如,A
的ASCII,十进制为 65,十六进制为 41
public static void main(String[] args) {
char c1 = 'A';
int c1Int = c1; // 把char类型的值转换为十进制整型
System.out.println("A 的十进制:" + c1Int);
char c2 = '\u0041'; // \\u 加 4位十六进制
System.out.println("\\u0041表示:" + c2);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
运行结果:
# 三:问题定位
首先把之前那个String,按照char打印
public static void main(String[] args) {
String string = "广州xxxx有限公司 ";
for (char c : string.toCharArray()) {
System.out.printf("【%s】十进制为:%d\n", c, (int)c);
}
}
1
2
3
4
5
6
2
3
4
5
6
运行结果:
这时候可以去查 ASCII 表,就会惊讶的发现,空格 在ASCII表的十进制为32,十六进制为20,而上面的运行结果,最后两行的空格,十进制为12288,那难道不是空格?
首先十进制12288,转成十六进制为3000。之后可以通过在线工具,例如 52unicode (opens new window) 找到代表的字符,可以发现确实为空格。只不过是全角空格。
科普
- \u00A0:不间断空格,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ;
- \u0020:半角空格(英文符号);
- \u3000:全角空格(中文符号)。
那就剩下最后一个问题,String#trim 方法为什么失效?
package java.lang;
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
/**
* 返回一个字符串,其值为该字符串,删除了前缀和后缀的空格。
*
* 如果此 String 对象表示一个空字符,或者此 String 的第一个和最后一个字符的 unicode 都大于 '\u0020'(空格字符),则返回对该 String 对象的引用。
*
* 否则,如果字符串中没有代码大于 '\u0020' 的字符,则返回空字符串。
*
* 设 k 为字符串中编码大于 '\u0020' 的第一个字符的索引,设 m 为字符串中编码大于 '\u0020' 的最后一个字符的索引。
* 返回一个 String 对象,表示这个字符串的子字符串,它以索引 k 处的字符开始,以索引 m 处的字符结束——也就是这个的结果。
* substring(k, m + 1)
*
* @return 一个字符串,去掉前后缀空格
*/
public 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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
不难发现,trim() 只能去除英文的空格。
# 四:解决方案
# 4.1 重写 trim
新 trim 工具类如下:
import org.apache.commons.lang3.StringUtils;
/**
* 去除字符串前后各种编码类型的空格
*/
public class StringUtil {
/**
* 普通的英文半角空格Unicode编码
*/
private static final int SPACE_32 = 32;
/**
* 中文全角空格Unicode编码(一个中文宽度)
*/
private static final int SPACE_12288 = 12288;
/**
* 普通的英文半角空格但不换行Unicode编码(== ==   == no-break space)
*/
private static final int SPACE_160 = 160;
/**
* 半个中文宽度(==   == en空格)
*/
private static final int SPACE_8194 = 8194;
/**
* 一个中文宽度(==   == em空格)
*/
private static final int SPACE_8195 = 8195;
/**
* 四分之一中文宽度(四分之一em空格)
*/
private static final int SPACE_8197 = 8197;
/**
* 窄空格
*/
private static final int SPACE_8201 = 8201;
/**
* 去除字符串前后的空格, 包括半角空格和全角空格(中文)等各种空格, java的string.trim()只能去英文半角空格
*
* @param str 待去掉前缀尾缀空格的字符串
* @return 去掉前缀尾缀空格的字符串
*/
public static String trim(String str) {
if (StringUtils.isEmpty(str)) {
return str;
}
char[] val = str.toCharArray();
int st = 0;
int len = val.length;
while ((st < len) && isSpace(val[st])) {
st++;
}
while ((st < len) && isSpace(val[len - 1])) {
len--;
}
return ((st > 0) || (len < val.length)) ? str.substring(st, len) : str;
}
/**
* 判断是否为空格
*
* @param aChar 待判断的字符
* @return true:是,false:否
*/
private static boolean isSpace(char aChar) {
return aChar == SPACE_32 || aChar == SPACE_12288 || aChar == SPACE_160 || aChar == SPACE_8194
|| aChar == SPACE_8195 || aChar == SPACE_8197 || aChar == SPACE_8201;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
测试:
public static void main(String[] args) {
String string = "广州xxxx有限公司 ";
String print = "【%s】 \t length:%d \n";
String temp = StringUtil.trim(string);
System.out.printf(print, temp, temp.length());
System.out.printf(print, string, string.length());
}
1
2
3
4
5
6
7
2
3
4
5
6
7
运行结果:
# 4.2 替换全角空格
str.replace((char) 12288, ' ').trim();
1
测试:
public static void main(String[] args) {
String string = "广州xxxx有限公司 ";
String print = "【%s】 \t length:%d \n";
String temp = string.replace((char) 12288, ' ').trim();
System.out.printf(print, temp, temp.length());
System.out.printf(print, string, string.length());
}
1
2
3
4
5
6
7
2
3
4
5
6
7
运行结果: