彻底搞懂:字符编码、文本编码、u8、中文乱码、QT乱码问题

本文是作者自己体会和原创,限于水平有限,如有错误,还请赐教。

开篇一个带入问题:

比如如下两个:

char * first ="中国你好";

char * second=u8"中国你好";

这两种写法到底有啥区别?

网友回答:
GCC/Clang 控制字符串编码有两个开关,是 -finput-charset 和 -fexec-charset , 分别控制源代码读入编译器时的源文件的编码,以及编译器生成目标文件时普通字面量的(const) char[] 类型数组里面的编码。

VC 编译器(VS2015及以后),也有对应的两个开关,叫 /source-charset 和 /execution-charset。功能相同。

u8 前缀,功能与 -fexec-charset=utf-8 或 /execution-charset:utf-8 一样,就是用来限定这一个具体的const char[]数组类型的字面量在保存为字节流时,编码为utf-8的。

vc2015在一定程度上可以自动检查文件编码,源文件是GBK或者utf-16编码的,vs可以自动检查出来,不影响按UTF-8编码。

(以上内容摘抄至网上)

那么是不是说,只要在c++11以后,字符串前面加上u8,就再也不会乱码了呢?非也,实际情况因为操作系统的不同,或者版本不同,还有编译器版本的新旧,依旧会出现中文乱码。


以下、私の理解についてお話します。

(1) 前回の記事の -finput-charset は、ソースコードをコンパイラに読み込む際のソースファイルのエンコードを制御するものです。つまり、メモ帳またはエディタでコードを記述した後、保存時に選択されたテキスト エンコーディングになります。一般に、このエンコード選択機能を備えているのはメモ帳やメモ帳などのソフトウェアのみです。このエンコーディングは、現在のテキスト エディターを保存するときに選択されたエンコーディング、またはデフォルトのオペレーティング システムのエンコーディングに関連しています。

たとえば、中国語のオペレーティング システム win10 では、デフォルトのエンコードが変更されていない場合、ローカルのデフォルトのエンコードは GBK になります。コードの書き込み後に保存するときにエンコードが選択されていない場合、ファイルのエンコードは中国の GBK に従ってエンコードされます。プログラマがこのような良識を持っていて、ファイルを保存するときにエンコード (または utf8-bom エンコード) として utf8 を手動で選択しない限り、テキストは utf8 エンコードに従って保存されます。

2) -fexec-charset は、コンパイラがオブジェクト ファイルを生成するときに、共通リテラル (const) char[] 型配列のエンコーディングを制御します。どういう意味ですか?コンパイラはコードをコンパイルした後、その文字列を実行可能ファイルの .text セクションに書き込み (これはコンパイル原則の必修コースで教えられます)、その文字列を読み取ってインターフェイスに表示できるようにすることがわかっています。プログラムの実行後。つまり、ここにもエンコード形式があり、gbkと指定すると、.textセクションに書かれたテキストはgbkエンコードされたテキストとなり、同様に、utf8であれば、.textに書かれたテキストはutf8エンコードされます。

ここまで言うと、u8 は上記 2 つの変数に影響を与えるということですが、上記 2 つの変数の組み合わせや、オペレーティング システム自体のデフォルトのエンコーディングなどによって、人々が混乱するか、そうではないかがわかります。わかりやすく、徹底的にプログラミング時に中国語の使用を避けて文字化けせずに動かすには?

著者は、上記の問題をすべて解決できる簡単なコロケーション方法を提供します。

(1) ソースファイルの文字コード

コードを作成した後は、コード内で中国語を使用するかどうかに関係なく、ファイルを保存するときに BOM を含む utf-8 エンコード形式を使用してファイルを保存する必要があります。この utf8-bom 表示は、私のエンコーディングが utf8 であることを他のテキスト エディターに伝え、私を開くときに utf8 で直接開くことができます。これにより、テキスト エディターがテキスト エンコーディングを動的に識別するプロセスが回避され、識別エラーも防止されます。私の知る限り、gbk と utf8 の間には個別のエンコーディングの重複があります。同じコードが gbk または utf8 として認識される場合があります。たとえば、特殊な単語「unknown」は gbk エンコーディングと utf8 エンコーディングの両方でサポートされています。テキストは utf8-bom エンコード形式で保存されます。vs または gcc がファイルを読み取るときは、utf8 を直接使用してコード ファイルを読み取ります。これにより、エディターの識別とエンコード プロセスが節約されるだけでなく、コード ファイルの問題も回避されます。エンコード識別エラー。そうしないとどのような結果が生じるでしょうか?

