Unicodeの文字エンコードの原則と実践

目次

1.文字セットエンコーディングの開発

1.1、文字セットと文字エンコードの違いと関係

1.2、文字セットエンコーディングの開発

 1.3。まとめ

2つの文字セット関連コマンド

2.1、BOMとは

 2.2。文字セット関連のコマンド

 第三に、文字セット変換のプログラミング実装

3.1、Windowsのvs2015でiconvをコンパイルしてインストールします

3.2、VS2015でコンパイルおよび変換


1.文字セットエンコーディングの開発

1.1、文字セットと文字エンコードの違いと関係

  • 文字セット:複数の文字のコレクション。たとえば、GB2312は、中国の国家標準簡体字中国語文字セットです。GB2312には、簡体字中国語文字(6763)と一般記号、シリアル番号、数字、ラテン文字、日本語かな、ギリシャ文字、ロシア文字、中国語の音声記号、および中国語の音声記号が含まれています。文字。7445グラフィック文字。
  • 文字エンコード:文字セット内の文字を指定されたセット内のオブジェクト(ビットパターン、自然数シーケンス、電気パルスなど)にエンコード(マッピング)して、テキストをコンピューターに保存し、通信を介して送信できるようにします。通信網。

文字セットと文字エンコードの関係:文字セットは、書記体系の文字と記号のコレクションであり、文字エンコードは、文字を特定のバイトまたはバイトシーケンスにマップするルールです。

通常、特定の文字セットは特定のエンコード方式を採用します(つまり、文字セットは文字エンコードに対応します(たとえば、ASCII、IOS-8859-1、GB2312、GBK、どちらも文字セットと対応する文字エンコードを表します)。 )、しかし、Unicodeはそうではなく、最新のモデルを使用しています))

1.2、文字セットエンコーディングの開発

(1)シングルバイト

ASCII(情報交換のためのアメリカ標準コード)、128文字、7ビットバイナリで表現(00000000-01111111は0x00-0x7F); EASCII(拡張ASCII)、256文字、8ビットバイナリで表現(00000000-11111111は0x00) -0xFF)。コンピュータがヨーロッパに到着すると、国際標準化機構はASCIIに基づいて拡張し、ISO-8859標準を形成しました。これは、EASCIIに類似し、ASCIIと互換性がありますが、上位128のコードポイントが異なります。ただし、ヨーロッパの言語環境は複雑であるため、各地域の言語、ISO-8859-1、ISO-8859-2、ISO-8859-3、...、ISO-に応じて多くの下位標準が作成されています。 8859-16。

(2)2バイト

コンピューターがアジアに到着したとき、256のコードポイントでは不十分でした。そのため、2次元テーブルを拡張し続け、1バイトを2バイト、16ビットの2進数、65536コードポイントに変更します。中国本土のGB2312、香港と台湾のBIG5、日本のShift JISなど、さまざまな国や地域で多くのコードが登場しています。

2バイトエンコーディングは可変長である可能性があるため、65536コードポイントが理想的な状況であることに注意してください。つまり、同じエンコーディングの一部の文字はシングルバイト表現であり、一部の文字はダブルバイト表現です。これの利点は、一方ではASCIIと互換性があり、他方では、いくつかのコードポイントを失うという犠牲を払って、ストレージ容量を節約できることです。

GBK(中国語内部コード仕様)はGB2312の拡張です(gbkエンコーディングを使用して、従来の文字と簡体字を同時に表すことができます)。これらがすべてダブルバイトエンコーディングであるのは当然です。コードポイントは同じです。拡張機能はまったくありませんが、実際には予約済みスペースが機能しています。たとえば、次の図はGBKのエンコードスペースを示しています。GBK/ 1とGBK / 2はGB2312の領域、GBK / 3、GBK / 4、GBK / 5はGBKの領域、赤はユーザー定義の領域です。白は、コーディング損失の領域が長くなっていることが原因である可能性があります。GBKのフルネームは「漢字内部コード拡張仕様」であり、国際規格ISO / IEC10646-1および国内規格GB13000-1のすべての漢字、日本語、および韓国語の漢字をサポートします。

