0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

關(guān)于C++編碼的轉(zhuǎn)換

工程師 ? 來(lái)源:CSDN ? 作者:FlushHip ? 2020-10-16 11:57 ? 次閱讀

【CPP開(kāi)發(fā)者導(dǎo)讀】:在處理東方語(yǔ)言(中日韓)時(shí),經(jīng)常會(huì)遇到各種編碼問(wèn)題,而且被這類問(wèn)題搞的暈頭轉(zhuǎn)向。到網(wǎng)上查資料,看的也是一頭霧水,最后往往是誤打誤撞的把問(wèn)題解決了,自己仍然稀里糊涂。

這篇文章介紹了如何在最常見(jiàn)的編碼方式(Unicode, UTF-8, ANSI)之間進(jìn)行轉(zhuǎn)換,結(jié)合代碼實(shí)例,清晰明了,方便讀者理解,例子也可以直接拿來(lái)使用。本文推薦給經(jīng)常對(duì)文字字符串進(jìn)行處理的程序員閱讀,使其掌握字符轉(zhuǎn)換的一些基本方法。

以下是正文

C++的項(xiàng)目,字符編碼是一個(gè)大坑,不同平臺(tái)之間的編碼往往不一樣,如果不同編碼格式用一套字符讀取格式讀取就會(huì)出現(xiàn)亂碼。因此,一般都是轉(zhuǎn)化成UTF-8這種平臺(tái)通用,且支持性很好的編碼格式。

Unicode、UTF-8的概念不做過(guò)多解釋,這里說(shuō)一下ANSI,我第一次看到這個(gè)名詞,我看成了ASCII。被Mentor狠批一頓。

ANSI是一種字符代碼,為使計(jì)算機(jī)支持更多語(yǔ)言,通常使用 0x00 ~ 0x7F范圍的1 個(gè)字節(jié)來(lái)表示 1 個(gè)英文字符。超出此范圍使用0x80~0xFFFF來(lái)編碼,即擴(kuò)展的ASCII編碼。

不同的國(guó)家和地區(qū)制定了不同標(biāo)準(zhǔn),由此產(chǎn)生了 GB2312、GBK、GB18030、Big5、Shift_JIS 等各自的編碼標(biāo)準(zhǔn)。這些使用多個(gè)字節(jié)來(lái)代表一個(gè)字符的各種漢字延伸編碼方式,稱為 ANSI 編碼。在簡(jiǎn)體中文Windows操作系統(tǒng),ANSI 編碼代表 GBK 編碼;在繁體中文Windows操作系統(tǒng),ANSI編碼代表Big5;在日文Windows操作系統(tǒng),ANSI 編碼代表 Shift_JIS 編碼。

以上內(nèi)容摘自百度百科,可以看出,ANSI和ASCII還是有關(guān)系的。ANSI也叫本地碼。

我們要做到能在Unicode、UTF-8、ANSI這三種編碼格式中自由轉(zhuǎn)換。如下圖所示:

在C++中,要怎么做呢?當(dāng)然是用標(biāo)準(zhǔn)庫(kù)的東西啦,C++11對(duì)國(guó)際化標(biāo)準(zhǔn)做得還是可以的,提供了這些接口,正如圖中虛線所示,標(biāo)準(zhǔn)庫(kù)沒(méi)有提供UTF-8到ANSI的互相轉(zhuǎn)化接口,但是我們可以自己封轉(zhuǎn)接口,借用這條路(UTF-8 《=》 Unicode 《=》 ANSI)來(lái)實(shí)現(xiàn)。

因此,接下來(lái)就聊聊UTF8 《=》 Unicode和Unicode 《=》 ANSI。

UTF8 《=》 Unicode

先看代碼:

std::string UnicodeToUTF8(const std::wstring & wstr){ std::string ret; try { std::wstring_convert《 std::codecvt_utf8《wchar_t》 》 wcv; ret = wcv.to_bytes(wstr); } catch (const std::exception & e) { std::cerr 《《 e.what() 《《 std::endl; } return ret;}std::wstring UTF8ToUnicode(const std::string & str){ std::wstring ret; try { std::wstring_convert《 std::codecvt_utf8《wchar_t》 》 wcv; ret = wcv.from_bytes(str); } catch (const std::exception & e) { std::cerr 《《 e.what() 《《 std::endl; } return ret;}

UTF-8是多字節(jié)字符串(multibyte string),而Unicode是寬字符字符串(wchar_t string)。

