web-dev-qa-db-ja.com

文字エンコーディングとは何か、なぜそれを気にする必要があるのか

文字エンコーディングの概念について、私はかなり混乱しています。

Unicode、GBKなどとは何ですか?プログラミング言語はそれらをどのように使用しますか?

それらについて知っていることを気にする必要がありますか?それらに悩む必要のない、より簡単またはより高速なプログラミング方法はありますか?

33
hguser

(私がこれらの用語のいくつかを大まかに/口語的に使用していることに注意してください、それでも重要なポイントに到達する単純な説明です。)

1バイトは、8ビットである256の異なる値のみを持つことができます。

文字セットには256文字を超える文字セットがあるため、一般に、各文字がバイトであると単純に言うことはできません。

したがって、文字セットの各文字をバイトのシーケンスに変換する方法を説明するマッピングが必要です。一部の文字は1バイトにマップされる場合がありますが、他の文字は複数バイトにマップされる必要があります。

それらのマッピングは、文字をバイトのシーケンスにエンコードする方法を示しているため、エンコードです。

Unicodeに関しては、非常に高いレベルで、Unicodeはすべての文字に単一の一意の番号を割り当てる試みです。明らかに256文字を超えるため、その数は1バイトよりも広くする必要があります:) Javaは、すべての文字に16ビット値が割り当てられているバージョンのUnicodeを使用します(これが理由です) Java文字は16ビット幅で、0〜65535の整数値を持っています。)Java文字のバイト表現を取得するとき、 JVMは、使用するエンコーディングを指定します。これにより、文字のバイトシーケンスを選択する方法が認識されます。

36
QuantumMechanic

ASCIIが基本です

元々、1文字は常に1バイトとして格納されていました。 1バイト(8ビット)は、256の可能な値を区別する可能性があります。しかし、実際には最初の7ビットのみが使用されました。したがって、128文字のみが定義されました。このセットはthe ASCII character setとして知られています。

  • 0x00-0x1Fにはステアリングコードが含まれます(CR、LF、STX、ETX、EOT、BELなど)。
  • 0x20-0x40には数字と句読点が含まれています
  • 0x41-0x7Fは主にアルファベット文字を含みます
  • 0x80-0xFF 8番目のビット=未定義。

フランス語、ドイツ語、およびその他の多くの言語では、追加の文字が必要でした。 (例à, é, ç, ô, ...)ASCII文字セットでは利用できませんでした。したがって、8番目のビットを使用して文字を定義しました。これは "拡張ASCII "。

問題は、追加の1ビットでは、世界のすべての言語をカバーするのに十分な容量がないことです。したがって、各リージョンには独自のASCIIバリアントがあります。拡張ASCIIエンコーディングが多数あります(latin-1は非常に人気のあるエンコーディングです)。

よくある質問: "Is ASCII Character set or it is a encoding"ASCIIは文字セットです。ただし、プログラミングではcharsetencodingは同義語として乱暴に使用されます。 ASCII文字とそれ以上(8番目のビットは常に0)):US-ASCIIです。

Unicodeはさらに一歩進んだ

nicode は、エンコーディングではなく文字セットの良い例です。 ASCII標準のように同じ文字を使用しますが、リストを追加文字で拡張し、各文字にu+xxxx形式のコードポイントを提供します。すべての文字を含めるという野心があります全世界で使用されている(および人気のアイコン)。

UTF-8、UTF-16、およびUTF-32は、Unicode文字テーブルを適用するエンコーディングです。ただし、エンコーディング方法はそれぞれ少し異なりますそれら。 UTF-8は、ASCII文字をエンコードするときに1バイトのみを使用し、他のASCIIエンコードと同じ出力を提供します。他の文字については、 2番目のバイトが続くことを示す最初のビット。