GBK文字セットのすべての漢字と全幅記号は2バイトを占有し、文字と半幅記号は1バイトを占有します。特別なエンコーディング方法はありません。GBKエンコーディングを呼び出すために使用されます。漢字が多い中国で一般的に使用されます。

インターネットが世界を席巻したとき、地理的な制限は破られました。異なる国や地域のコンピューターがデータを交換すると、文字化けの問題が発生します。つまり、同じバイナリデータのセットに対して、異なるエンコーディングが異なる文字を解析します。

UNICODE文字セットは国際標準の文字セットであり、言語間およびプラットフォーム間のテキスト情報変換の要件を満たすために、世界中のさまざまな言語で各文字に一意のコードを定義します。複数のエンコード方法、つまりUTF-8、UTF-16、およびUTF-32エンコードがあります。

例:「漢字」に対応するUNICODE番号は0x6c49と0x5b57であり、コード化されたプログラムデータは次のとおりです。

UTF8エンコーディング:E6B189 E5AD97

UTF16BEエンコーディング:6C49 5B57

UTF32BEエンコーディング:0006C490 0005B57

(3)マルチバイト

Unicode文字セットで使用できるエンコーディングは3つあります。

  • UFT-8:1〜6バイトを使用して格納する可変長コーディングスキーム。
  • UFT-32:固定長コーディング方式は、文字番号のサイズに関係なく、常に4バイトをストレージに使用します。
  • UTF-16:UTF-8とUTF-32の間で、2バイトまたは4バイトを使用して格納し、長さは固定と可変の両方です。

UTFはUnicodeTransformation Formatの略語で、「Unicode Transformation Format」を意味します。次の数字は、少なくとも文字を格納するために使用されるビット数を示しています。

GB18030文字セットは、1バイト、2バイト、および4バイトの3つの方法を使用して文字をエンコードします。GBKおよびGB2312文字セットと互換性があります。

(4)UTF-8

UTF-8:コードポイント値の有効ビット数に応じて、1〜4バイトのコードポイントをエンコードするように定義された可変長文字エンコードです。

注:UTF-8はエンコード仕様ではなく、エンコード方法です。

Unicodeエンコーディング(16進数) 

UTF-8バイトストリーム(バイナリ)

000000-00007F

0xxxxxxx

000080-0007FF

110xxxxx 10xxxxxx

000800-00FFFF

1110xxxx 10xxxxxx 10xxxxxx

01 0000-10 FFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

たとえば、漢字の厳密なUnicodeコードは4E25でバイナリに変換されます(01001110 00100101、合計15ビット)。上記の表によると、UTF-8文字のエンコードは3バイトを占めるため、最初の3ビットは1、4番目のビット(n + 1ビット)は0、次の2バイトの各バイトの最初の2ビットは10、つまり1110 xxxx 10 xxxxxx10xxxxxxです。入力すると、1110 0100 10 111000 10 100101になり、合計24ビットが3バイトを占めます。

000800-00FFFF(4E25)

0100 111000 100101

1110 0100 10 111000 10 100101  - > E4B8A5

(5)UFT-16

UFT-16はかなり奇妙で、2バイトまたは4バイトを使用して格納します。

Unicode番号が0からFFFFの範囲の文字の場合、UTF-16はストレージに2バイトを使用し、エンコード変換なしでUnicode番号を直接格納します。これはUTF-32と非常によく似ています。

Unicode番号が10000〜10FFFFの範囲の文字の場合、UTF-16はストレージに4バイトを使用します。具体的には、UTF-16は文字番号のすべてのビットを2つの部分に分割し、上位ビットは2バイトのストレージ間の値を使用します。 D800〜DBFFの間では、下位ビット(残りのビット)はDC00〜DFFFの間の2バイト値で格納されます。

Unicode番号の範囲(16進数)

 

特定のUnicode番号(2進数)

UTF-16エンコーディング

エンコード後のバイト数

0000 0000〜0000 FFFF

xxxxxxxx xxxxxxxx

xxxxxxxx xxxxxxxx