結果は次のとおりです。 (1.1) これを行わないと、中国語のオペレーティング システムではデフォルトのエンコーディングが gbk になり、中国語の文字ファイルの保存は gbk に従って保存される可能性があります。中国のシステムでファイルを開く場合も問題ありません。ただし、英語オペレーティング システム (ASCII) やロシア語オペレーティング システム (ロシア語ローカル エンコーディング) など、他のシステム言語を使用するオペレーティング システムに切り替えると、それらはすべて独自のローカル エンコーディングを持ち、gbk ファイルは認識できなくなります。そして直接文字化けしました。utf8-bom 形式で保存すると、現在ではすべてのオペレーティング システムが Unicode を認識でき、utf8 utf16 は Unicode の特定の実装であるため、そのような問題はありません。これで、どのオペレーティング システムでも utf8 でエンコードされたファイルを文字化けせずに開くことができます。(これは少し絶対的なものです。Unicode エンコーディングをサポートするシステムであれば、それを認識できると言うべきです。これで、システムはすべて Unicode エンコーディングをサポートするはずです) (2) コードを記述するときの文字列のバイト

エンコーディング

中国語の文字を含むすべての文字列には、接頭辞として u8 が付きます。たとえば、char* t = u8 "Hello China 123" となります。これは、exe ファイルのバイトコードを生成するときに中国語を utf8 形式にエンコードし、gbk やその他のエンコードを使用しないことをコンパイラーに示して指示します。そうしないとどのような結果が生じますか?

結果は次のとおりです。前提 (1) を確実に満たす場合、ファイルが開かれたときに t のエンコードされた文字列が utf8 でエンコードされ、コンパイラーが exe バイトコードを生成するときに、ローカル エンコーディングに従ってバイトコードが生成される可能性があります。 。具体的には、コンパイラが異なれば処理方法も異なる可能性があり、状況はさらに複雑になります。一部のコンパイラは、ローカル コード (中国語のオペレーティング システムのデフォルトは GBK) に従って実行可能ファイルのバイトコードを生成する場合があり、utf8 の元の中国語コードが gbk コードとして exe のテキスト セグメントに保存され、結果が文字化けします。 . . 一部のコンパイラは、よりスマートで、オペレーティング システムと現在のテキスト エンコーディングをチェックし、utf8 に従ってバイトコードを生成できる場合があります。つまり、結果は不確実であり、間違っている可能性が高いということです。

前提 (1) が保証されていない場合、つまり、ファイルを開いたとき、t のエンコード文字列はまったく utf8 ではなく、ローカル エンコード gbk (中国語のオペレーティング システムの場合は gbk、その他のオペレーティング システムの場合はロシア語のエンコード) です。 (1.1) ですでに述べたように、ロシアなどのオペレーティング システムを使用している場合、エディタでファイルを開くと文字化けしている可能性があります。たとえば、このソース ファイルを英語のオペレーティング システムに入れて開くと、gbk を認識できず、ascii に従って直接認識できないため、開くときに文字化けする可能性があります。たとえば、まだ中国語のシステムで開く場合は、中国語版の win10 の方が優れており、中国語を認識できるので問題ありません。ただし、Linux システムのバージョンによっては中国語が十分にサポートされていないため、開くと依然として文字化けが発生します。実行ファイルのバイトコードを生成する際、文字化けしたコードからローカルコードに保存しても、結果は文字化けしたままになる場合があります。幸いなことに、それらはすべて gbk であり、セーブは文字化けしていません。

根本的な解決策:

ゴーストの問題を回避するためです。すべてのファイルが utf8-bom エンコード形式で保存されるという前提 (1) を確認し、エンコードに中国語が含まれるという条件 (2) を確認する場合は、プレフィックス u8 を追加します。これらの幽霊動物の問題をすべて解決します。コードでプログラムされたファイルを読み取って解析する場合、それらはすべて utf8 形式で解析されます。そうすれば何も失われません。

( 3 ) QT で中国語の文字化けが発生する

QT のローカルエンコーディングはプログラム内で動的に変更できるので注意してください。

