ISO8859-1字符集与其他字符集兼容性测试

发布时间 2023-03-26 23:00:53作者: 逐梦北京

ISO8859-1字符集中所有字符只占一个字节,8位,一个字节的编码空间为0x00-0xFF共256个字符。

 

ISO8859-1字符集中的部分(GBK GB2312 )或全部(UTF-8 UTF-16)字符在其他字符集中会存在,而且编码值还相同。

 

当把一个字符集中某个字符转换成另外一种字符集中的字符时,在转换过程中会有很大一部分字符在另一种字符集中是没有的(比如GBK繁体字符到GB2312),这时会使用另一种字符集中的问号代替这个未知字符,且编为63。但一般从多字节编码字符集(GBK GB2312 UTF-8 UTF-16)转换成单字节字符ISO8859-1时,是可以映射的,不会出现找不到可映射字符,因为每个字节的内容在ISO8859-1中都是找得到的,这就是为什么把一个 GBK、GB2312、UTF-8等编码的字符串以IS08859-1编码后,编码信息不会丢失的原因,最后还是可以还原成原来样子。

 

在Java里从一种字符转换成另一种字符集中的字符时,转换过程是要借助中间编码的,这个中间码就是Java语言本身所使用的编码——Unicode。现以ISO8859-1字符集中的¤字符转为GBK中的该字符为例:¤的ISO8859-1编码为A4,转换到Unicode字符集中后还是为A4(Unicode前256字个符与ISO8859-1是完全兼容的),然后由中间Unicode码映射到GBK字符集中相应字符,如果这个Unicode字符在GBK中存在,则使用对应的GBK编码,否则使用问号编码63代替,当然这一中间转换过程是由Java来帮我们实现的,最后我们的感觉就是由ISO8859-1直接转到了GBK编码。注,两种不同的编码中的相同的字符的编码不一定相同,这就是所谓的编码不兼容问题,比如说ISO8859-1字符¤的编码为A4,而映射到UTF-8后所对应的编码却为C2A4了。

 

从输出的附件可以看出(注,最好用记事本打开),GB2312、GBK、UTF-8字符集能兼容(兼容是指同一字符在两种不同字符集中都存在且编码还要相同)ISO8859-1的0x00-0x7F共128个字符。

 

ISO8859-1字符映射到GB2312、GBK字符集中后,能映射的字符这两种字符集基本上一样,只是在GBK字符集比GB2312多映射一个字符(B7·)。

 

ISO8859-1中编码大于0x7F的字符可全部映射到UTF-8字符,只是编码占用了两字节,但0x7F之后的字符只有一部分可以映射到GB2312、GBK字符集中。

 

Unicode、UTF-16编码完全兼容ISO8859-1字符集,即ISO8859-1中的字符在Unicode、UTF-16中存在,且编码完全相同。

 

编码大于0x7F的ISO8859-1字符,能映射到GB2312、GBK、UTF-8的都占两个字节,UTF-16就不用说了,肯定是两字节,只不过编码未变。

 

下面程序就是用来把ISO8859-1字符集映射到其他字符集的代码,它会把映射完后的字符分别输出到不同文件中,且无法映射(只ISO8859-1中某字符无法在其他字符集中找到)的字符不会输出到文件中。

 