2

0001 0000 --- 0010 FFFF

yyyy yyyy yyxx xxxx xxxx

110110yy yyyyyyyy 110111xx xxxxxxxx

4

UTF-16BE、その接尾辞はBEです。これはビッグエンディアンを意味し、ビッグエンディアンを意味します。ビッグエンディアンとは、上位バイトを下位アドレスに配置することを意味します。UTF-16LE、その接尾辞はLEです。これはリトルエンディアンを意味し、リトルエンディアンを意味します。リトルエンディアンとは、上位バイトを上位アドレスに配置することを意味します。UTF-16、サフィックスは指定されていません。つまり、ビッグエンディアンであるかどうかは不明であるため、最初の2バイトは、バイト配列がビッグエンディアンであるかリトルエンディアンであるかを示します。つまり、FE FFはビッグエンディアンを意味し、FFFEはリトルエンディアンを意味します。

(6)UTF-32

UTF-32は固定長エンコーディングであり、常に4バイトを占有します。これは、すべてのUnicode文字を保持するのに十分であるため、エンコーディング変換なしでUnicode番号を直接格納するのに十分です。スペースが無駄になり、効率が向上します。

 1.3。まとめ

プログラムは、ファイルを開くときに、それがUTF-8であるかUTF-16であるかをどのように識別しますか?サインを作成するサインがあるかどうかに関係なく、ファイルの最初の数バイトがサインです。

  • EF BBBFはUTF-8を意味します
  • FEFFはUTF-16BEを意味します
  • FFFEはUTF-16LEを意味します
  • 00 00 FEFFはUTF32-BEを意味します
  • FF FE 0000はUTF32-LEを意味します

UTF-8のみがASCIIと互換性があり、UTF-32とUTF-16はシングルバイトエンコーディングを持たないため、ASCIIと互換性がありません。

完全なUnicode文字セットとさまざまなエンコード方法を表示します:https//unicode-table.com/cn/

UnicodeおよびUTFエンコーディング変換:https//www.qqxiuzi.cn/bianma/Unicode-UTF.php

2つの文字セット関連コマンド

2.1、BOMとは

BOM(バイトオーダーマーク)バイトオーダー(バイトオーダーの識別)は、実際には、ビッグエンディアン(BE)またはリトルエンディアン(LE)を使用することです。

ファイル内のUTFのストレージ。UTF形式では、ファイルに常に固定ファイルヘッダーがあります。

UTFエンコーディング

バイト順マーク

UTF-8

EF BB BF

UTF-16LE

FF FE

UTF-16BE

FE FF

UTF-32LE

FF FE 00 00

UTF-32BE

00 00 FE FF 

 UTF-8にはデフォルトでBOMがありません。UTF-8には1バイトがあります。この場合、両端に引数はありません。他の2バイト、3バイト、4バイトの場合は、例として3バイトを取り上げます。エンディアンを把握する必要がある場合、それは不可能ではありません。たとえば、リトルエンディアンは「小-中-大」です。ビッグエンディアン。法律は「大中小」です。しかし、実際には、UTF-8はビッグエンディアンである1つのエンディアンメソッドのみを使用します。

 2.2。文字セット関連のコマンド

ファイルのエンコーディングを確認するにはどうすればよいですか?

例:

file -i chatset.cpp

エンコード方法を変換する方法は?

iconvコマンドは、ファイルのエンコーディングを変換するために使用されます。たとえば、UTF8エンコーディングをGB18030エンコーディングに、またはその逆に変換できます。Linuxでのiconv開発ライブラリには、iconv_open、iconv_close、iconvなどのC関数が含まれており、C / C ++プログラムで文字コードを簡単に変換するために使用できます。

语法:iconv -f encoding [-t encoding] [inputfile] .. ..

オプション:

-fエンコーディング:エンコーディングエンコーディングから文字の変換を開始します。

-t encoding:文字をエンコーディングに変換します。

-l:コード化された文字の既知のセットを一覧表示します

-o file:出力ファイルを指定します

-c:出力された不正な文字を無視します

