因為打開記事本亂碼后,就去翻了網上比較好的博客作為材料,本文對網上的博客進行的再次的編輯撰寫。
一、首先什么是編碼
編碼意思是一種含義的內容,以兩種不同含義表達, 這兩種表達就是其中一種對另一種的編碼,類似的有,文字編碼成2進制和明文編碼成密文,中文翻譯成英語也是一種語言翻譯成另一種語言。
二、字符集
在計算機里,不論何種語言的字符,都是以二進制的形式保存、傳輸、交換的。這就牽扯到字符的編碼和解碼問題了:同樣含義的字符,如何在人類理解的形狀這一形式與計算機內部的二進制形式之間做出對應呢?
不過,在回答這個問題之前,還有一個更基本的問題需要解答:當計算機遭遇字符,我們到底需要計算機表示哪些字符?
這就引出了字符集(Charset)的概念。通常來說,字符集是一類字符按照一定方式編號排成的表格。比如,中國為漢字曾陸續制定了多個字符集:GB2312、GBK、GB18030;其中 GBK 字符集收錄了 21886 個漢字和圖形符號。又例如,Unicode 對世界上大多數文字系統進行了同一的整理和編碼,因此正在逐漸成為計算機領域內的事實標準。基于 Unicode 字符集,流行的字符集有 UTF-8、UTF-16、UTF-32 等。
三、Unicode
正如上一節所說,世界上存在著多種編碼方式,同一個二進制數字可以被解釋成不同的符號。因此,要想打開一個文本文件,就必須知道它的編碼方式,否則用錯誤的編碼方式解讀,就會出現亂碼。為什么電子郵件常常出現亂碼?就是因為發信人和收信人使用的編碼方式不一樣。
可以想象,如果有一種編碼,將世界上所有的符號都納入其中。每一個符號都給予一個獨一無二的編碼,那么亂碼問題就會消失。這就是 Unicode,就像它的名字都表示的,這是一種所有符號的編碼。
Unicode 當然是一個很大的集合,現在的規模可以容納100多萬個符號。每個符號的編碼都不一樣,比如,U+0639表示阿拉伯字母Ain,U+0041表示英語的大寫字母A,U+4E25表示漢字嚴。具體的符號對應表,可以查詢[unicode.org],或者專門的[漢字對應表]。
四、Unicode 的問題
這個二進制代碼應該如何存儲。
比如,漢字嚴的 Unicode 是十六進制數4E25,轉換成二進制數足足有15位(100111000100101),也就是說,這個符號的表示至少需要2個字節。表示其他更大的符號,可能需要3個字節或者4個字節,甚至更多。
這里就有兩個嚴重的問題,第一個問題是,如何才能區別 Unicode 和 ASCII ?計算機怎么知道三個字節表示一個符號,而不是分別表示三個符號呢?第二個問題是,我們已經知道,英文字母只用一個字節表示就夠了,如果 Unicode 統一規定,每個符號用三個或四個字節表示,那么每個英文字母前都必然有二到三個字節是0,這對于存儲來說是極大的浪費,文本文件的大小會因此大出二三倍,這是無法接受的。
它們造成的結果是:1)出現了 Unicode 的多種存儲方式,也就是說有許多種不同的二進制格式,可以用來表示 Unicode。2)Unicode 在很長一段時間內無法推廣,直到互聯網的出現。
五、UTF-8 編碼
互聯網的普及,強烈要求出現一種統一的編碼方式。UTF-8 就是在互聯網上使用最廣的一種 Unicode 的實現方式。其他實現方式還包括 UTF-16(字符用兩個字節或四個字節表示)和 UTF-32(字符用四個字節表示),不過在互聯網上基本不用。重復一遍,這里的關系是,UTF-8 是 Unicode 的實現方式之一。
UTF-8 最大的一個特點,就是它是一種變長的編碼方式。它可以使用1-4個字節表示一個符號,根據不同的符號而變化字節長度。
UTF-8 的編碼規則很簡單,只有二條:
1)對于單字節的符號,字節的第一位設為0,后面7位為這個符號的 Unicode 碼。因此對于英語字母,UTF-8 編碼和 ASCII 碼是相同的。
2)對于n字節的符號(n > 1),第一個字節的前n位都設為1,第n + 1位設為0,后面字節的前兩位一律設為10。剩下的沒有提及的二進制位,全部為這個符號的 Unicode 碼。
下表總結了編碼規則,字母x表示可用編碼的位。
Unicode符號范圍 | UTF-8編碼方式
(十六進制) | (二進制)
------------------+---------------------------------------------
'' 0000 0000-0000 007F | 0xxxxxxx
'' 0000 0080-0000 07FF | 110xxxxx 10xxxxxx
'' 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
'' 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
跟據上表,解讀 UTF-8 編碼非常簡單。如果一個字節的第一位是0,則這個字節單獨就是一個字符;如果第一位是1,則連續有多少個1,就表示當前字符占用多少個字節。
下面,還是以漢字嚴為例,演示如何實現 UTF-8 編碼。
嚴的 Unicode 是4E25(100111000100101),根據上表,可以發現4E25處在第三行的范圍內(0000 0800 - 0000 FFFF),因此嚴的 UTF-8 編碼需要三個字節,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,從嚴的最后一個二進制位開始,依次從后向前填入格式中的x,多出的位補0。這樣就得到了,嚴的 UTF-8 編碼是11100100 10111000 10100101,轉換成十六進制就是E4B8A5。
六、Windows系統記事本編碼
曾經有一個笑話,把「聯通」兩個字寫在txt記事本上,保存再次打開后,“聯通”這兩個字就消失了。如果我沒記錯的話,還曾有好事者據此編排,認定 Windows 背后的微軟和聯通有仇,故意不讓聯通二字正常顯示。
Windows 系統記事本里的「Unicode 編碼」實際上是「帶有 BOM 的小端序 UTF-16」。這意味著 Windows 將 Unicode 字符集和 UTF-16 劃上了等號。這實際是不對的。
七、Windows 記事本都做了什么
這里著重感謝 margen 對 Windows 記事本程序做的逆向工作。沒有他的工作,本文不至于這樣精彩。光榮屬于前輩!
保存的過程
根據 [margen 的逆向分析],在打開文件的過程中,記事本程序會調用 fDetermineFileType 來判斷文件的編碼類型。翻譯成 C 語言代碼,大致如下。,Windows 記事本在以 ANSI 保存文件時,沒有任何多余的動作,直接將 buffer 中的內容通過 WriteFile 系統調用寫入到 txt 文件當中。
我們以 010editor打開保存了「聯通」二字文件看看。
(img)
可以看到,在簡體中文 Windows 下,以記事本保存「聯通」兩個字。那么保存得到的 txt 文件內,就僅有 0xC1AACDA8 這些內容。而 0xC1AA 和 0xCDA8 正是「聯通」兩個字的 GBK 編碼。
打開的過程
根據 margen 的逆向分析,在打開文件的過程中,記事本程序會調用 fDetermineFileType 來判斷文件的編碼類型。翻譯成 C 語言代碼,大致如下。
int __stdcall fDetermineFileType(LPVOID lpBuffer,int cb)
{
int iType = 0;
WORD wSign = 0;
if( cb <= 1 ) return 0;
wSign = *(PWORD)lpBuffer;
switch( wSign )
{
case 0xBBEF:
{
if( cb >= 3 && (PBYTE)lpBuffer[3] == 0xBF) iType = 3;
}
break;
case 0xFEFF:
{
iType = 1;
}
break;
case 0xFFFE:
{
iType = 2;
}
break;
default:
{
if( !IsInputTextUnicode( lpBuffer, cb ) )
{
if( IsTextUTF8( lpBuffer, cb ) ) iType = 3;
}
else iType = 1;
}
}
return iType;
}
首先,代碼從文件頭部取出了前 2 個字節,然后走 switch 分支判斷。
若前兩個字節是 0xBBEF,且文件第三個字節是 0xBF,則組成 UTF-8 的 BOM(雖然 UTF-8 不需要)。那么據此判斷文件編碼是 UTF-8。
若前兩個字節是 0xFEFF,那么這是(Big-Endian)大端序 UTF-16 的 BOM。據此判斷文件編碼是(Windows 所謂的)Unicode Big-Endian編碼。
若前兩個字節是 0xFFFE,那么這是小端序的 UTF-16 的 BOM。據此判斷文件編碼是(Windows 所謂的)Unicode Little- Endian編碼。因此字符 "Zero Width No-Break Space" (“零寬無間斷間隔”)又被稱作 BOM。
否則,則需要做更深層次的判斷。注意到,iType 被初始化為 0,代表 ANSI 編碼(簡體中文下是 CP936,相當于是 GBK 編碼)。若已走到了 default 分支,要函數返回 0,當且僅當 IsTextUTF8( lpBuffer, cb ) 為 false 才行。然而,這個函數的寫法是這樣的。
否則,則需要做更深層次的判斷。注意到,iType 被初始化為 0,代表 ANSI 編碼(簡體中文下是 CP936,相當于是 GBK 編碼)。若已走到了 default 分支,要函數返回 0,當且僅當 IsTextUTF8( lpBuffer, cb ) 為 false 才行。然而,這個函數的寫法是這樣的。
BOOL IsTextUTF8( LPSTR lpBuffer, int iBufSize )
{
int iLeftBytes = 0;
BOOL bUtf8 = FALSE;
if( iBufSize <= 0 ) return FALSE;
for( int i=0;i<iBufSize;i++)
{
char c = lpBuffer[i];
if( c < 0 ) bUtf8 = TRUE;
if( iLeftBytes == 0 )
{
if( c >= 0 ) continue;
do
{
c <<= 1;
iLeftBytes++;
} while( c < 0 );
iLeftBytes--;
if( iLeftBytes == 0 ) return FALSE;
}
else
{
c &= 0xC0;
if( c != (char)0x80 ) return FALSE;
else iLeftBytes--;
}
}
if( iLeftBytes ) return FALSE;
return bUtf8;
}
我們重點看 for 循環內部的邏輯。首先,char c = lpBuffer[i]; 從 buffer 中取出一個字節,保存在 signed char 當中。而后判斷 if( c < 0 )。因為 c 是有符號的 char,所以 c < 0 意味著最高位是 1。這就意味著該字符肯定不是 ASCII 字符,可能是一個 UTF-8 字符。因此將 bUtf8 置為 true。
而后,在 if( iLeftBytes == 0 ) 分支中,我們看到 c <<= 1; iLeftBytes++; 的 do-while 循環。這是在判斷 UTF-8 編碼的首字符中,有多少個前綴的 1。根據 UTF-8 的編碼規則,這個數值就是該 UTF-8 字符的編碼長度,記錄在 iLeftBytes 當中。
接下來,根據 iLeftBytes 的大小,逐一檢查后續的字節,是否以 10 開頭。一旦發現有不滿足條件的字節,就能判定當前文檔不是 UTF-8 編碼的。或是(在 for 循環結束之后)發現 iLeftBytes 尚未自減到 0 就已經到了文檔末尾,則也可以判定當前文檔不是 UTF-8 編碼的。
也就是說,這個函數的邏輯,是根據 UTF-8 編碼規則,全文掃描。若發現有一個字符不符合 UTF-8 的編碼規則,則返回 false;否則若全文都符合 UTF-8 的編碼規則,則返回 true。
八、「聯通」都經歷了什么?
回過頭,我們看到,聯通二字以 ANSI(CP936)保存的 txt 文件里只有 0xC1AACDA8 這些內容。因為無有 BOM,所以在 fDetermineFileType 函數中必然走到 default 分支,而后陷入 IsTextUTF8 函數當中。
不巧的是,0xC1AA 和 0xCDA8 都符合 UTF-8 編碼的要求。因此該函數返回 true。于是,Windows 記事本打開這一文件時,認定這是一個無 BOM 的 UTF-8 編碼的文件。于是按照 UTF-8 編碼去解讀 0xC1AACDA8,那么就亂碼了。
九、還有哪些字符
從前文的分析,我們可以得到結論:如果一個以 ANSI(CP936/GBK)保存的文檔,內里包含的所有字符,都不幸滿足了 UTF-8 的編碼規則。那么這個文檔將被 Windows 記事本當做是 UTF-8 編碼的文件打開,就會亂碼。
由于 GBK 是雙字節的編碼格式,只可能滿足 UTF-8 中對 U+0080 至 U+07FF 編碼的格式:110xxxxx, 10xxxxxx。我們可以將這些字符全都掃描輸出出來。以下是完成這一任務的 Python 代碼。
pluses = map(lambda i:"+%s" % (hex(i)[2:].upper()), xrange(16))
headline = "%s%s" % (" " * 7, " ".join(pluses))
print headline
for i in xrange(192, 224):
high = hex(i)[2:].upper()
for j in xrange(4):
low = hex(128 + j * 16)[2:].upper()
chars = map(lambda k:(chr(i) + chr(128 + j * 16 + k)).decode("gbk"), xrange(16))
line = u"0x%s%s %s" % (high, low, " ".join(chars))
print line
得到的結果是:
+0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
0xC080 纮 纴 纻 纼 绖 绤 绬 绹 缊 缐 缞 缷 缹 缻 缼 缽
0xC090 缾 缿 罀 罁 罃 罆 罇 罈 罉 罊 罋 罌 罍 罎 罏 罒
0xC0A0 罓 饋 愧 潰 坤 昆 捆 困 括 擴 廓 闊 垃 拉 喇 蠟
0xC0B0 臘 辣 啦 萊 來 賴 藍 婪 欄 攔 籃 闌 蘭 瀾 讕 攬
0xC180 羳 羴 羵 羶 羷 羺 羻 羾 翀 翂 翃 翄 翆 翇 翈 翉
0xC190 翋 翍 翏 翐 翑 習 翓 翖 翗 翙 翚 翛 翜 翝 翞 翢
0xC1A0 翣 痢 立 粒 瀝 隸 力 璃 哩 倆 聯 蓮 連 鐮 廉 憐
0xC1B0 漣 簾 斂 臉 鏈 戀 煉 練 糧 涼 梁 粱 良 兩 輛 量
0xC280 聙 聛 聜 聝 聞 聟 聠 聡 聢 聣 聤 聥 聦 聧 聨 聫
0xC290 聬 聭 聮 聯 聰 聲 聳 聴 聵 聶 職 聸 聹 聺 聻 聼
0xC2A0 聽 隆 壟 攏 隴 樓 婁 摟 簍 漏 陋 蘆 盧 顱 廬 爐
0xC2B0 擄 鹵 虜 魯 麓 碌 露 路 賂 鹿 潞 祿 錄 陸 戮 驢
0xC380 脌 脕 脗 脙 脛 脜 脝 脟 脠 脡 脢 脣 脤 脥 脦 脧
0xC390 脨 脩 脪 脫 脭 脮 脰 脳 脴 脵 脷 脹 脺 脻 脼 脽
0xC3A0 脿 謾 芒 茫 盲 氓 忙 莽 貓 茅 錨 毛 矛 鉚 卯 茂
0xC3B0 冒 帽 貌 貿 么 玫 枚 梅 酶 霉 煤 沒 眉 媒 鎂 每
0xC480 膧 膩 膫 膬 膭 膮 膯 膰 膱 膲 膴 膵 膶 膷 膸 膹
0xC490 膼 膽 膾 膿 臄 臅 臇 臈 臉 臋 臍 臎 臏 臐 臑 臒
0xC4A0 臓 摹 蘑 模 膜 磨 摩 魔 抹 末 莫 墨 默 沫 漠 寞
0xC4B0 陌 謀 牟 某 拇 牡 畝 姆 母 墓 暮 幕 募 慕 木 目
0xC580 艀 艁 艂 艃 艅 艆 艈 艊 艌 艍 艎 艐 艑 艒 艓 艔
0xC590 艕 艖 艗 艙 艛 艜 艝 艞 艠 艡 艢 艣 艤 艥 艦 艧
0xC5A0 艩 擰 濘 牛 扭 鈕 紐 膿 濃 農 弄 奴 努 怒 女 暖
0xC5B0 虐 瘧 挪 懦 糯 諾 哦 歐 鷗 毆 藕 嘔 偶 漚 啪 趴
0xC680 苺 苼 苽 苾 苿 茀 茊 茋 茍 茐 茒 茓 茖 茘 茙 茝
0xC690 茞 茟 茠 茡 茢 茣 茤 茥 茦 茩 茪 茮 茰 茲 茷 茻
0xC6A0 茽 啤 脾 疲 皮 匹 痞 僻 屁 譬 篇 偏 片 騙 飄 漂
0xC6B0 瓢 票 撇 瞥 拼 頻 貧 品 聘 乒 坪 蘋 萍 平 憑 瓶
0xC780 莯 莵 莻 莾 莿 菂 菃 菄 菆 菈 菉 菋 菍 菎 菐 菑
0xC790 菒 菓 菕 菗 菙 菚 菛 菞 菢 菣 菤 菦 菧 菨 菫 菬
0xC7A0 菭 恰 洽 牽 扦 釬 鉛 千 遷 簽 仟 謙 乾 黔 錢 鉗
0xC7B0 前 潛 遣 淺 譴 塹 嵌 欠 歉 槍 嗆 腔 羌 墻 薔 強
0xC880 葊 葋 葌 葍 葎 葏 葐 葒 葓 葔 葕 葖 葘 葝 葞 葟
0xC890 葠 葢 葤 葥 葦 葧 葨 葪 葮 葯 葰 葲 葴 葷 葹 葻
0xC8A0 葼 取 娶 齲 趣 去 圈 顴 權 醛 泉 全 痊 拳 犬 券
0xC8B0 勸 缺 炔 瘸 卻 鵲 榷 確 雀 裙 群 然 燃 冉 染 瓤
0xC980 蓘 蓙 蓚 蓛 蓜 蓞 蓡 蓢 蓤 蓧 蓨 蓩 蓪 蓫 蓭 蓮
0xC990 蓯 蓱 蓲 蓳 蓴 蓵 蓶 蓷 蓸 蓹 蓺 蓻 蓽 蓾 蔀 蔁
0xC9A0 蔂 傘 散 桑 嗓 喪 搔 騷 掃 嫂 瑟 色 澀 森 僧 莎
0xC9B0 砂 殺 剎 沙 紗 傻 啥 煞 篩 曬 珊 苫 杉 山 刪 煽
0xCA80 蕗 蕘 蕚 蕛 蕜 蕝 蕟 蕠 蕡 蕢 蕣 蕥 蕦 蕧 蕩 蕪
0xCA90 蕫 蕬 蕭 蕮 蕯 蕰 蕱 蕳 蕵 蕶 蕷 蕸 蕼 蕽 蕿 薀
0xCAA0 薁 省 盛 剩 勝 圣 師 失 獅 施 濕 詩 尸 虱 十 石
0xCAB0 拾 時 什 食 蝕 實 識 史 矢 使 屎 駛 始 式 示 士
0xCB80 藔 藖 藗 藘 藙 藚 藛 藝 藞 藟 藠 藡 藢 藣 藥 藦
0xCB90 藧 藨 藪 藫 藬 藭 藮 藯 藰 藱 藲 藳 藴 藵 藶 藷
0xCBA0 藸 恕 刷 耍 摔 衰 甩 帥 栓 拴 霜 雙 爽 誰 水 睡
0xCBB0 稅 吮 瞬 順 舜 說 碩 朔 爍 斯 撕 嘶 思 私 司 絲
0xCC80 虁 虂 虃 虄 虅 虆 虇 虈 虉 虊 虋 虌 虒 虓 處 虖
0xCC90 虗 虘 虙 虛 虜 虝 號 虠 虡 虣 虤 虥 虦 虧 虨 虩
0xCCA0 虪 獺 撻 蹋 踏 胎 苔 抬 臺 泰 酞 太 態 汰 坍 攤
0xCCB0 貪 癱 灘 壇 檀 痰 潭 譚 談 坦 毯 袒 碳 探 嘆 炭
0xCD80 蛝 蛠 蛡 蛢 蛣 蛥 蛦 蛧 蛨 蛪 蛫 蛬 蛯 蛵 蛶 蛷
0xCD90 蛺 蛻 蛼 蛽 蛿 蜁 蜄 蜅 蜆 蜋 蜌 蜎 蜏 蜐 蜑 蜔
0xCDA0 蜖 汀 廷 停 亭 庭 挺 艇 通 桐 酮 瞳 同 銅 彤 童
0xCDB0 桶 捅 筒 統 痛 偷 投 頭 透 凸 禿 突 圖 徒 途 涂
0xCE80 蝷 蝸 蝹 蝺 蝿 螀 螁 螄 螆 螇 螉 螊 螌 螎 螏 螐
0xCE90 螑 螒 螔 螕 螖 螘 螙 螚 螛 螜 螝 螞 螠 螡 螢 螣
0xCEA0 螤 巍 微 危 韋 違 桅 圍 唯 惟 為 濰 維 葦 萎 委
0xCEB0 偉 偽 尾 緯 未 蔚 味 畏 胃 喂 魏 位 渭 謂 尉 慰
0xCF80 蟺 蟻 蟼 蟽 蟿 蠀 蠁 蠂 蠄 蠅 蠆 蠇 蠈 蠉 蠋 蠌
0xCF90 蠍 蠎 蠏 蠐 蠑 蠒 蠔 蠗 蠘 蠙 蠚 蠜 蠝 蠞 蠟 蠠
0xCFA0 蠣 稀 息 希 悉 膝 夕 惜 熄 烯 溪 汐 犀 檄 襲 席
0xCFB0 習 媳 喜 銑 洗 系 隙 戲 細 瞎 蝦 匣 霞 轄 暇 峽
0xD080 衻 衼 袀 袃 袆 袇 袉 袊 袌 袎 袏 袐 袑 袓 袔 袕
0xD090 袗 袘 袙 袚 袛 袝 袞 袟 袠 袡 袣 袥 袦 袧 袨 袩
0xD0A0 袪 小 孝 校 肖 嘯 笑 效 楔 些 歇 蝎 鞋 協 挾 攜
0xD0B0 邪 斜 脅 諧 寫 械 卸 蟹 懈 泄 瀉 謝 屑 薪 芯 鋅
0xD180 褉 褋 褌 褍 褎 褏 褑 褔 褕 褖 褗 褘 褜 褝 褞 褟
0xD190 褠 褢 褣 褤 褦 褧 褨 褩 褬 褭 褮 褯 褱 褲 褳 褵
0xD1A0 褷 選 癬 眩 絢 靴 薛 學 穴 雪 血 勛 熏 循 旬 詢
0xD1B0 尋 馴 巡 殉 汛 訓 訊 遜 迅 壓 押 鴉 鴨 呀 丫 芽
0xD280 襽 襾 覀 覂 覄 覅 覇 覈 覉 覊 見 覌 覍 覎 規 覐
0xD290 覑 覒 覓 覔 覕 視 覗 覘 覙 覚 覛 覜 覝 覞 覟 覠
0xD2A0 覡 搖 堯 遙 窯 謠 姚 咬 舀 藥 要 耀 椰 噎 耶 爺
0xD2B0 野 冶 也 頁 掖 業 葉 曳 腋 夜 液 一 壹 醫 揖 銥
0xD380 觻 觼 觽 觾 觿 訁 訂 訃 訄 訅 訆 計 訉 訊 訋 訌
0xD390 訍 討 訏 訐 訑 訒 訓 訔 訕 訖 託 記 訙 訚 訛 訜
0xD3A0 訝 印 英 櫻 嬰 鷹 應 纓 瑩 螢 營 熒 蠅 迎 贏 盈
0xD3B0 影 穎 硬 映 喲 擁 傭 臃 癰 庸 雍 踴 蛹 詠 泳 涌
0xD480 詟 詠 詡 詢 詣 詤 詥 試 詧 詨 詩 詪 詫 詬 詭 詮
0xD490 詯 詰 話 該 詳 詴 詵 詶 詷 詸 詺 詻 詼 詽 詾 詿
0xD4A0 誀 浴 寓 裕 預 豫 馭 鴛 淵 冤 元 垣 袁 原 援 轅
0xD6A0 譅 幀 癥 鄭 證 芝 枝 支 吱 蜘 知 肢 脂 汁 之 織
0xD6B0 職 直 植 殖 執 值 侄 址 指 止 趾 只 旨 紙 志 摯
0xD780 讇 讈 讉 變 讋 讌 讍 讎 讏 讐 讑 讒 讓 讔 讕 讖
0xD790 讗 讘 讙 讚 讛 讜 讝 讞 讟 讬 讱 讻 诇 诐 诪 谉
0xD7A0 谞 住 注 祝 駐 抓 爪 拽 專 磚 轉 撰 賺 篆 樁 莊
0xD7B0 裝 妝 撞 壯 狀 椎 錐 追 贅 墜 綴 諄 準 捉 拙 卓
0xD880 貈 貋 貍 貎 貏 貐 貑 貒 貓 貕 貖 貗 貙 貚 貛 貜
0xD890 貝 貞 貟 負 財 貢 貣 貤 貥 貦 貧 貨 販 貪 貫 責
0xD8A0 貭 亍 丌 兀 丐 廿 卅 丕 亙 丞 鬲 孬 噩 丨 禺 丿
0xD8B0 匕 乇 夭 爻 卮 氐 囟 胤 馗 毓 睪 鼗 丶 亟 鼐 乜
0xD980 賭 賮 賯 賰 賱 賲 賳 賴 賵 賶 賷 賸 賹 賺 賻 購
0xD990 賽 賾 賿 贀 贁 贂 贃 贄 贅 贆 贇 贈 贉 贊 贋 贌
0xD9A0 贍 佟 佗 伲 伽 佶 佴 侑 侉 侃 侏 佾 佻 儕 佼 儂
0xD9B0 侔 儔 儼 儷 俅 俚 俁 俜 俑 俟 俸 倩 偌 俳 倬 倏
0xDA80 趢 趤 趥 趦 趧 趨 趩 趪 趫 趬 趭 趮 趯 趰 趲 趶
0xDA90 趷 趹 趻 趽 跀 跁 跂 跅 跇 跈 跉 跊 跍 跐 跒 跓
0xDAA0 跔 凇 冖 冢 冥 讠 訐 訌 訕 謳 詎 訥 詁 訶 詆 詔
0xDAB0 詘 詒 誆 誄 詿 詰 詼 詵 詬 詮 諍 諢 詡 誚 誥 誑
0xDB80 踿 蹃 蹅 蹆 蹌 蹍 蹎 蹏 蹐 蹓 蹔 蹕 蹖 蹗 蹘 蹚
0xDB90 蹛 蹜 蹝 蹞 蹟 蹠 蹡 蹢 蹣 蹤 蹥 蹧 蹨 蹪 蹫 蹮
0xDBA0 蹱 邸 邰 郟 郅 邾 鄶 郄 郇 鄆 酈 郢 郜 郗 郛 郫
0xDBB0 郯 郾 鄄 鄢 鄞 鄣 鄱 鄯 鄹 酃 酆 芻 奐 勱 劬 劭
0xDC80 軃 軄 軅 軆 軇 軈 軉 車 軋 軌 軍 軏 軐 軑 軒 軓
0xDC90 軔 軕 軖 軗 軘 軙 軚 軛 軜 軝 軞 軟 軠 軡 転 軣
0xDCA0 軤 堋 堍 埽 埭 堀 堞 堙 塄 堠 塥 塬 墁 墉 墚 墀
0xDCB0 馨 鼙 懿 艸 艽 艿 芏 芊 芨 芄 芎 芑 薌 芙 芫 蕓
0xDD80 輤 輥 輦 輧 輨 輩 輪 輫 輬 輭 輮 輯 輰 輱 輲 輳
0xDD90 輴 輵 輶 輷 輸 輹 輺 輻 輼 輽 輾 輿 轀 轁 轂 轃
0xDDA0 轄 蕁 茛 藎 荬 蓀 葒 荮 莰 荸 蒔 萵 莠 莪 莓 莜
0xDDB0 蒞 荼 薟 莩 荽 蕕 荻 莘 莞 莨 鶯 莼 菁 萁 菥 菘
0xDE80 迉 迊 迋 迌 迍 迏 迒 迖 迗 迚 迠 迡 迣 迧 迬 迯
0xDE90 迱 迲 迴 迵 迶 迺 迻 迼 迾 迿 逇 逈 逌 逎 逓 逕
0xDEA0 逘 蕖 蔻 蓿 蓼 蕙 蕈 蕨 蕤 蕞 蕺 瞢 蕃 蘄 蕻 薤
0xDEB0 薨 薇 薏 蕹 藪 薜 薅 薹 薷 薰 蘚 藁 藜 藿 蘧 蘅
0xDF80 還 邅 邆 邇 邉 邊 邌 邍 邎 邏 邐 邒 邔 邖 邘 邚
0xDF90 邜 邞 邟 邠 邤 邥 邧 邨 邩 邫 邭 邲 邷 邼 邽 邿
0xDFA0 郀 摺 擷 擼 撙 攛 搟 擐 擗 擤 擢 攉 攥 攮 弋 忒
0xDFB0 甙 弒 卟 叱 嘰 叩 叨 叻 吒 吖 吆 呋 嘸 囈 呔 嚦
若一個文檔里只包含這個表格中的漢字(可以再包含 ASCII 字符),在簡體中文 Windows 下在記事本中以 ANSI 編碼保存,則再次打開必然亂碼。特別地,這個表格本身也會亂碼。
據此,你可以構造出各種跟微軟「有仇」的文檔。比如「聯通」,比如「小泉水」。
本文參考地址:
https://liam0205.me/2017/08/27/mojibake-in-Windows-Notepad-due-to-wrong-encoding-detect/
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html