Java代码  收藏代码
  1. import java.io.FileNotFoundException;  
  2. import java.io.FileOutputStream;  
  3. import java.io.IOException;  
  4. import java.io.OutputStreamWriter;  
  5. import java.io.UnsupportedEncodingException;  
  6.   
  7. /** 
  8.  * ISO8859-1与其他字符兼容性测试 
  9.  * @author jzj 
  10.  */  
  11. public class ISOCharSet2OtherCharSet {  
  12.     public static void main(String[] args) throws UnsupportedEncodingException {  
  13.         try {  
  14.             String charSet = "GBK";  
  15.             toOtherCharSet(charSet);  
  16.             charSet = "UTF-8";  
  17.   
  18.             toOtherCharSet(charSet);  
  19.             charSet = "GB2312";  
  20.             toOtherCharSet(charSet);  
  21.   
  22.             charSet = "UTF-16";  
  23.             toOtherCharSet(charSet);  
  24.         } catch (UnsupportedEncodingException e) {  
  25.             e.printStackTrace();  
  26.         } catch (IOException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30.   
  31.     private static void toOtherCharSet(String charSet)  
  32.             throws UnsupportedEncodingException, FileNotFoundException, IOException {  
  33.         OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("e:/tmp/"  
  34.                 + charSet + ".txt"), charSet);  
  35.         osw.write("可映射字符 ISO8859-1 -> " + charSet + "\r\n");  
  36.         osw.write("\r\nISO8859-1=XX" + " " + charSet + "=XX\r\n");  
  37.   
  38.         StringBuffer sb = new StringBuffer();  
  39.         //遍历256个ISO8859-1字符  
  40.         for (int i = 0; i <= 255; i++) {  
  41.             //ISO8859-1字符真实编码  
  42.             byte[] b = new byte[] { (byte) i };  
  43.   
  44.             byte[] encodeArr = new String(b, "ISO8859-1").getBytes(charSet);  
  45.             short codeShort = encodeArr[0];  
  46.   
  47.             /* 
  48.              * 只有UTF-16才是固定4字节(前两字节为FE FF,后两个字节者是真真内容),其他编码可编码后为一个 
  49.              * 字节,也可能为两个字节,且真实编码最多为两个字节。所以单字节ISO字符在其他字符集中可能为双字 
  50.              * 节,如果为双字节时,取后两个字节(针对UTF-16,其他字符集最多为双字节)。 
  51.              */  
  52.             if (encodeArr.length > 1) {  
  53.                 codeShort = (short) ((encodeArr[encodeArr.length - 2] << 8) | (encodeArr[encodeArr.length - 1] & 0x00FF));  
  54.             }  
  55.             String gbkEncodeHex = short2Hex(codeShort);  
  56.             String isoEncodeHex = byte2Hex((byte) i);  
  57.   
  58.             //如果ISO字符不能转换到指定的字符集中的字符时,会以问号替换,这里不输出不能映射的字符  
  59.             if (codeShort != 63 || (i == 63)) {  
  60.                 osw.write(isoEncodeHex + "=" + new String(b, "ISO8859-1") + " ");  
  61.                 osw.write(gbkEncodeHex + "=" + new String(encodeArr, charSet) + "\r\n");  
  62.             }  
  63.             //记录不兼容字符,即ISO8859-1中的字符在其他字符集中不存在,排除问题,因为问题肯定是兼容的  
  64.             if (codeShort == 63 && i != 63) {  
  65.                 sb.append(isoEncodeHex);  
  66.                 sb.append("=");  
  67.                 sb.append(new String(b, "ISO8859-1"));  
  68.                 sb.append("\r\n");  
  69.             }  
  70.         }  
  71.         if (sb.length() > 0) {  
  72.             osw.write("\r\n不兼容字符:\r\n" + sb);  
  73.         }  
  74.         osw.flush();  
  75.         osw.close();  
  76.     }  
  77.   
  78.     /** 
  79.      * 短整型转十六进制 
  80.      * @param coding 
  81.      * @return 
  82.      */  
  83.     private static String short2Hex(short coding) {  
  84.         return Integer.toHexString(coding & 0x00FFFF | 0xFF0000).toUpperCase().substring(  
  85.                 2, 6);  
  86.     }  
  87.   
  88.     /** 
  89.      * 字节型转十六进制 
  90.      * @param coding 
  91.      * @return 
  92.      */  
  93.     private static String byte2Hex(byte coding) {  
  94.         return Integer.toHexString(coding & 0x00FF | 0xFF00).toUpperCase()  
  95.                 .substring(2, 4);  
  96.     }  
  97. }