-s:警告メッセージを抑制しますが、エラーメッセージは抑制しません

--verbose:進行状況情報を表示します

-fおよび-tで指定できる有効な文字は、-lオプションのコマンドにリストされています。

(1)iconvでサポートされているフォーマット

形式の一部を次に示します:UTF-8、UTF-16、UTF-16BE、UTF-16LE、UTF-32、UTF-32BE、UTF-32LE、UTF8、UTF16、UTF16BE、UTF16LE、UTF32、UTF32BE、UTF32LE GB2312 GBK ISO- 8859-1

(2)iconvでサポートされているさまざまな形式を変換します

iconv -f UTF-8  -t UTF-8 utf8.txt -o UTF-8.txt 
iconv -f UTF-8  -t UTF8  utf8.txt -o UTF8.txt

iconv -f UTF-8  -t UTF-16   	UTF-8.txt -o UTF-16.txt
iconv -f UTF-8  -t UTF-16BE 	UTF-8.txt -o UTF-16BE.txt
iconv -f UTF-8  -t UTF-16LE 	UTF-8.txt -o UTF-16LE.txt

iconv -f UTF-8  -t UTF16   	UTF-8.txt -o UTF16.txt
iconv -f UTF-8  -t UTF16BE 	UTF-8.txt -o UTF16BE.txt
iconv -f UTF-8  -t UTF16LE 	UTF-8.txt -o UTF16LE.txt

iconv -f UTF-8  -t UTF-32   UTF-8.txt -o UTF-32.txt
iconv -f UTF-8  -t UTF-32BE UTF-8.txt -o UTF-32BE.txt
iconv -f UTF-8  -t UTF-32LE UTF-8.txt -o UTF-32LE.txt

iconv -f UTF-8  -t GB2312   UTF-8.txt -o GB2312.txt
iconv -f UTF-8  -t GBK 		UTF-8.txt -o GBK.txt
iconv -f UTF-8  -t ISO-8859-1 UTF-8.txt -o ISO-8859-1.txt

 第三に、文字セット変換のプログラミング実装

インターネット時代の到来とともに、インターネットを介したテキスト通信は徐々に増加してきました。外国のWebサイトを閲覧する場合、現時点では文字エンコードの変換が特に重要になります。これは問題を引き起こします。つまり、多くの文字が特定のエンコード方法に含まれていません。この混乱を解決するために、Unicodeエンコーディング方式が確立されました。Unicodeは、これらのエンコーディングのすべての文字セットを含むスーパーエンコーディングであるため、XMLなどの一部の新しいテキスト形式のデフォルトのエンコーディングはUnicodeです。

しかし、多くの古いコンピューターは、依然としてローカルの繁体字エンコード方式を使用しています。また、メールプログラムやブラウザなどの一部のプログラムは、これらの異なるユーザーコードを切り替えることができる必要があります。他のいくつかのプログラムには、国際化の処理をスムーズにサポートするためにUnicodeのサポートが組み込まれていますが、Unicodeと他の従来のエンコーディングの間で変換する必要があります。GNUのlibiconvは、これら2つのアプリケーション用に設計されたエンコーディング変換ライブラリです。

3.1、Windowsのvs2015でiconvをコンパイルしてインストールします

ここでは、私がコンパイルしたlibiconvライブラリ、特定のリンクを直接使用できます。

リンク:https  ://pan.baidu.com/s/1FAqkN9ggxSpLlRhvPtMIig抽出コード:6jpt

参照リンク:Windowsでiconvをコンパイルする

3.2、vs2015でコンパイルおよび変換

  • 変換ハンドルを取得する

関数数:iconv_t iconv_open(const char * tocode、const char * fromcode);

それらの中で:tocode:ターゲットエンコーディングメソッド; fromcode:ソースエンコーディングメソッド

さらに、TRANSLIT:変換できない文字を検索し、それらを類似の文字に置き換える、 IGNORE  :変換できない文字をスキップするなどの宛先コードを設定することもできます具体的には、char * encTo = "UNICODE // TRANSLIT"、UNICODEはエンコード方式、TRANSLITエンコード設定は次のように設定できます。

