1. 程式人生 > >令人抓狂的編碼問題

令人抓狂的編碼問題

一直以來,編碼問題都是比較令人糾結的,我自己也是,迷惑了好一段時間。

首先看一下ANSI編碼和ASCII 編碼,用google搜到這篇文章,挺好的。http://www.differencebetween.net/technology/web-applications/difference-between-ansi-and-ascii/

ASCII: American Standard Code for Information Interchange

ANSI: American National Standard Institute

基本的區別就是:

Summary:

ANSI has more characters than ASCII
ASCII uses 7 bits while ANSI uses 8
ASCII characters are fixed to the code points while ANSI code points may represent different characters
ASCII is more straightforward to use than ANSI
ASCII works with Unicode while ANSI compatibility is very limited

這裡,我主要再介紹一下ansi,unicode和utf8

首先看一下ANSI

ANSI編碼

首先在C++程式碼裡面敲入一行程式碼,很簡單看下圖,執行一下,會發現字串ansi裡面的記憶體是0xb3, 0xcc, 0xd0, 0xf2, 0xd4, 0xb1.開啟記事本,寫入“程式設計師”3個字,然後save,用ultraedit看一下十六進位制編碼,如下圖。

跟VS裡面看到的一模一樣。我們在看一下C++的原始檔。

看16進位制的原始檔,可以發現原始檔裡面的“程式設計師”3個字也是ANSI編碼。好像VS對於C++原始檔預設的就是ANSI編碼,我在VS2013裡面看到有個功能可以自動檢測UTF-8編碼啥的。但是沒有仔細研究過。

OK, 現在我們知道,在notepad裡面,打入一些字元,然後save,那麼預設的就是ANSI編碼。在VS裡面如果輸入一些常量字串,假如是純英文的話,那應該也是ANSI編碼,如果你的常量字串裡面有中文或者韓文等其他字元的話,就視情況而定了,像vs2013可能會把你的原始檔轉換成UTF8格式,但我知道早期的VS是不會轉的還是用ANSI.所以如果你在IDE,比如VS, Eclipse,甚至XCODE等裡面輸入常量字串的話,需要小心。通常如果只是英文的話,一般是沒有問題的,但是如果有中文的話,要留個心眼,看你的IDE是怎麼編碼的。不然恐怕就會出現亂碼的情況。當然如果真的有中文等字元的話,也不建議使用ANSI編碼,儘可能使用UNICODE吧。

UNICODE

unicode其實有好幾種,比如unicode16,unicode32啥的。通常我們在寫程式的時候,說起unicode或者寬字元,一般指的就是unicode16.也就是2個位元組(wchar_t)來表示一個字元。一個英文字母a使用2個位元組的寬位元組wchar_t來表示,一箇中文也是用一個wchar_t來表示。

notepad的saveas裡面有個功能,可以把當前檔案儲存成unicode。

同樣開啟notepad輸入“程式設計師”3個字,然後點選save as,在編碼那裡選擇unicode。如圖

儲存完之後,用ultraedit開啟,前面兩個位元組FFFE,這個其實是notepad的一個標記,不用管它,看後面的6個位元組。“程式設計師”總共是3箇中文字元,那麼用unicode就是6個位元組,也就是0B7A8F5E5854.

OK, 現在C++程式裡面敲入一行程式碼,如下圖.從下面的圖片裡面可以看到unicode字串的記憶體是0x7a0b, 0x5e8f, 0x5458.跟上面ultraedit裡面比較。好像每兩個位元組都反過來了,這是何故?

其實這裡有個很好玩的事情。我們直接看unicode裡面的指向的記憶體吧。

unicode指向的是地址0x0026fb90,看記憶體,記憶體裡面的資料是0b, 7a, 8f, 5e, 58, 54。跟上面ultraedit裡面顯示的是一致的。那麼說明unicode裡面在記憶體存放的位元組流跟ultraedit裡面展示的是一模一樣的。那為什麼用wchar_t表示的時候就反過來了呢?其實我覺得這應該是windows上面的機制,用wchar_t表示的時候就是反過來的(不知道linux上是不是也是這樣?),就好象是int在記憶體裡面存放也是逆序的。

順便再來看一下C#吧,寫幾行簡單程式碼,直接看下圖:

首先我們可以看到sizeof(char)在C#裡面是2.其實在C#裡面並沒有wchar_t這種東西。只有一個char,而它就是2個位元組。這是因為C#裡面用的都是unicode。C#的string裡面存放的就是unicode格式。好像Java也是這樣。每一個char和上面的C++的wchar_t的值一模一樣。

ANSI VS Unicode

那麼我們到底應該使用ANSI還是Unicode呢?我建議使用Unicode,特殊是在寫windows程式的時候,因為windows的API都支援ANSI和Unicode兩種,也就是我們常說的多位元組和寬位元組。比如CreateFileA()支援ANSI編碼, CreateFileW()支援Unicode編碼。如果使用Ansi的話,萬一你的字串裡面含有中文,就會比較麻煩一些,比如有些時候為了換行,很難計算,以為ANSI裡面英文佔一個自己,中文佔2個位元組。如果把一箇中文給劈開了,那就顯示亂碼了。如果使用Unicode就很方便了,因為中文,英文都是佔2個位元組。當然如果你的程式確定只支援英文,那用ANSI也行,畢竟用Unicode的話,會多佔記憶體。假如一個英文字串有100個字元,用ANSI就佔用100位元組,用UNICODE就是200位元組。Windows的大多數API都支援ANSI和UNICODE兩種,我個人比較喜歡用UNICODE版本,畢竟現在的記憶體動不動都4g,8g的,多耗些記憶體也不是什麼大問題。

utf8

最後再介紹一種非常常用的編碼utf8. 什麼是utf-8, 看定義, UTF-8 stands for Unicode Transformation Format-8. It is an octet (8-bit) lossless encoding of Unicode characters

至於utf8的具體細節和好處,網上一搜一大堆。基本上現在的網頁用的都是utf-8編碼,資料庫裡面用的很多也是utf-8,網路傳輸也是很多使用utf8。反正我覺得utf8的使用率是非常高的。比如我們想把一個字串存入本地檔案的時候也可以使用utf8編碼,當然也使用ANSI或者UNICODE. 這裡就簡單介紹一下C++和Java裡面的utf8使用吧。在C++裡面,現在可以使用C++11了,簡單的一個例子,把一個unicode字串轉換成utf8,再把utf8轉換成unicode

#ifndef UNICODE
#define UNICODE
#endif

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <locale>
#include <codecvt>
#include <fstream>

#include <string>

using namespace std;

// convert UTF-8 string to wstring
std::wstring utf8_to_wstring (const std::string& str)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.from_bytes(str);
}

// convert wstring to UTF-8 string
std::string wstring_to_utf8 (const std::wstring& str)
{
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.to_bytes(str);
}

int main()
{
    // UTF-8 narrow multibyte encoding
    std::string ansi = "程式設計師";
             
    std::wstring unicode(L"程式設計師");
    const wchar_t* p = unicode.c_str();
    
    std::string utf8 = wstring_to_utf8(unicode);
   
    std::wstring unicode2 = utf8_to_wstring(utf8);
}
執行一下,可以看到utf8的位元組流,然後再把utf8位元組流轉換成UNICODE得到unicode2,unicode2顯示的也是“程式設計師”。

如果用C#就更簡單了。我們可以看到utf8編碼的位元組流跟C++的一模一樣。

最後看一下c#原始檔的編碼,我這裡的c#原始檔編碼用的是UNICODE, 看圖:(好像如果有中文的話,VS會轉換成utf8)

儘量不要在原始碼檔案裡面hardcode需要顯示在UI上的字串

比如類似的程式碼:

string title = "hellow world";

SetWindowText(title);

這個真的不是好習慣。如果你的程式要支援其他語言的話,你就不得不修改原始檔而且重新編譯了。而且萬一需要支援中文的話,那麼就得在字串常量裡面寫中文,可是有些時候又不知道原始檔是用什麼格式來編碼的。比如原始檔是用utf8編碼的話,檔案就來的,SetWindowText()是不支援utf8編碼顯示的,我們不得不先把utf8編碼轉換成ANSI或者UNICODE,再呼叫windows API。還有其他問題,比如你用VS UNICODE編碼來寫程式的,而另外一個人用Xcode來寫程式,那麼你的中文在他的Xcode裡面肯定顯示亂碼。總之很麻煩。我覺得我們的字串常量應該儘可能放在資原始檔裡面,比如C++的resource檔案,C#的資原始檔。android程式也是有資原始檔。這樣比較好,如果要改字串的話,改資原始檔就可以了。不需要跟原始碼。當然如果是一些log之類的字串,寫在原始碼檔案裡面倒也問題不大,因為這些log通常都是英文,而且沒有localization的問題。