[〜#〜] gbk [〜#〜] はエンコーディングであり、UTF-8が複数のバイトを使用するのと同じです。原則はほとんど同じです。最初のバイトはASCII標準に準拠しているため、7ビットのみが使用されます。ただし、UTF-8と同様に、8番目のビットは2番目のバイトの存在を示すために使用できます。は、22,000の中国語文字の1つをエンコードするために使用します。主な違いは、これがUnicode文字セットに準拠していないことです。 。

データのデコード

データをエンコードする場合はエンコードを使用しますが、データをデコードする場合は、使用されたエンコードを確認し、同じエンコードを使用してデコードする必要があります。

残念ながら、エンコーディングは常に宣言または指定されているわけではありません。すべてのファイルに、データが格納されているエンコーディングを示すプレフィックスが含まれていると理想的です。しかし、それでも多くの場合、アプリケーションは使用するエンコーディングを想定または推測する必要があります。 (たとえば、オペレーティングシステムの標準エンコーディングを使用します)。

多くの開発者はエンコーディングが何であるかさえ知らないので、まだこれについての認識の欠如があります。

MIMEタイプ

MIMEタイプはエンコーディングと混同されることがあります。これらは、受信者が到着するデータの種類を識別するための便利な方法です。以下は、MIMEタイプ宣言を使用してHTTPプロトコルがコンテンツタイプを定義する方法の例です。

Content-Type: text/html; charset=utf-8

そして、それは別の大きな混乱の原因です。 MIMEタイプは、メッセージに含まれるデータの種類を記述します(例:text/xmlimage/png、...)。また、場合によっては、データのエンコード方法howも追加で説明します(つまり、charset=utf-8)。 2点の混乱:

  1. すべてのMIMEタイプがエンコーディングを宣言しているわけではありません。場合によっては、それはオプションであるか、完全に無意味なこともあります。
  2. 前に説明したように、UTF-8はエンコーディングであり、文字セットではないため、構文charset=utf-8は意味の混乱を招きます。しかし、前に説明したように、一部の人々は2つの単語を同じ意味で使用しています。

たとえば、text/xmlの場合、エンコーディングを宣言しても意味がありません(そしてcharsetパラメータは単に無視されます)。代わりに、XMLパーサーは通常、ファイルの最初の行を読み取り、<?xml encoding=...タグを探します。そこにある場合は、そのエンコーディングを使用してファイルを再度開きます。

同じ問題が存在します 電子メールを送信するとき 。電子メールには、htmlメッセージまたはプレーンテキストのみを含めることができます。また、その場合、MIMEタイプはコンテンツのタイプを定義するために使用されます。

しかし、要約すると、問題を解決するためにMIMEタイプが常に十分であるとは限りません。

プログラミング言語のデータ型

Java(および他の多くのプログラミング言語))の場合、エンコーディングの危険性に加えて、バイトと整数を文字にキャストするのは複雑です。これは、それらのコンテンツが異なる範囲に格納されているためです。

  • バイトは符号付きバイトとして保存されます(範囲:-128127)。
  • Javaのcharタイプは2つの符号なしバイトに格納されます(範囲:0-65535
  • ストリームは、-1255の範囲の整数を返します。

データにASCII値のみが含まれていることがわかっている場合。適切なスキルを使用すると、データをバイトから文字に解析したり、すぐに文字列にラップしたりできます。

// the -1 indicates that there is no data
int input = stream.read();
if (input == -1) throw new EOFException();

// bytes must be made positive first.
byte myByte = (byte) input;
int unsignedInteger = myByte & 0xFF;
char ascii = (char)(unsignedInteger);

ショートカット

Javaのショートカットは、リーダーとライターを使用し、それらをインスタンス化するときにエンコーディングを指定することです。

// wrap your stream in a reader. 
// specify the encoding
// The reader will decode the data for you
Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);

XMLファイルについて前に説明したように、適切なDOMまたはJAXBマーシャラーはエンコード属性をチェックするため、それはそれほど重要ではありません。

35
bvdb

文字エンコーディングは、自分とは異なる言語を使用する誰かのためにソフトウェアを作成する問題を解決するために使用するものです。