QTextCodec  *QTextCodec::codecForLocale() この関数は、現在の QT 実行環境で使用されているローカル エンコーディングを取得できます。当然のことですが、中国のオペレーティング システムであり、ローカル エンコーディングが変更されていない場合、返されるのは GBK です。

また、void QTextCodec::setCodecForLocale( QTextCodec  *c)を呼び出して、QT ランタイム環境でローカル コードをプログラムし、動的に変更します。

多くの QT ユーザーは、QString  QString::fromLocal8Bit を直接呼び出して中国語を無差別に処理することを好みますが、これは毎回機能するとは限りません。この Local は動的に変更できるためです。また長文になりましたが、中国語のオペレーティング システムの場合、このローカルは gbk です。オペレーティング システムの環境を変更せず、中国語を書き込むだけで表示できます。

ただし、ユーザーの動作環境が英語版の場合や、プログラミングで上記の SetCodecForLocale を使用してコードを動的に変更するなど、OS が変更された場合、次の FromLocal8Bit が中国語を処理することになり、文字化けが発生します。

実際、QString  QString::fromLocal8Bit はまったく使用すべきではありません。ローカル エンコーディングに依存しないでください。ローカル エンコーディングはシステムによって異なります。上記の条件 (1) と (2) を確実に満たす場合は、次のインターフェイスを使用するだけです: QString fromUtf8(const char *str, int size = -1)  。もちろん、str 内の中国語は、u8 を使用してプレフィックスを識別するか、ファイル自体内の utf8 形式の文字列を読み取る必要があります。コードでは、utf8 形式に従って文字列のみを解析して処理します。つまり、入力ファイルが utf8 形式であることを確認し、プログラミングも utf8 に従って解析されるようにすれば、すべての複雑な問題が単純化されるか、問題がなくなることさえあります。

( 4 ) QT でファイルを読み込み、ファイル読み込み後にインターフェース上で文字化けが表示される問題を解決しました。

また、同じ問題です。
読み取られたファイルのエンコードが不明であるか、奇妙です。Unity は、テキストエディターで utf8 エンコーディングに切り替えてから読み取ります。または、切り替えずに、gbk を識別するなど、ファイルのエンコーディングを手動で識別しますが、プログラミングではなぜこのようなありがたいことを行うのでしょうか? 国際版の場合、数十ものローカルコードを認識する必要があり、大変です。

元のファイルを手動で utf8 エンコードに切り替えた後、ファイルを読み取るようにプログラミングするときは、utf8 エンコードに従って文字を取得します。つまり、以前の QString fromUtf8(const char *str, int size = -1) を直接使用します。これにより、ソース入力ファイルが utf8 でエンコードされ、プログラミング プロセスが utf8 に従って直接読み取れるように簡素化されます。誰もが簡単で問題なく、幽霊や動物の動的な識別コードの必要性を排除します。ローカルのエンコーディングを動的に識別し、それを照合して識別後のファイルを解析します。

もちろん、当日やむを得ない場合は、ローカル コードの識別も原則に従って識別する必要があります。入力ファイルのエンコードが、プログラミング、読み取り、解析時のエンコードと一致している限り、文字化けは発生する可能性があります。これが唯一のルールです

(4) u8 をサポートできるかどうかはコンパイラのバージョンに依存します。

C++11 より前は、通常、ワイド文字列を指定するために L"" が使用されていましたが、コンパイラはワイド文字列の格納場所を指定する必要はありませんでした。このために、Windows では 2 バイト、つまり UCS-2 (初期) 、UTF-16 が使用されていました。 (最新)。

C++11 では、u8 "utf-8 文字列"、u "utf-16 文字列"、u "utf-32 文字列" が導入されました。また、R" (非エスケープ文字列)" はエスケープせずに直接文字列を書き込むことができ、対応する utf バージョン u8R" (utf-8 非エスケープ文字列)"、uR" (utf-16 非エスケープ文字列)"、 UR「(utf-32文字列)」。

つまり、コンパイラが C++11 をサポートしている限り、サポートできます。現在、ほとんどの主流コンパイラがこれをサポートしています。

結論:コーディングの問題は小さな問題のように見えますが、完全に理解していないと、プログラムの表示が幽霊のように混乱することがよくあります。将来混乱しないように、最初にそれを理解するのが良い方法です。

おすすめ

転載: blog.csdn.net/peterbig/article/details/124728388