而C++11提供了wstring_convert這個(gè)類,這個(gè)類可以在wchar_t string和multibyte string之間來(lái)回轉(zhuǎn)換;

而codecvt_utf8可以提供UTF-8的編碼規(guī)則。這個(gè)類在#include 《codecvt》中。有了wstring_convert提供寬字符字符串到多字節(jié)字符串的轉(zhuǎn)化,而這個(gè)轉(zhuǎn)換規(guī)則由codecvt_uft8提供。這樣子就可以實(shí)現(xiàn)UTF8和Unicode的互相轉(zhuǎn)換。

從UTF8到Unicode調(diào)用成員函數(shù)wstring_convert::from_bytes;

從Unicode到UTF8調(diào)用成員函數(shù)wstring_convert::to_bytes;

Unicode 《=》 ANSI

std::string UnicodeToANSI(const std::wstring & wstr){ std::string ret; std::mbstate_t state = {}; const wchar_t *src = wstr.data(); size_t len = std::wcsrtombs(nullptr, &src, 0, &state); if (static_cast《size_t》(-1) != len) { std::unique_ptr《 char [] 》 buff(new char[len + 1]); len = std::wcsrtombs(buff.get(), &src, len, &state); if (static_cast《size_t》(-1) != len) { ret.assign(buff.get(), len); } } return ret;}std::wstring ANSIToUnicode(const std::string & str){ std::wstring ret; std::mbstate_t state = {}; const char *src = str.data(); size_t len = std::mbsrtowcs(nullptr, &src, 0, &state); if (static_cast《size_t》(-1) != len) { std::unique_ptr《 wchar_t [] 》 buff(new wchar_t[len + 1]); len = std::mbsrtowcs(buff.get(), &src, len, &state); if (static_cast《size_t》(-1) != len) { ret.assign(buff.get(), len); } } return ret;}

標(biāo)準(zhǔn)庫(kù)提供了wcsrtombs和mbsrtowcs這兩個(gè)函數(shù),當(dāng)然C的標(biāo)準(zhǔn)庫(kù)也提供了這兩個(gè)函數(shù)。

講下wcsrtombs,這個(gè)函數(shù)把寬字符串轉(zhuǎn)成多字節(jié)字符串。編碼規(guī)則受地域的LC_CTYPE影響。因此這個(gè)函數(shù)可以用于本地碼的轉(zhuǎn)化(和本地的編碼息息相關(guān))。

因此,有關(guān)于本地碼的使用,在代碼中要加上下列語(yǔ)句:

setlocale(LC_CTYPE, “”);

目的是讓本地碼生效,這條代碼的作用就是讓C++語(yǔ)言的Locale(地域)和本地的地域相同。在Linux下可以運(yùn)行l(wèi)ocale命令看看:

可以看到,LC_CTYPE = en_US.UTF-8,這表示英文,英國(guó),UTF-8編碼,也就是說(shuō)本地碼就是這個(gè)。

當(dāng)然,你也可以在setlocale中指定一些編碼規(guī)則,把wcsrtombs用于別的編碼轉(zhuǎn)化,但是,這里不推薦,因?yàn)閟etlocale是全局的,設(shè)置了這個(gè)就會(huì)影響其他地方的編碼。

wcsrtombs的四個(gè)參數(shù)分別代表什么意思呢?

std::size_t wcsrtombs( char* dst, const wchar_t** src, std::size_t len, std::mbstate_t* ps );

dst,轉(zhuǎn)化后的結(jié)果存入dst指向的內(nèi)存;

src,待轉(zhuǎn)化的字符串的指針的指針;

len,dst指向內(nèi)存的可用字節(jié)數(shù);

ps,轉(zhuǎn)換的狀態(tài),一般默認(rèn)初始化就好了;

return type,轉(zhuǎn)化后結(jié)果的長(zhǎng)度,不包含\0。

注意:如果dst == nullptr,這個(gè)時(shí)候wcstombs的返回值表示會(huì)有這么多字節(jié)的結(jié)果產(chǎn)生,因此,我們可以拿到這個(gè)返回值去新建一個(gè)數(shù)組來(lái)存儲(chǔ)new char[len + 1]。所以,一般調(diào)用兩次wcstombs。

mbsrtowcs同理。

UTF-8 《=》 ANSI

以Unicode為中介裝換便是。

std::string UTF8ToANSI(const std::string & str){ return UnicodeToANSI(UTF8ToUnicode(str));}std::string ANSIToUTF8(const std::string & str){ return UnicodeToUTF8(ANSIToUnicode(str));}

