`

UTF8 与 UTF16 编码

阅读更多

Unicode 的发展,英文好的直接去 unicode.org 上去看吧,不好的可以移步到这里 看dengyunze的总结:《关于UTF8,UTF16,UTF32,UTF16-LE,UTF16-BE 》 。此文讲的清除明白:为了能把世界上的所有字符都表示,理论上需要用 UTF-16,但是由于“大部分”(当然这是欧美那边技术宅男拍脑袋想出来的大部分啦~)的字符只需要 1 个字节就搞定了,用 UTF16 实在太浪费啦,于是他们就用了 UTF8. 对于那些个“少数”(比如中日韩)的字符,就通过一个 UTF8-UTF16 的转换来表示。

UTF8 和 UTF16 都是变长表示的,为啥欧美技术宅会觉得太浪费了咧?因为欧美字符 0x0000 - 0x00FF 就搞定了,UTF8 最小变长是 1 个字节,而 UTF16 变长是 2 个字节,所以……(↓看下图中 code unit size)

注意:上面这个图中,UTF-16 和 UTF-16LE 是一样的,因为…… UTF16 默认就是 UTF-16LE

 

那么,UTF8是如何表示 的咧?↓看下图

 

↓↓ 举例

表示的方法跟上上个图对应,第一个字节中,从左往右第一个 10 前面的 “1” 的个数表示后面还有这么多个的字节在表示这个字符。UTF8 最多可以表示 31 bit 的字符。

 

 

UTF16 编码的过程

v  = 0x64321
v′ = v - 0x10000
   = 0x54321
   = 0101 0100 0011 0010 0001
vh = v′ >> 10
   = 01 0101 0000 // higher 10 bits of v′
vl = v′ & 0x3FF
   = 11 0010 0001 // lower  10 bits of v′
w1 = 0xD800 + vh
   = 1101 1000 0000 0000
   +        01 0101 0000
   = 1101 1001 0101 0000
   = 0xD950 // first code unit of UTF-16 encoding
w2 = 0xDC00 + vl
   = 1101 1100 0000 0000
   +        11 0010 0001
   = 1101 1111 0010 0001
   = 0xDF21 // second code unit of UTF-16 encoding

 

附一段 java 版本的 UTF8 与 UTF16 的相互转换,代码来源于 Lucene3.6

/**
	 * Interprets the given byte array as UTF-8 and converts to UTF-16. The
	 * {@link CharsRef} will be extended if it doesn't provide enough space to
	 * hold the worst case of each byte becoming a UTF-16 codepoint.
	 * <p>
	 * NOTE: Full characters are read, even if this reads past the length passed
	 * (and can result in an ArrayOutOfBoundsException if invalid UTF-8 is
	 * passed). Explicit checks for valid UTF-8 are not performed.
	 */
	// TODO: broken if chars.offset != 0
	public static void UTF8toUTF16(byte[] utf8, int offset, int length,
			CharsRef chars) {
		int out_offset = chars.offset = 0;
		final char[] out = chars.chars = ArrayUtil.grow(chars.chars, length);
		final int limit = offset + length;
		while (offset < limit) {
			int b = utf8[offset++] & 0xff;
			if (b < 0xc0) {
				assert b < 0x80;
				out[out_offset++] = (char) b;
			} else if (b < 0xe0) {
				out[out_offset++] = (char) (((b & 0x1f) << 6) + (utf8[offset++] & 0x3f));
			} else if (b < 0xf0) {
				out[out_offset++] = (char) (((b & 0xf) << 12)
						+ ((utf8[offset] & 0x3f) << 6) + (utf8[offset + 1] & 0x3f));
				offset += 2;
			} else {
				assert b < 0xf8 : "b=" + b;
				int ch = ((b & 0x7) << 18) + ((utf8[offset] & 0x3f) << 12)
						+ ((utf8[offset + 1] & 0x3f) << 6)
						+ (utf8[offset + 2] & 0x3f);
				offset += 3;
				if (ch < UNI_MAX_BMP) {
					out[out_offset++] = (char) ch;
				} else {
					int chHalf = ch - 0x0010000;
					out[out_offset++] = (char) ((chHalf >> 10) + 0xD800);
					out[out_offset++] = (char) ((chHalf & HALF_MASK) + 0xDC00);
				}
			}
		}
		chars.length = out_offset - chars.offset;
	}

 /** Encode characters from a char[] source, starting at
   *  offset for length chars. After encoding, result.offset will always be 0.
   */
 public static void UTF16toUTF8(final char[] source, final int offset, final int length, BytesRef result) {

    int upto = 0;
    int i = offset;
    final int end = offset + length;
    byte[] out = result.bytes;
    // Pre-allocate for worst case 4-for-1
    final int maxLen = length * 4;
    if (out.length < maxLen)
      out = result.bytes = new byte[maxLen];
    result.offset = 0;

    while(i < end) {
      
      final int code = (int) source[i++];

      if (code < 0x80)
        out[upto++] = (byte) code;
      else if (code < 0x800) {
        out[upto++] = (byte) (0xC0 | (code >> 6));
        out[upto++] = (byte)(0x80 | (code & 0x3F));
      } else if (code < 0xD800 || code > 0xDFFF) {
        out[upto++] = (byte)(0xE0 | (code >> 12));
        out[upto++] = (byte)(0x80 | ((code >> 6) & 0x3F));
        out[upto++] = (byte)(0x80 | (code & 0x3F));
      } else {
        // surrogate pair
        // confirm valid high surrogate
        if (code < 0xDC00 && i < end) {
          int utf32 = (int) source[i];
          // confirm valid low surrogate and write pair
          if (utf32 >= 0xDC00 && utf32 <= 0xDFFF) { 
            utf32 = (code << 10) + utf32 + SURROGATE_OFFSET;
            i++;
            out[upto++] = (byte)(0xF0 | (utf32 >> 18));
            out[upto++] = (byte)(0x80 | ((utf32 >> 12) & 0x3F));
            out[upto++] = (byte)(0x80 | ((utf32 >> 6) & 0x3F));
            out[upto++] = (byte)(0x80 | (utf32 & 0x3F));
            continue;
          }
        }
        // replace unpaired surrogate or out-of-order low surrogate
        // with substitution character
        out[upto++] = (byte) 0xEF;
        out[upto++] = (byte) 0xBF;
        out[upto++] = (byte) 0xBD;
      }
    }
    //assert matches(source, offset, length, out, upto);
    result.length = upto;
  }
分享到:
评论

相关推荐

    UTF8转16进制工具 Utf8ToHex

    标题中的"UTF8转16进制工具 Utf8ToHex"指的是一个能够将UTF-8编码的字符串转换成16进制表示形式的实用工具。描述中提到的例子,中文的“你好”在UTF-8编码下是"\xE4\xBD\xA0\xE5\xA5\xBD",这个就是将UTF-8编码转换...

    UTF-16汉字编码表

    与UTF-8相比,UTF-16在处理包含大量非拉丁文字符的语言时具有更好的性能。 #### 二、UTF-16编码原理 UTF-16将Unicode字符集中的每一个字符映射到一个16位或32位的数值上。对于基本多文种平面(Basic Multilingual ...

    UTF-8编码表

    如果UNICODE字符由2个字节表示,则编码成UTF-8很可能需要3个字节,而如果UNICODE字符由4个字节表示,则编码成UTF-8可能需要6个字节。用4个或6个字节去编码一个UNICODE字符可能太多了,但很少会遇到那样的UNICODE...

    c++ UTF-8 UTF-16转换

    在编程领域,尤其是在涉及到字符编码的时候,理解和操作UTF-8和UTF-16之间的转换是一项基本技能。UTF-8和UTF-16是两种广泛使用的Unicode编码格式,它们各自有其特性和应用场景。本文将深入探讨如何利用C++来实现这两...

    MySQL 编码utf8 与 utf8mb4 utf8mb4_unicode_ci 与 utf8mb4_general_ci

    这里我们将深入探讨UTF8和UTF8MB4两种编码格式,以及它们各自的排序规则`utf8mb4_unicode_ci`和`utf8mb4_general_ci`。 首先,UTF-8是一种广泛使用的Unicode字符编码方案,它允许使用1到4个字节来表示不同的字符。...

    utf-8/utf-16转换代码完整版

    最近需要对Linux与Windows平台下的字符传输出现乱码,对...参考了网上的UTF-8/UTF-16转换的资料,只有0x10000以下的Unicode编码进行了转换;对其代码进行了修改和补充,可以实现所有的UTF-8/UTF-16的转换,分享给大家。

    c语言gbk、utf8转换编码表及函数

    本篇将详细介绍GBK与UTF-8编码的区别,以及如何在C语言中进行这两种编码的转换。 1. **GBK编码** - GBK是中国大陆广泛使用的汉字编码标准,它是GB2312的扩展,包含了更多的汉字和符号,总共约2万多个汉字。 - GBK...

    UTF8-无BOM转为UTF16LE

    本主题主要关注UTF8和UTF16LE两种不同的字符编码格式之间的转换,特别是如何进行无BOM(字节顺序标记)的处理。下面我们将深入探讨这两种编码方式以及它们在实际应用中的转换。 首先,UTF8是一种广泛使用的变长...

    gb2312_unicode_utf8汉字编码对照表

    ### gb2312、Unicode与UTF-8汉字编码对照解析 #### 一、引言 随着信息技术的发展,字符编码成为计算机科学中的一个重要概念。不同的字符集和编码方式被广泛应用于各种场合,其中gb2312、Unicode以及UTF-8是较为...

    UTF-8toGBK_labview编码gbk_LabVIEWUTF-8_utf-8toGbk_

    本篇文章将详细探讨UTF-8与GBK编码,以及如何在LabVIEW环境下进行这两种编码之间的转换。 首先,UTF-8(Unicode Transformation Format - 8 bit)是一种变长的Unicode编码,它使用1到4个字节来表示一个字符。UTF-8...

    Ansi Unicode UTF8编码转换及代码示例

    ### ANSI、Unicode与UTF-8编码转换及相关代码示例 #### 一、基本概念解析 在探讨ANSI、Unicode以及UTF-8之间的转换之前,我们首先需要了解这三种编码的基本概念及其应用场景。 - **ANSI编码**:ANSI(American ...

    实现ascii ,utf8,utf16三种编码之间的转换.zip

    ASCII、UTF-8和UTF-16是三种常见的字符编码标准,每种都有其独特的特性和用途。本篇文章将深入探讨这三种编码方式,并解释如何在它们之间进行转换。 **ASCII编码**(American Standard Code for Information ...

    utf8汉字编码16进制对照.xls

    utf8汉字编码16进制对照,utf8编码在编程中使用相当平凡,汉字转换成utf8的16进制必须查本表

    C# 生成xml文件,编码为utf-8方法

    此外,UTF-8 编码也是 XML 文件的默认编码格式,使用它可以与其他系统和应用程序进行良好的集成。 需要注意的是,在生成 XML 文件时,需要确保 XML 声明中的 encoding 属性也设置为 UTF-8,以确保 XML 文件的编码...

    Utf-8编码与解码(vb6代码)

    UTF-8编码是一种广泛使用的Unicode字符编码方案,它在互联网上尤其常见,因为其兼容性和效率。UTF-8的特点是每个Unicode字符可以被编码为1到4个字节,其中ASCII字符(基本的英文字符)仅需1个字节。这使得UTF-8在...

    STM32 MDK utf8 gbk编码转换

    在提供的`gbk_utf8_unicode.c`和`gbk_utf8_unicode.h`文件中,可能包含了用于实现UTF-8与GBK之间转换的函数。这些函数可能包括将GBK编码的字符串转换为UTF-8,以及将UTF-8编码的字符串转换为GBK。 例如,一个可能的...

    utf8与gb312编码互相转换

    本篇将深入探讨UTF-8与GBK(GB2312)编码的互相转换,并重点关注在涉及ASCII编码时可能出现的问题。 首先,让我们理解这两种编码的基础知识。UTF-8是一种变长的Unicode编码,它使用1到4个字节来表示一个字符,其中...

    UTF-8编码转化(Visual Basic)

    UTF-8是Unicode的一种编码方式,它的特点是前128个字符(ASCII字符)与ASCII编码相同,对于其他Unicode字符,使用多个字节进行编码,每个字节都以1或1110开头。 2. **读取UTF-8文件**: 在Visual Basic中,使用`My...

    Xcode控制台把UTF8编码显示成中文

    然而,当这些信息中包含中文字符时,Xcode的控制台默认可能会按照UTF8编码显示,而不是直接以中文形式展示,这给调试带来了不便。标题"Xcode控制台把UTF8编码显示成中文"正是针对这一问题提供了解决方案。 首先,...

    utf8.zip_UTF8_VB6 UTF-8_cutf8.cls_utf8解码在线_vb6

    在VB6(Visual Basic 6)环境中,处理UTF-8编码是常见的需求,尤其是在与网络交互,如发送HTTP请求或解析URL时。UTF-8是一种广泛使用的Unicode字符编码方案,它可以表示Unicode字符集中的所有字符,包括各种语言的...

Global site tag (gtag.js) - Google Analytics