字符存储的本质就是二进制字符的编码和解码规则
byte[] b_gbk = "深".getBytes("GBK");
byte[] b_utf8 = "深".getBytes("UTF-8");
byte[] b_iso88591 = "深".getBytes("ISO8859-1");
byte[] b_unicode = "深".getBytes("unicode");
将分别返回“深”这个汉字在GBK、UTF-8、ISO8859-1和unicode编码下的byte数组表示,此时b_gbk的长度为2,b_utf8的长度为3,b_iso88591的长度为1,unicode为4。
而与getBytes相对的,可以通过new String(byte[], decode)的方式来还原这个“深”字时,这个new String(byte[], decode)实际是使用decode指定的编码来将byte[]解析成字符串。
String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组。这个表示在不同情况下,返回的东西不一样! String.getBytes(String decode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示,
String s_gbk = new String(b_gbk,"GBK");
String s_utf8 = new String(b_utf8,"UTF-8");
String s_iso88591 = new String(b_iso88591,"ISO8859-1");
String s_unicode = new String(b_unicode, "unicode");
通过打印s_gbk、s_utf8、s_iso88591和unicode,会发现,s_gbk、s_utf8和unicode都是“深”,而只有s_iso88591是一个不认识的字符,为什么使用ISO8859-1编码再组合之后,无法还原“深”字呢,其实原因很简单,因为ISO8859-1编码的编码表中,根本就没有包含汉字字符,当然也就无法通过”深”.getBytes(“ISO8859-1”);来得到正确的“深”字在ISO8859-1中的编码值了,所以再通过new String()来还原就无从谈起了。
因此,通过String.getBytes(String decode)方法来得到byte[]时,一定要确定decode的编码表中确实存在String表示的码值,这样得到的byte[]数组才能正确被还原。
有时候,为了让中文字符适应某些特殊要求(如http header头要求其内容必须为iso8859-1编码)和tomcat中全部用ISO-8859-1编码,可能会通过将中文字符按照字节方式来编码的情况,如
String s_iso88591 = new String("深".getBytes("UTF-8"),"ISO8859-1")
这样得到的s_iso8859-1字符串实际是三个在 ISO8859-1中的字符,在将这些字符传递到目的地后,目的地程序再通过相反的方式String s_utf8 = new String(s_iso88591.getBytes(“ISO8859-1”),“UTF-8”)来得到正确的中文汉字“深”。这样就既保证了遵守协议规定、也支持中文
GBK码("你")->URLencode后变成->(%3F%2F)->Tomcat自动替你转一次ISO-8859-1->得到字符串( 23 43 68 23 42 68 每一个符号表示为ISO-8859-1中的一个编码)->接收页面--->再转一次为ISO-8859-1的Byte数组[23,43,68,23,42,68]--->用GBK再转为可读的文字--->(%3F%2F"---->转为("你") =>即为new String(getBytes(ISO-8859-1),UTF-8)
判断字符串的编码
private boolean useUTF8Coding(String text) {
return text.equals(new String(text.getBytes(),StandardCharsets.UTF_8));
}
使用系统默认编码获取字节流(String存在,即已经使用系统默认的编码),然后重新按照指定编码规则,看一下二者是不是相等的字符串
但是上述逻辑是不可行的,思考一下,这样获取的总是 true
如下是可以的,即如果是 iso8859 ,这样转换还可以回去,但是 utf8就会被转换失败
public static boolean isMessyCode(String str) {
String utf8 = null;
String iso88591 = null;
try {
utf8 = new String(str.getBytes("ISO-8859-1"), "UTF-8");
iso88591 = new String(utf8.getBytes("UTF-8"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return !str.equals(iso88591);
}
或者使用正则表达式
public static boolean isMessyCode(String str) {
String pattern = "[\u4e00-\u9fa5]+";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(str);
while (m.find()) {
String s = m.group();
if (!str.contains(s)) {
return true;
}
}
return false;
}