2015-08-12Go言語の文字列、バイト、ルーンと文字(翻訳)sellGoGoブログ記事https://blog.golang.org/stringsの翻訳です。ライセンスの下、Google社によりホストされています。翻訳の誤りなどあればご指摘お待ちしております。GoブログGo言語の文字列、バイト、ルーンと文字はじめに以前のブログの記事は、その実装のメカニズムを説明するためにいくつかの例を使用して、Go言語のスライスがどのように機能するかを説明しました。その背景を踏まえ、この記事は、Go言語の文字列について説明します。文字列はブログの記事としてあまりにも単純なトピックに見えるかもしれませんが、それらを使いこなすことはそれらがどのように動作するかだけでなく、バイト、文字、及びルーンの違い、UnicodeとUTF-8との違い、文字列と文字列リテラルの違い、および他のより一層の微妙な違いについて、理解しておく必要があります。このトピックにアプローチする一つの方法は、よく寄せられる質問への答えとしてそれを考えることです、「どのようなときにGo言語文字列に位置nのインデックスをつけられますか、なぜn番目の文字を取得できないのですか?」これから見ていくように、この質問は、現代の世界でテキストがどのように機能するかについての多くの詳細に私たちを導きます。これらの問題の優れた紹介は、Go言語とは無関係に、ジョエル·スポルスキーの有名なブログの記事、絶対最低限すべてのソフトウェア開発者は絶対、積極的にUnicodeと文字集合について知っておかなければならない(言い訳なし!)にあります。彼が提起した点の多くは、ここに繰り返されます。文字列とは?それでは、いくつかの基本から始めましょう。Go言語では、文字列は実質的に読み取り専用のバイトのスライスです。バイトのスライスとは何か、それがどのように動作するかについて、良く分からなければ、以前のブログ記事を読んでください、ここでは知っていることを仮定します。前置きとして、文字列が任意のバイト列を保持できることを述べることが重要です。Unicodeテキスト、UTF-8テキスト、または任意の他の所定のフォーマットを保持する必要はありません。文字列の内容に関する限り、それはバイトのスライスとまったく同じです。表記を使用した文字列リテラル(詳細はすぐに述べます)があります。(もちろん、バイトの範囲は16進数で00からFFに含まれます。"\xbd\xb2\x3d\xbc\x20\xe2\x8c\x98"文字列の出力サンプル文字列のバイトの一部は有効なASCIIではなく、有効なUTF-8でもないため、文字列を直接出力すると醜い結果になります。以下の単純なprint文を実行すると、fmt.Println(sample)以下の乱れた結果を得ます(正確な外観は環境によって異なります)。⌘その文字列が実際に何を保持しているかを調べるために、それを分割して部分を調べる必要があります。これを行うには、いくつかの方法があります。sample[i])}前置きで暗示したように、文字列のインデックスは、文字ではなく個々のバイトにアクセスします。このトピックの詳細については後で述べます。今のところ、単にバイトに固執しましょう。個々のバイトが文字列を定義した16進エスケープと一致していることに注目してください。(16進数)形式の動詞を使用することです。それは単に文字列の連続バイトを、16進数としてバイトごとに2文字ダンプします。間にスペースを入ます。(quoted、引用符で囲まれた)動詞は、出力が明確になるように、文字列内のすべての印字不可能なバイトシーケンスをエスケープします。sample)このテクニックは、文字列の大部分がテキストとしてわかるが、一部治すべき特殊文字がある場合には便利です。Interest」を示す記号を見ることができます。エンコードされています。動詞に「プラス」フラグを使用することができます。このフラグは、UTF-8を解釈する間、印字不可能な列だけでなく非ASCIIバイトについても、エスケープして出力します。結果、適切な形式のUTF-8文字列内の非ASCIIデータを表すUnicode値がさらされます。\u2318"これらの出力テクニックは、文字列内容のデバッグにも有効ですし、以下の説明に便利になります。これらのすべての方法は、文字列とまったく同じように、バイトスライスについても作用することを指摘することも有用です。ここに、ブラウザで正しく実行(および編集)することが可能なプログラムとして、リストされた完全なプリントオプションのセットを提示します。sample)}[演習:文字列の代わりにバイトのスライスを使用するように上記の例を変更してください。ヒント:スライスを作成するために変換を使用します]。書式を使用してください。出力は何を教えてくれますか?]UTF-8と文字列リテラル見てきたように、文字列のインデクシングでは、文字ではなく、バイトが得られます。文字列は単なるバイトの束です。これは、文字列内に文字の値を格納するとき、バイト1つずつの表現を格納することを意味します。それでは、それがどのように起こるかを確認するために、よりコントロールされた例を見てみましょう。ここに単純なプログラムがあります、これは単一文字の文字列定数を3つの異なる方法でプリントします、まずプレーンな文字列として、次にASCIIのみのクォートされた文字列として、最後に個々のバイトを16進数で。混乱を避けるために、バッククォートで囲まれた「生の文字列」を作成します、そのため単にリテラルテキストのみを含めることができます。(通常の文字列は、二重引用符で囲まれ、上記に示したようにエスケープシーケンスを含めることができます。表現され、このバイト列は16進数の2318のUTF-8エンコーディングであることを再認識させます。明らかであるか微妙であるかは、あなたのUTF-8の習熟度次第ですが、文字列のUTF-8表現が作られる方法について説明する価値はあります。純然たる事実は以下の通りです:それはソースコードが書かれたときに作られた。Go言語のソースコードはUTF-8のテキストであると定義されます。他の表現は許可されていません。それは以下を意味します、ソースコード中で、テキスト`⌘`を書くとき、プログラムを作成するために使用されるテキストエディタは、ソーステキストに記号⌘のUTF-8エンコーディングを配置します。16進数のバイトをプリントアウトするとき、まさにエディタがファイルに配置したデータをダンプしています。要するに、Go言語のソースコードはUTF-8であるため、文字列リテラルのソースコードはUTF-8のテキストです。文字列リテラルが、生の文字列が含むことのできない、エスケープシーケンスを含まない場合、構築された文字列は引用符の間のソーステキストそのものを保持します。このように定義と構築により、生の文字列は常にその内容の有効なUTF-8表現を含みます。同様に、前の節のようなUTF-8のブレーキングエスケープを含まない限り、通常の文字列リテラルもまた常に有効なUTF-8を含みます。一部の人々は、Go言語の文字列は常にUTF-8であると思いますが、そうではありません:文字列リテラルのみがUTF-8です。前の節で示したように、文字列値は、任意のバイトを含むことができます。この一つとして示したように、文字列リテラルは、バイトレベルのエスケープを持っていない限り、常にUTF-8テキストを含みます。要約すると、文字列は任意のバイトを含めることができますが、文字列リテラルから構築される場合、それらのバイトは(ほとんど常に)UTF-8です。コードポイント、文字、ルーンこれまで、「バイト」と「文字」という言葉の用法について、非常に慎重にしてきました。文字列はバイトを保持するためであり、「文字」の考え方を定義することは少々難しいためでもあります。Unicode標準は、単一の値で表される項目を参照するために用語「コードポイント」を使用しています。コードポイントU+2318は、16進数値2318で、記号⌘を表します。(そのコードポイントに関する多くの詳細については、Unicodeのページを参照してください。)もっと平凡な例を選ぶと、UnicodeコードポイントU+0061はラテン文字'A'の小文字'a'です。重いアクセント文字'A'の小文字'à'についてはどうでしょう?それは文字であり、また、コードポイント(U+00E0)ですが、それは他の表現を持っています。「組み合わせ」アクセントコードポイント、U+0300を使用することができ、àと同じ文字を作成するには、小文字a、U+0061に接続します。一般的に、一つの文字は、複数の異なるコードポイントの列、したがって異なるUTF-8バイト列により、表現される場合があります。コンピューティングの文字の概念が曖昧なので、または少なくとも紛らわしいので、注意して使用します。物事が信頼できるようにするには、そこに指定された文字は常に同じコードポイントで表されることを保証する正規化技術ですが、その対象は、現在のトピックから離れます。後のブログの記事で、Go言語ライブラリの正規化対処方法を説明します。「コードポイント」は長くてちょっと発音しにくいため、Go言語はこの概念のためにより短い用語を導入します、ルーンです。この用語は、ライブラリとソースコードに表示され、一つの興味深い点を加えて、「コードポイント」と全く同じことを意味します。定義します、整数値がコードポイントを表すことをプログラムが明確にすることができるように。文字定数とみなされるものは、Go言語ではルーン定数と呼ばれます。要約すると、ここでの要点は次のとおりです。Go言語のソースコードは、常にUTF-8です。文字列は任意のバイトを保持します。文字列リテラルは、バイトレベルのエスケープが無ければ、常に有効なUTF-8シーケンスを保持しています。これらの配列は、ルーンと呼ばれるUnicodeコードポイント列を表します。文字列内の文字が正規化されていることはGo言語では保証されません。ループを使用する場合です。ループで何が起こるか見てきました。ループは、対照的に、各反復で一つのUTF-8でエンコードされたルーンをデコードします。ループのたびに、ループのインデックスは、バイト単位で測った現在のルーンの開始位置で、コードポイントはその値です。}出力は、各コードポイントがどのように複数のバイトを占有するかを示します。6[演習:文字列に無効なUTF-8バイトのシーケンスを入れてください。(どうやって?)ループの繰り返しで何が起きますか?]ライブラリGo言語の標準ライブラリは、UTF-8のテキストを解釈するための強力なサポートを提供します。ループがあなたの目的に十分でないとしても、必要な機能はライブラリ内のパッケージで提供されている可能性があります。するヘルパールーチンが含まれる、unicode/utf8です。関数を使用するプログラムを示します。関数の戻り値は、ルーンと、そのUTF-8エンコードされたバイト単位での幅です。}実行すると同じように動作します。同じ反復シーケンスを生成するように定義されています。パッケージのドキュメントを参照してください。冒頭で提起した質問に答えるために:文字列はバイトから構成されているため、それらのインデクシングは文字ではなくバイトを生成します。文字列は、文字を保持しない可能性もあります。実際には、「文字」の定義は曖昧であり、その曖昧さを、文字列は文字で作られていると定義することで解決しようとすることは、間違いでしょう。そこにはUnicode、UTF-8、多言語テキスト処理の世界について言うべきことはもっとありますが、それは別のポストを待ってください。今のところ、Go言語の文字列がどのように動作するか、それらが任意のバイトを含むことができること、UTF-8がその設計の中心であることについて、あなたがよりよい理解を得られたことを願っています。