其他編碼

除了ANIS, UNICODE, UTF8之後還有很多其他的編碼,但是我覺得這三種是最常用的。而且一旦掌握了這三種以後,再看其他的編碼應該也是很容易了。



相關推薦

令人編碼問題

一直以來,編碼問題都是比較令人糾結的,我自己也是,迷惑了好一段時間。 首先看一下ANSI編碼和ASCII 編碼,用google搜到這篇文章,挺好的。http://www.differencebetween.net/technology/web-applications/di

關閉令人的ESlint 語法檢測配置方法《《《 非人類的方法

剛剛開始的小夥伴是不是空格報錯少一行報錯各種錯?是不是覺得快被限制的失去了自由的思緒了?受折磨後找到了不錯的文章來取消eslint語法檢測限制,作為學習筆記摘自segmentfault其實我並不反對這些語法檢測,但是像許多反個人意願的那就真的不得不吐槽了,比如vue-cli腳

關於令人的 E/HAL: load: id=gralloc != hmi->id=gralloc

我在網上搜索了挺多資料的,很多都是重複在說許可權問題,然而我報這種錯誤的大部分程式都恰好不是因為許可權問題,而是一些特別細節的問題...... 按照我的經驗,我的建議是: 找控制元件程式碼的錯誤! 報錯原因:一般是由於取不到控制元件物件、控制元件的點選事件執行的時候得到

一道令人的零一背包變式 -- UVA 12563 Jin Ge Jin Qu hao

bre std 一定的 isp 鏈接 struct ostream 如果 動態規劃 題目鏈接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_

我要了。。又回到了幾天不能A一道題的時候

sdn 做了 csdn ati .net xheditor dsm gif 微笑 poj1556我不做了。你做做把...我已經要game over了 我要抓狂了。。又回到了幾天不能A一道題的時候

記一次的亂碼經歷

