发信人: lzzzl(lzzzl) 
整理人: wenbobo(2003-08-23 11:01:40), 站内信件
 | 
 
 
unicode<->utf8我写过,但是是根据自己的需要写的,是JAVA版的,核心代码其实不长,其它辅助代码写得比较多。如果只用于特定目的,可以大大简化
 
 /**
  * Title:        <p>
  * Description:  <p>
  * Copyright:    Copyright (c) <p>
  * 2003.02.24<br>
  * Company:      philosoft<p>
  * @author	zzl([email protected])
  * @version 1.0
  */
 package com.philo.general;
 
 /**
  * UTF-8与Unicode编码的数据的转换器<br>
  * 主要目前是给数据编码以便于传输<br>
  * 例如编码后的数据只是十六制数据,数据体与协议可分离<br>
  * 此类的参数限于文本消息,特别是中英文混合的文本。如果全是中文,那么使用UTF-8编码后,将比原来的Unicode编码多出50%的长度,反而不好<br>
  * 另外对文件的转换其实无所谓编码,一律看作二进制数据字节进行十六进制编码即可,其转换过程以及数据压缩、检验等就不是UTF8这个类所该做的事情了<br>
  * 提供两种编码的数据的相互转换(目前仅通过Unicode的ISO8859-1和GB2312两个子集的测试)<br>
  * 目前为简单起见,超时不处理转换异常<br>
  * 参考文档《无废话XML》及本程序的相关开发文档
  */
 public class UTF8
 {
 	private final static char DEFAULT_UNKNOWN_CHAR ='?';		// 默认替字符
 	private static String unknowChars ="" + UTF8.DEFAULT_UNKNOWN_CHAR;	// 替代内容
 
 	/**
 	 * 设置转换时遇到的丢失或混乱字符的替代内容
 	 * @param p 替代内容
 	 */
 	public static void setUnknowChars(String p)
 	{
 		if(p==null){	// 简单容错,无效值好象不能代表什么特殊含义
 			UTF8.unknowChars ="";
 		}else{
 			UTF8.unknowChars =p;
 		}
 	}
 
 	//-------------------------------Unicode2UTF8-------------------------------
 	/**
 	 * Unicode转换为UTF-8编码的数据<br>
 	 * 为简单起见,此方法不处理异常
 	 * @param unicode Unicode编码的数据
 	 * @return UTF-8编码的数据,以16进制串的格式返回
 	 * @see toOneUTF8Hex(char)
 	 */
 	public static String Unicode2UTF8Hex(String unicode)
 	{
 		String s =null;
 
 		s ="";
 		int L =unicode.length();
 		// 逐个字符转换
 		for(int i=0;i<L;i++){
 			s +=UTF8.toOneUTF8Hex(unicode.charAt(i));
 		}
 
 		return s;
 	}
 
 	/**
 	 * 一个Unicode字符转换成一个UTF-8字符的核心算法<br>
 	 * 为简单起见,此方法不处理异常
 	 * @param c Unicode编码的字符
 	 * @pram UTF-8编码的字符,以16进制串的格式返回,不定长,但总是2,4或6之一
 	 */
 	public static String toOneUTF8Hex(char c)
 	{
 		String s =null;
 
 		s ="";
 		int i =(int)c;
 		if(i<=0x007E){
 			s +=UTF8.hex(c);																	// L=2
 		}else if(i<=0x07FF){
 			s +=UTF8.hex((byte)(0xC0 + ((i>>6) & 0x1F)));			// L=4,先移位后运算可简化一些
 			s +=UTF8.hex((byte)(0x80 + (i & 0x3F)));
 		}else{
 			s +=UTF8.hex((byte)(0xE0 + ((i>>12) & 0x0F)));		//L=6
 			s +=UTF8.hex((byte)(0x80 + ((i>>6) & 0x3F)));
 			s +=UTF8.hex((byte)(0x80 + ((i & 0x3F))));
 		}
 
 		return s;
 	}
 
 	/**
 	 * 取16进制串
 	 * @param b 数值(0∽255)
 	 * @return 2个16进制字符组成的串
 	 */
 	public static String hex(byte b)
 	{
 		String s =null;
 
 		// 转换成非负数
 		int i =(int)b;
 		i +=256;
 		i %=256;
 
 		// 转换成2个16进制字符
 		s =UTF8.hex(i>>4) + UTF8.hex(i%16);
 
 		return s;
 	}
 
 	/**
 	 * 取16进制串(方法重载)
 	 * @see hex(byte)
 	 */
 	public static String hex(char c){
 		return UTF8.hex((byte)c);
 	}
 
 	/**
 	 * 取16进制串
 	 * @param n 数值(0∽15)
 	 * @return 1个16进制字符组成的串
 	 */
 	public static String hex(int n)
 	{
 		String s ="";
 
 		// 简单处理非法值
 		n %=16;
 
 		if(n<10){
 			s +=n;
 		}else{
 			s +=(char)((int)'A' + (n-10));
 		}
 
 		return s;
 	}
 
 	//-------------------------------UTF82Unicode-------------------------------
 	/**
 	 * UTF-8编码的数据(16进制表示)转换为Unicode编码的数据<br>
 	 * 为简单起见,此方法不处理异常
 	 * @param utf8hex UTF8编码(16进制表示)的数据,长度应为偶数
 	 * @return Unicode编码的字符串
 	 */
 	public static String UTF8Hex2Unicode(String utf8hex)
 	{
 		String s =null;
 
 		s ="";
 		int L =utf8hex.length();
 		// 逐个“小块”小心转换
 		for(int i=0;i<L-1;)	//1-
 		{
 			byte b1 =(byte)UTF8.valueOf(utf8hex.substring(i,i+2));	// bi表示第i个字节,1∽3个字节将组合成一个UTF8字符。16进制字符总是成对出现,不会有孤立的情况(下同)
 			if(UTF8.isByteOfOneByteChar(b1)){	//2-
 				s +=(char)UTF8.valueOf(utf8hex.substring(i,i+2));
 				i +=2;
 			}else if(UTF8.isHeadOfTwoBytesChar(b1))
 			{
 				// 试图读取2个bytes(4个16进制字符)。
 				if(i+4<=L){
 				}else				// 当前字符表面好但内部已经变“坏”的恶劣情况不会出现在此分支
 				{
 					s +=UTF8.unknowChars;
 					break;		// 处理完毕,不必处理下标移动问题
 				}
 
 				// 尽量准确地断字,但显然太乱了也无能为力
 				byte b2 =(byte)UTF8.valueOf(utf8hex.substring(i+2,i+4));
 				if(UTF8.isComingByteOfMultBytesChar(b2)){			// 正是期望中的1个后继byte
 					s +=(char)(((b1 & 0x1F)<<6) + (b2 & 0x3F));
 					i +=4;
 				}else if(UTF8.isHeadOfUTF8Char(b2)){	// 如果下一byte是另一个Unicode的头部(当然假设这个头不是“假”的啦)也好
 					s +=UTF8.unknowChars;
 					i +=2;
 				}else{	// 否则再贪“吃”一口
 					s +=UTF8.unknowChars;
 					i +=4;
 				}
 			}else if(UTF8.isHeadOfThreeBytesChar(b1))
 			{
 				// 试图读取3个bytes(6个16进制字符)
 				if(i+6<=L){	//3-
 				}else if(i+4<=L)
 				{
 					// 处理当前字符表面好但内部已经变“坏”的恶劣情况
 					byte b2 =(byte)UTF8.valueOf(utf8hex.substring(i+2,i+4));
 					if(UTF8.isByteOfOneByteChar(b2))			// 后继有“人”,不过只能是个“小人”,即一个byte的ASCII字符
 					{
 						s +=UTF8.unknowChars;
 						i +=2;
 						continue;	// 和“小人”打交道的事留待下一循环再说,先了结当前问题再说
 					}else{
 						s +=UTF8.unknowChars;
 						break;	// 处理完毕,不必处理下标移动问题
 					}
 				}else{			// 当前字符表面好但内部已经变“坏”的恶劣情况不会出现在此分支
 					s +=UTF8.unknowChars;		// 处理完毕,不必处理下标移动问题
 					break;
 				} //-3
 
 				// 尽量准确地断字,但显然太乱了也无能为力
 				byte b2 =(byte)UTF8.valueOf(utf8hex.substring(i+2,i+4));
 				byte b3 =(byte)UTF8.valueOf(utf8hex.substring(i+4,i+6));
 				if(UTF8.isComingByteOfMultBytesChar(b2) && UTF8.isComingByteOfMultBytesChar(b3)){	// 正是期望中的2个后继bytes
 					s +=(char)(((b1 & 0x0F)<<12) + ((b2 & 0x3F)<<6) + (b3 & 0x3F));
 					i +=6;
 				}else if(UTF8.isHeadOfUTF8Char(b2)){	// 如果下一byte是另一个Unicode的头部(当然假设这个头不是“假”的啦)也好
 					s +=UTF8.unknowChars;
 					i +=2;
 				}else if(UTF8.isHeadOfUTF8Char(b3)){	// 如果再下一byte是另一个Unicode的头部(当然假设这个头不是“假”的啦)也好
 					s +=UTF8.unknowChars;
 					i +=4;
 				}else{	// 否则再贪“吃”两口
 					s +=UTF8.unknowChars;
 					i +=6;
 				}
 			}else{	// 乱得没有“头绪”,只好快刀斩乱麻了,错误的东西怎么说都是垃圾,处理掉就算不错了
 				s +=UTF8.unknowChars;
 				i +=2;		// 和垃圾打交道的事当然也留待下一循环再说啦
 			}	//-2
 		}	//-1
 
 		return s;
 	}
 
 	/**
 	 * 是否新UTF-8字符开始
 	 * @param 组成UTF-8字符的字节
 	 * @return 结果。true表示是,false表示否
 	 */
 	public static boolean isHeadOfUTF8Char(byte b)
 	{
 		boolean ok =false;
 
 		ok = ok || UTF8.isByteOfOneByteChar(b);
 		ok = ok || UTF8.isByteOfOneByteChar(b);
 		ok = ok || UTF8.isHeadOfThreeBytesChar(b);
 
 		return ok;
 	}
 
 	 /**
 	 * 是否单字节UTF-8字符
 	 * @param 组成UTF-8字符的字节
 	 * @return 结果。true表示是,false表示否
 	 */
 	public static boolean isByteOfOneByteChar(byte b){
 		return (b & 0x80)==0x00;
 	}
 
 	/**
 	 * 是否双字节UTF-8字符首字节
 	 * @param 组成UTF-8字符的字节
 	 * @return 结果。true表示是,false表示否
 	 */
 	public static boolean isHeadOfTwoBytesChar(byte b){
 		return (b & 0xE0)==0xC0;
 	}
 
 	/**
 	 * 是否三字节UTF-8字符首字节
 	 * @param 组成UTF-8字符的字节
 	 * @return 结果。true表示是,false表示否
 	 */
 	public static boolean isHeadOfThreeBytesChar(byte b){
 		return (b & 0xF0)==0xE0;
 	}
 
 	/**
 	 * 是否多字节UTF-8字符后继字节
 	 * @param 组成UTF-8字符的字节
 	 * @return 结果。true表示是,false表示否
 	 */
 	public static boolean isComingByteOfMultBytesChar(byte b){
 		return (b & 0xC0)==0x80;
 	}
 
 	/**
 	 * UTF8Hex2Unicode()中所有组合的完全测试<br>
 	 * 根据Case树得到的解析单个字符时可能的所有20种组合
 	 */
 	private static void completedTest()
 	{
 		String[] list ={
 			"41",
 			"C2B1",
 			"C241",
 			"C2C2",
 			"C2E4",
 			"C2F0",
 			"C2",
 			"E4B8AD",
 			"E4B841",
 			"E4B8C2",
 			"E4B8E4",
 			"E4B8F0",
 			"E4B8",
 			"E441",
 			"E4C2",
 			"E4E4",
 			"E4F0",
 			"E4",
 			"F0",
 			""
 		};
 
 		int L =list.length;
 		for(int i=0;i<L;i++){
 			Debugger.debug("" + (i+1) + ":\tUTF8Hex2Unicode(\"" + list[i] + "\")=" + UTF8.UTF8Hex2Unicode(list[i]));
 		}
 	}
 
 	/**
 	 * 16进制串转10进制数值<br>
 	 * 为简单起见,此方法不处理异常
 	 * @param hex 16进制字符组成的串
 	 * @return 转换得到的数值
 	 */
 	public static int valueOf(String hex)
 	{
 		int k =0;
 
 		int L =hex.length();
 		for(int i=0;i<L;i++)
 		{
 			char c =hex.toUpperCase().charAt(i);	// 统一大小写可简化后面的代码
 			if(c>='0' && c<='9'){
 				k =(k<<4) + ((int)c) -((int)'0');
 			}else{
 				k =(k<<4) + 10 + ((int)c) -((int)'A');	// 如果传入的数据不合法,就难说是n进制还是-m进制了
 			}
 
 		}
 
 		return k;
 	}
 
 	/**
 	 * 16进制串转10进制数值(方法重载)
 	 * @see valueOf(String)
 	 */
 	public static int valueOf(char c){
 		return UTF8.valueOf("" + c);
 	}
 
 	/**
 	 * 调试入口
 	 * @param argv 命令行参数(一维字符数组)
 	 */
 	public static void main(String[] argv)
 	{
 		Exception ee =null;
 
 		try
 		{
 			if(true)
 			{
 				Debugger.debug("hex(\"A\")=" + UTF8.hex('A'));
 
 				Debugger.debug("valueOf(\"41\")=" + UTF8.valueOf("41"));
 				Debugger.debug("valueOf('2'))=" + UTF8.valueOf('2'));
 				Debugger.debug("valueOf('B'))=" + UTF8.valueOf('B'));
 
 				Debugger.debug("unicode(\"A\")=" + hex('A'));
 				Debugger.debug("unicode(\"±\")=" + hex('±'));
 				Debugger.debug("unicode(\"中\")=" + hex('中'));
 				Debugger.debug("1&2=" + (1&2));
 			}else{
 			}
 
 			String s =UTF8.Unicode2UTF8Hex(argv[0]);
 			Debugger.debug("Unicode2UTF8Hex(\"" + argv[0] + "\")=" + s);
 
 			// 加点干扰(重点考查GB2312区)
 			s +="E4B8AD";	// 正常
 
 			s +="E4E4AD";	// 结束得早
 			s +="E4B8E4";
 			s +="E441AD";
 			s +="E4B841";
 
 			s +="80" + "E4B8AD";	// 无头绪
 			Debugger.debug("UTF8Hex2Unicode(\"" + s + "\")=" + UTF8.UTF8Hex2Unicode(s));
 
 			UTF8.completedTest();
 		}catch(ArrayIndexOutOfBoundsException aioobe){
 			ee =aioobe;
 			Debugger.debug("参数不足!");
 		}catch(Exception e){
 			ee =e;
 		}finally
 		{
 			if(ee==null){
 			}else{
 				Debugger.debug(ee);
 				Debugger.debug("用法:...<要转换的字符串>");
 			}
 		}
 	}
 }
 
  ---- 不想计较得失,却总在计较得失      | 
 
 
 |