范例:iconv_t cd = iconv_open( "UTF-8"、 "UTF-16");

  • 変換を行う

関数数:size_t iconv(iconv_t cd、const char * * inbuf、size_t * inbytesleft、char * * outbuf、size_t * outbytesleft);

その中で:

cd:iconv_open()によって生成されたハンドル

inbuf:変換される文字列

inbytesleft:変換せずに保存される文字数

outbuf:変換された文字列を保存します

outbytesleft:変換後のtempoutbufの残りのスペースを保存します

戻り値:-1を返し、例外を示します。エラーコード:E2BIG:Outbufに十分なスペースがありません。EILSEQ:無効なマルチバイトシーケンスが検出されました。EINVAL:不完全なマルチバイトシーケンスが検出されました。

范例:size_t ret = iconv(cd、&srcstart、&srclen、&tempoutbuf、&outlen);

  • ハンドルを閉じる

関数数:int iconv_close(iconv_t cd);

例:iconv_close(cd);

これは説明するための基本的な例です。具体的なコードは次のとおりです。

#include<iostream>
#include<string>
#include<iconv.h>

using namespace std;

int main(){
	/* 目的编码, TRANSLIT:遇到无法转换的字符就找相近字符替换
	*          IGNORE  :遇到无法转换字符跳过*/
	//char *encTo = "UNICODE//TRANSLIT";
	// char *encTo = "UNICODE//IGNORE";
	char *encTo = "UTF-16";
	/* 源编码 */
	char *encFrom = "UTF-8";

	/* 获得转换句柄
	*@param encTo 目标编码方式
	*@param encFrom 源编码方式
	*
	* */
	iconv_t cd = iconv_open(encTo, encFrom);
	if (cd == (iconv_t)-1)
	{
		perror("iconv_open");
	}

	/* 需要转换的字符串 */
	const char inbuf[1024]="学习unicode编码";
	size_t srclen=strlen(inbuf);
	cout<<"srclen= "<<srclen<<endl;

	/* 存放转换后的字符串 */
	size_t outlen = 1024;
	char outbuf[1024];
	size_t utf16_len = outlen;
	memset(outbuf, 0, outlen);

	/* 由于iconv()函数会修改指针,所以要保存源指针 */
	const char *srcstart = inbuf;
	char *tempoutbuf = outbuf;

	printf("utf8:\n");
	for (int i = 0; i < strlen(inbuf); i++)
	{
		printf("%02x ", inbuf[i]);
	}
	printf("\n");

	/* 进行转换
	*@param cd iconv_open()产生的句柄
	*@param srcstart 需要转换的字符串
	*@param srclen 存放还有多少字符没有转换
	*@param tempoutbuf 存放转换后的字符串
	*@param outlen 存放转换后,tempoutbuf剩余的空间
	*
	* */
	outlen = 20;
	printf("1 srcstart=%p, tempoutbuf=%p, srclen=%ld, outlen=%ld\n",
		srcstart, tempoutbuf, srclen, outlen);
	size_t ret = iconv(cd, &srcstart, &srclen, &tempoutbuf, &outlen);
	printf("2 srcstart=%p, tempoutbuf=%p, srclen=%ld, outlen=%ld\n",
		srcstart, tempoutbuf, srclen, outlen);

	if (ret == -1)
	{
		perror("iconv");
	}
	utf16_len = utf16_len - outlen;
	printf("inbuf=%s, srclen=%d, outbuf=%s, outlen=%d,  ret = %d\n",
		inbuf, srclen, outbuf, utf16_len, ret);

	printf("utf16:\n");
	for (int i = 0; i < utf16_len; i++)
	{
		printf("%02x ", outbuf[i]);
	}
	printf("\n");
	/* 关闭句柄 */
	iconv_close(cd);

	return 0;
}

最終結果は次のとおりです。

参照リンク:

開発ドキュメント:http//www.gnu.org/software/libiconv/documentation/libiconv-1.13/

 

おすすめ

転載: blog.csdn.net/wxplol/article/details/104921569