win7 idt 參數 崩潰 tex 讀取 消失 以及 發生 常年Eclipse的守舊派久聞IDEA大名,終於在dalao的安利下入了IDEA的坑((才不是因為可以用翻譯插件 入坑一段時間,因為在編碼方面了解的還算比較多,平時基本沒遇到過亂碼問題,並且在第一次使用ID

還在選什麼涼蓆?有品味的朋友都開始用牛皮涼蓆了!

竹蓆、藤席伴隨我們很多年。在炎炎夏季,竹蓆藤席幫我們趕走悶熱和燥熱,讓我們的夢更沉靜和香甜。竹蓆藤席成為尋常老百姓家的夏日必備。到了夏季就要買一床,拿回家用開水燙,然後再放到太陽下晒,避免長蟎蟲,身體過敏,然後再檢查一下毛刺,因為毛刺可能劃傷大腿和手臂被,雖然傷口不大,還是比較疼。所以雖然麻

我也曾經因安裝庫而,直到我遇到了Anaconda

幾乎所有的 Python 學習者都遇到過“安裝”方面的問題。這些安裝問題包括 Python 自身環境的安裝、第三方模組的安裝、不同版本的切換,以及不同平臺、版本間的相容問題等。當你因為這些問題而卡殼,一行程式碼沒寫就已瘋,相信我,你不是一個人……包括我自己,也是這麼被坑過來的。 我自己

兩件小事讓我 之一:Mac OSX上沒有可用的雙拼

1995年我就看上了蘋果電腦,但是沒有錢,也沒必要買,當時的蘋果電腦還很難用,高層應用和PC有很大的差異,但是現在的Mac OSX已經很好用了,很多平時在PC上賴以生存的工具都有了Mac版。簡單舉兩個例子,凡是跟Apache/Eclipse/Mozilla/Codehaus有

Oh! 讓人的git!

Git很難:因為搞砸了很容易,但是找到如何修復錯誤的方法缺很難。Git官方的文件,存在“先有雞還是先有蛋”的問題——除非你知道解決問題的方法的特定名字,否則很難查詢到解決方案並順利的解決自己的問題。 所以,下面是我自己曾經遇到的一些十分糟糕的場景,並且我最終解決了這些問題,下面就用最通俗的話介紹一下。

讓人的許可權問題

在ubuntu下遇到一個怪事。 用vi編定一個文字檔案,下面總示提示[RO],即只有只讀許可權。 這個文字檔案的當前使用者和組都是我自己,我甚至chmod 777 成功後,那個文字檔案還是隻讀。抓狂 後面發現用vi開啟這個檔案時,下面的命令列的那一欄提示 [ILLEGA

週末imac機重灌win7,裝得我

自用mac機以前裝的是win7 32位的系統,一直受記憶體限制,越來越慢,週末決定裝個64位的系統,朋友建議在虛擬機器上裝win7,想想這樣估計會影響速度,就還是採用了mac,win7雙系統。 第一個坑:用bootcamp引導安裝時,在“配置檔案”那卡住了,試了好幾次,都過

曾讓我哭笑不得的C語言

1.關於+=以及-= 這是兩個運算子,但你否有過這種經歷: int temp; char i for(i=0;i<MAX;i++) { ... temp=+2; //這裡本意是每次迴圈,temp都自增2,但是卻將'+='寫成了'=+',按照這種寫法,每次迴圈都為temp賦值正數2,與本意相

混亂到讓人近乎的程式碼

給一家工廠寫軟體,是基於一個他們正在使用的軟體新增一些功能。程式碼及其混亂,既無註釋也無文件,甚至連基本的程式碼格式都沒有。修改起來及其困難,效率特別低,很多變數名稱不得不去猜測程式碼什麼意思。 暑假在一家硬體公司實習做DSP開發,讓我詫異的是就連專案經理的程式碼也是及其混亂

word中讓人的自動編號設定方法備忘

在word 2007中使用自動編號,一級編號是1. 2. 3.,二級編號是1.1, 1.2, 1.3,在2.之後本來應該是2.1,但總是自動編成1.1。這個問題記得我畢設的時候就遇到過了,今天又遇到一次,把解決方案放在這裡備忘。 首先,善用樣式管理器,就是點更改樣式右下角那個

啊啊啊啊啊啊啊啊啊啊啊xcode 讓人啊!!!!

之前在桌面新建了一個test專案,裡面用xib拉的介面按鈕(10個按鈕,以及相應的按鍵行為),後來整個專案刪掉了。 重建了一個名字一樣的test專案,用程式碼新建了一個按鈕,然而一run,模擬器中彈出了舊的介面!!!!!!!!!!!!!!!!!!!!! 尼瑪啊啊啊啊啊啊

!!對浮點數使用 abs() 函式求絕對值的代價!!

因程式需要,需求出浮點數的絕對值~ 第一個想到的函式就是 abs(),不料無論怎麼求,abs出來的結果都是0!! 是的,就是0!! 真是他媽的太奇怪了,我檢查了一遍又一遍,程式碼的寫法沒有發現任何的問題, 可以求出來的結果他媽的就是0!!! 白白浪費了哥1個半小時以上,不瀉

textarea文字總是居中問題解決辦法 讓人

每次文字從資料庫讀到textarea後文字都不居左。在排出樣式,轉義字元等問題後,baidu,google了一會始終沒找到答案。後來發現原來問題出在HTML上     <textarea>   內容內容   </textarea>     上面這句看似

Spring Data JPA 全域性DAO的擴充套件(第一次用JPA時總是提示 另人的錯誤: No property find for type class )

前幾天看了springside4的mini-web程式碼發現確實有不少新的東東,咱這次單說說Spring Data JPA吧。  引用springside4的 wiki關於對Spring Data JPA的簡介  Spring Data JPA在JPA上又

ERP為何總是讓企業?

 ERP自上世紀未正式進入中國大陸以來,一直被中國企業作為企業管理工具的熱寵,然而它的匯入並未給企業管理帶來多少實質性的改變,甚至給不少企業在管理上造成很多不便,更有甚者增加了不少管理成本。特別是在中小型民營企業更是如此。     這難道是ERP不行嗎?不是,因為它有成功的