刚刚研究的一个问题“Java同样的汉字在服务器和本地的电脑上URLencode 出来的结果不一致”也涉及了字符串的编码格式。
最简单的方法就是:Charset.defaultCharset();
Servlet中可以使用:request.getCharacterEncoding();
也可以使用上文提到的,不过也不那么简单:
dfltEncName = (String)AccessController.doPrivileged(new GetPropertyAction("file.encoding"));
也有一些其它方式可以参考,如下面这个就比较麻烦了!
public static String getEncoding(String str) {
String encode = "GB2312";
try {
if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是GB2312
String s = encode;
return s; //是的话,返回“GB2312“,以下代码同理
}
} catch (Exception exception) {
}
encode = "ISO-8859-1";
try {
if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是ISO-8859-1
String s1 = encode;
return s1;
}
} catch (Exception exception1) {
}
encode = "UTF-8";
try {
if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是UTF-8
String s2 = encode;
return s2;
}
} catch (Exception exception2) {
}
encode = "GBK";
try {
if (str.equals(new String(str.getBytes(encode), encode))) { //判断是不是GBK
String s3 = encode;
return s3;
}
} catch (Exception exception3) {
}
return ""; //如果都不是,说明输入的内容不属于常见的编码格式。
2017-02-10更新
纠正对”Charset.defaultCharset()“的错误理解,”Charset.defaultCharset()“方法的注释内容是返回此Java虚拟机的默认字符集。默认字符集在虚拟机启动期间确定,并且通常取决于底层操作系统的区域设置和字符集。而字符串的编码是受来源影响的!
但是如”Java同样的汉字在服务器和本地的电脑上URLencode 出来的结果不一致“中提到的,”Charset.defaultCharset()“实际上是返回的”file.encoding“,也就是文件采用的编码。
使用”System.getProperties()“ 可以得到如下几种编码相关的属性:
file.encoding.pkg=sun.io
sun.jnu.encoding=GBK
file.encoding=UTF-8
sun.io.unicode.encoding=UnicodeLittle
sun.cpu.endian=little
sun.jnu.encoding 猜测是系统的默认编码,参考:
关于 Java 的系统属性 sun.jnu.encoding 和 file.encoding 的区别
sun.jnu.encoding 影响文件名的创建,而 file.encoding 则影响到文件内容。
所以说,在我们使用 Java 处理中文文件的时候,如果发现文件的中文内容没有乱码,而文件的中文名发生乱码,我们就应当多考虑一下 sun.jnu.encoding 和 file.encoding 的区别了。
file.encoding 处理文件内容默认使用的编码;
使用Eclipse main 方法测试时,会自动根据文件内容的编码确定启动JVM使用的编码,如下图:
如果在这里配置了和文件编码不同的编码方式,文件中的字符串输出可能就会产生乱码,如下面的代码输出为:
ISO-8859-1
?????????? ?????18
public static void main(String[] args) {
Properties pro = System.getProperties();
System.out.println(pro.getProperty("file.encoding"));
try {
String destination = new String("中文エキサイト네이버 중국어사전17");
if(destination.equals(new String(destination.getBytes("GB2312"), "GB2312")))
{
System.out.println(destination);
}
destination = new String("中文エキサイト네이버 중국어사전18");
if(destination.equals(new String(destination.getBytes("utf-8"), "utf-8")))
{
System.out.println(destination);
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
由于文件的编码是”UTF-8“,而调试配置的是:ISO-8859-1
上面的代码我们创建一个名为 ”CharsetTest3.java“的文件,在CMD下编译执行:
打开CMD,切换到文件所在目录:
D:\javaProject\javatrans\src\main\java\wasdev\sample\servlet>javac CharsetTest3.
java
CharsetTest3.java:17: 错误: 编码GBK的不可映射字符
String destination = new String("涓枃銈ㄣ偔銈点偆銉堧
劋鞚措矂 欷戧淡鞏挫偓鞝?17");
^
CharsetTest3.java:23: 错误: 编码GBK的不可映射字符
destination = new String("涓枃銈ㄣ偔銈点偆銉堧劋鞚措矂
欷戧淡鞏挫偓鞝?18");
^
2 个错误
没有指定编码,与系统默认不符!
D:\javaProject\javatrans\src\main\java\wasdev\sample\servlet>javac CharsetTest3.
java -encoding utf-8
使用”-encoding utf-8“指定编码,执行成功。
注意:在CMD在测试的时候最好不要使用包名,不然很麻烦,我真想说恨死Java了(包的查找方式太恶心,或许是因为性能考虑所以写的这么死板)。
我的文件完整路径是:D:\javaProject\javatrans\src\main\java\wasdev\sample\servlet\CharsetTest3.java
可以通过” -Dfile.encoding=utf-8“指定编码方式
但是CMD应该是使用的GBK编码,不支持韩文,我们把韩文复制粘贴到CMD窗口中发现这一点:
只见光标后移了,却看不见内容。
sun.cpu.endian=little CPU的字节序为小结尾,这涉及到”主机字节序和网络字节序“的问题,通常主机字节序为小结尾(Little endian:将低序字节存储在起始地址),网络字节序为大结尾(Big endian:将高序字节存储在起始地址)。但不同的处理器(CPU)、操作系统也有可能不同。
优化后的方法:
/**
* 判断字符串的编码
*
* @param str
* @return
*/
public static String getEncoding(String str) {
String encode[] = new String[]{
"UTF-8",
"ISO-8859-1",
"GB2312",
"GBK",
"GB18030",
"Big5",
"Unicode",
"ASCII"
};
for (int i = 0; i < encode.length; i++){
try {
if (str.equals(new String(str.getBytes(encode[i]), encode[i]))) {
return encode[i];
}
} catch (Exception ex) {
}
}
return "";
}
说明:把”UTF-8“放在第一位是因为现在使用的比较普遍,见下图:
显示Google记录的2001年至2012年网络上主要编码的使用情况。参考:https://en.wikipedia.org/wiki/UTF-8测试代码:
public static void main(String[] args) {
String str = "中文エキサイト";
String encode = getEncoding(str);
System.out.println(encode);
str = "中文エキサイト네이버 중국어사전";
encode = getEncoding(str);
System.out.println(encode);
}
执行输出为:UTF-8
UTF-8注意:如果将数组”String encode[]“中”UTF-8“和”GB2312“的位置换一下,结果就会发生改变为:
GB2312
UTF-8
这是为什么?通过监视以下代码中的”destination.getBytes“,我们可以发现是存在重码区域的!
destination = new String("中文エキサイト네이버 중국어사전17");
if(destination.equals(new String(destination.getBytes("GB2312"), "GB2312")))
{
System.out.println(destination);
}
destination = new String("中文エキサイト네이버 중국어사전18");
if(destination.equals(new String(destination.getBytes("utf-8"), "utf-8")))
{
System.out.println(destination);
}
如下图:
所以”getEncoding“方法的正确性有是局限性的,一方面是数组中包含的编码的各类是否够全,一方面是需要判断的字符串特征是否明显。
2018-12-13更新
原理是根据编码字符集和给定字符串的编码相似度去猜测,并不能给出百分百正确的结果。
比如:你想判断字符串“123456”的编码,但是由于每一个编码字符集中都包含数字的编码,所以返回哪一个编码都没有错,但可能不是你期望的。
======================文档信息===========================
版权声明:非商用*转载-保持署名-注明出处
署名(BY) :testcs_dn(微wx笑)
文章出处:[无知人生,记录点滴](http://blog.csdn.net/testcs_dn)
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net