總結(jié)

C++11的標(biāo)準(zhǔn)庫(kù)還是挺強(qiáng)大的,雖然這么強(qiáng)大,但是很多特性還不了解,因此還是要多擴(kuò)寬自己的視野,不然有好東西都不知道用,那就棒槌了。

對(duì)了,在Linux下加上setlocale(LC_CTYPE, “”)后程序在命令行中可以正常顯示,不加有可能不正常顯示,原因是setlocale(LC_CTYPE, “”)也影響了cout,全局的嘛;而在CodeBlocks下不能正常顯示,不知道為什么,但是調(diào)試的過(guò)程中,觀察到了正常的結(jié)果;Visual Studio中沒(méi)有做實(shí)驗(yàn),不過(guò)應(yīng)該沒(méi)問(wèn)題。

作者:FlushHip

來(lái)源:CSDN

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 編程
    +關(guān)注

    關(guān)注

    88

    文章

    3565

    瀏覽量

    93536
  • 編碼
    +關(guān)注

    關(guān)注

    6

    文章

    932

    瀏覽量

    54731
  • C++
    C++
    +關(guān)注

    關(guān)注

    21

    文章

    2102

    瀏覽量

    73453
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C語(yǔ)言和C++中結(jié)構(gòu)體的區(qū)別

    同樣是結(jié)構(gòu)體,看看在C語(yǔ)言和C++中有什么區(qū)別?
    的頭像 發(fā)表于 10-30 15:11 ?104次閱讀

    C7000優(yōu)化C/C++編譯器

    電子發(fā)燒友網(wǎng)站提供《C7000優(yōu)化C/C++編譯器.pdf》資料免費(fèi)下載
    發(fā)表于 10-30 09:45 ?0次下載
    <b class='flag-5'>C</b>7000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器

    C++語(yǔ)言基礎(chǔ)知識(shí)

    電子發(fā)燒友網(wǎng)站提供《C++語(yǔ)言基礎(chǔ)知識(shí).pdf》資料免費(fèi)下載
    發(fā)表于 07-19 10:58 ?6次下載

    C++中實(shí)現(xiàn)類似instanceof的方法

    C++有多態(tài)與繼承,但是很多人開(kāi)始學(xué)習(xí)C++,有時(shí)候會(huì)面臨一個(gè)常見(jiàn)問(wèn)題,就是如何向下轉(zhuǎn)型,特別是不知道具體類型的時(shí)候,這個(gè)時(shí)候就希望C++ 可以向Java或者Python中有instanceof這個(gè)
    的頭像 發(fā)表于 07-18 10:16 ?504次閱讀
    <b class='flag-5'>C++</b>中實(shí)現(xiàn)類似instanceof的方法

    鴻蒙OS開(kāi)發(fā)實(shí)例:【Native C++

    使用DevEco Studio創(chuàng)建一個(gè)Native C++應(yīng)用。應(yīng)用采用Native C++模板,實(shí)現(xiàn)使用NAPI調(diào)用C標(biāo)準(zhǔn)庫(kù)的功能。使用C標(biāo)準(zhǔn)庫(kù)hypot接口計(jì)算兩個(gè)給定數(shù)平方和的平
    的頭像 發(fā)表于 04-14 11:43 ?2449次閱讀
    鴻蒙OS開(kāi)發(fā)實(shí)例:【Native <b class='flag-5'>C++</b>】

    使用 MISRA C++:2023? 避免基于范圍的 for 循環(huán)中的錯(cuò)誤

    在前兩篇博客中,我們?向您介紹了新的 MISRA C++ 標(biāo)準(zhǔn)?和?C++ 的歷史?。在這篇博客中,我們將仔細(xì)研究以 C++ 中?for?循環(huán)為中心的特定規(guī)則。
    的頭像 發(fā)表于 03-28 13:53 ?709次閱讀
    使用 MISRA <b class='flag-5'>C++</b>:2023? 避免基于范圍的 for 循環(huán)中的錯(cuò)誤

    c語(yǔ)言,c++,java,python區(qū)別

    C語(yǔ)言、C++、Java和Python是四種常見(jiàn)的編程語(yǔ)言,各有優(yōu)點(diǎn)和特點(diǎn)。 C語(yǔ)言: C語(yǔ)言是一種面向過(guò)程的編程語(yǔ)言。它具有底層的特性,能夠?qū)τ?jì)算機(jī)硬件進(jìn)行直接操作。
    的頭像 發(fā)表于 02-05 14:11 ?2126次閱讀

    C++簡(jiǎn)史:C++是如何開(kāi)始的

    MISRA C++:2023,MISRA? C++ 標(biāo)準(zhǔn)的下一個(gè)版本,來(lái)了!為了幫助您做好準(zhǔn)備,我們介紹了 Perforce 首席技術(shù)支持工程師 Frank van den Beuken 博士撰寫(xiě)
    的頭像 發(fā)表于 01-11 09:00 ?514次閱讀
    <b class='flag-5'>C++</b>簡(jiǎn)史:<b class='flag-5'>C++</b>是如何開(kāi)始的

    基于C/C++面向?qū)ο蟮姆绞椒庋bsocket通信類流程簡(jiǎn)析

    在掌握了基于 TCP 的套接字通信流程之后,為了方便使用,提高編碼效率,可以對(duì)通信操作進(jìn)行封裝,本著有淺入深的原則,先基于 C 語(yǔ)言進(jìn)行面向過(guò)程的函數(shù)封裝,然后再基于 C++ 進(jìn)行面向?qū)ο蟮念惙庋b。
    的頭像 發(fā)表于 12-26 10:00 ?1680次閱讀

    基于C/C++面向?qū)ο蟮姆绞椒庋bsocket通信類

    在掌握了基于 TCP 的套接字通信流程之后,為了方便使用,提高編碼效率,可以對(duì)通信操作進(jìn)行封裝,本著有淺入深的原則,先基于 C 語(yǔ)言進(jìn)行面向過(guò)程的函數(shù)封裝,然后再基于 C++ 進(jìn)行面向?qū)ο蟮念惙庋b。
    的頭像 發(fā)表于 12-26 09:57 ?1265次閱讀

    C語(yǔ)言和C++中那些不同的地方

    C語(yǔ)言雖說(shuō)經(jīng)常和C++在一起被大家提起,但可千萬(wàn)不要以為它們是一個(gè)東西?,F(xiàn)在我們常用的C語(yǔ)言是C89標(biāo)準(zhǔn),C++
    的頭像 發(fā)表于 12-07 14:29 ?889次閱讀
    <b class='flag-5'>C</b>語(yǔ)言和<b class='flag-5'>C++</b>中那些不同的地方

    開(kāi)箱即用!教你如何正確使用華為云CodeArts IDE for C/C++!

    C/C++編碼體驗(yàn)、方便的訪問(wèn)華為云資源、簡(jiǎn)單的引用華為云服務(wù)于一身,實(shí)現(xiàn)C/C++開(kāi)發(fā)者在個(gè)人研發(fā)作業(yè)體驗(yàn)和效率上的巨大提升。 為了幫助
    的頭像 發(fā)表于 11-29 17:40 ?742次閱讀
    開(kāi)箱即用!教你如何正確使用華為云CodeArts IDE for <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>!

    如何選擇創(chuàng)建c語(yǔ)言和c++

    選擇創(chuàng)建 C 語(yǔ)言和 C++ 都需要綜合考慮多個(gè)因素。在決定使用哪種語(yǔ)言之前,我們需要對(duì)這兩種語(yǔ)言的特點(diǎn)、優(yōu)缺點(diǎn)、適用場(chǎng)景、學(xué)習(xí)成本等進(jìn)行全面的了解和對(duì)比。下面是關(guān)于選擇創(chuàng)建 C 語(yǔ)言
    的頭像 發(fā)表于 11-27 15:58 ?558次閱讀

    c++怎么開(kāi)始編程

    C++是一種高級(jí)的、通用的編程語(yǔ)言,用于開(kāi)發(fā)各種類型的應(yīng)用程序。它是從C語(yǔ)言演變而來(lái),也是一種靜態(tài)類型語(yǔ)言,可以在不同的平臺(tái)上進(jìn)行開(kāi)發(fā)。C++具有高度的靈活性和性能,并且廣泛應(yīng)用于游戲開(kāi)發(fā)、桌面
    的頭像 發(fā)表于 11-27 15:56 ?876次閱讀

    c++多行注釋快捷鍵

    C++中,多行注釋(也稱為塊注釋)是一種用于注釋大段代碼或多個(gè)語(yǔ)句的方法。當(dāng)你希望暫時(shí)禁用一些代碼或者解釋特定部分代碼的作用時(shí),多行注釋是非常有用的。 在C++中,多行注釋以 /* 開(kāi)始,以
    的頭像 發(fā)表于 11-22 10:24 ?7937次閱讀