あなたはキャラクターがどのようなもので、どのように並べられているのか分かりません。したがって、この新しい言語の文字列がバイナリでどのように表示されるかはわかりません。率直に言って、気にしません。

あなたが持っているのは、あなたが話す言語から、彼らが話す言語(例えば翻訳者)に文字列を翻訳する方法です。競合することなく、両方の言語をバイナリで表現できるシステムが必要です。エンコーディングはそのシステムです。

これにより、言語がバイナリで表される方法に関係なく機能するソフトウェアを作成できます。

3
Carl

ほとんどのコンピュータープログラムは、自然言語(人間が使用する言語)のテキストを使用して人と通信する必要があります。しかし、コンピューターにはテキストを表現するための基本的な手段がありません。基本的なコンピューター表現は、バイトとワードに編成されたビットのシーケンスであり、ビットのシーケンスを固定幅のbase-2(バイナリ)整数および浮動小数点実数として解釈するためのハードウェアサポートがあります。したがって、コンピュータプログラムには、テキストをビットのシーケンスとして表すためのスキームが必要です。これが基本的に文字エンコーディングです。文字エンコーディングには本質的に明白な、または正しいスキームはありません。そのため、多くの可能な文字エンコーディングが存在します。

ただし、実際の文字エンコーディングにはいくつかの共通の特徴があります。

  1. エンコードされたテキストは、一連の文字(書記素)に分割されます。

  2. 既知の可能な文字のそれぞれにエンコードがあります。テキストのエンコーディングは、テキストの文字のエンコーディングのシーケンスで構成されています。

  3. 可能な各(許可された)文字には、一意の符号なし(負でない)整数が割り当てられます(これはコードポイントと呼ばれることもあります)。したがって、テキストは符号なし整数のシーケンスとしてエンコードされます。異なる文字エンコーディングは、使用できる文字、およびこれらの一意の整数を割り当てる方法が異なります。ほとんどの文字エンコーディングでは、実際に存在している多くの人間の書記体系(スクリプト)で使用されるすべての文字が許可されていません。したがって、文字エンコーディングは、それらが表すことができるテキストがまったく異なります。同じテキストを表すことができる文字エンコーディングでも、コードポイントの割り当てが異なるため、異なる方法で表すことができます。

  4. 文字をエンコードする符号なし整数は、ビットのシーケンスとしてエンコードされます。文字エンコーディングは、このエンコーディングに使用するビット数が異なります。これらのビットがバイトにグループ化されると(一般的なエンコードの場合のように)、文字エンコードのエンディアンが異なる場合があります。文字エンコードは、固定幅(エンコードされた文字ごとに同じビット数)であるか、可変幅(一部の文字でより多くのビットを使用)であるかによって異なります。

したがって、コンピュータプログラムがテキストを表すためのバイトシーケンスを受信した場合、コンピュータプログラムmustがそのテキストに使用されている文字エンコーディングを知っている(それが何らかの操作を行う場合)テキスト(不透明な値と見なして変更せずに転送する以外)。唯一の可能性は、テキストに、使用されているエンコーディングまたはを示す追加データが添付されていることです。プログラムは、テキストに特定のエンコーディングが必要であることを前提としています。

同様に、コンピュータープログラムがテキストを別のプログラムまたはディスプレイデバイスに送信(出力)する必要がある場合、使用する文字エンコードまたはを宛先に通知する必要があります。プログラムは、宛先が予期するエンコードを使用する必要があります。

実際には、文字エンコードに関するほとんどすべての問題は、宛先が1つの文字エンコードを使用して送信されるテキストを予期し、実際にテキストが別の文字エンコードで送信される場合に発生します。これは通常、コンピュータープログラマーがmany可能な文字エンコーディングが存在すること、およびプログラムがエンコードされたテキストを不透明な値ですが、入力では外部表現から変換し、出力では外部表現に変換する必要があります。

0
Raedwald