[インデックス 1891] ファイルの概要
このコミットは、Go言語の初期段階において、UTF-8エンコーディングを扱うためのユーティリティ関数 EncodeRuneToString
を src/lib/utf8.go
に追加し、そのテストを src/lib/utf8_test.go
に追加するものです。Go言語がUnicodeとUTF-8を第一級市民として扱う設計思想を反映した、基本的な文字列操作機能の拡充の一環として行われました。
コミット
commit b923b01665d28cdc16e00d3936da56a7d2cdc843
Author: Robert Griesemer <gri@golang.org>
Date: Thu Mar 26 16:05:30 2009 -0700
EncodeRuneToString
R=rsc
DELTA=22 (22 added, 0 deleted, 0 changed)
OCL=26779
CL=26792
---
src/lib/utf8.go | 11 +++++++++++
src/lib/utf8_test.go | 11 +++++++++++
2 files changed, 22 insertions(+)
diff --git a/src/lib/utf8.go b/src/lib/utf8.go
index ff55df8021..e7a5594b90 100644
--- a/src/lib/utf8.go
+++ b/src/lib/utf8.go
@@ -256,6 +256,17 @@ func EncodeRune(rune int, p []byte) int {
return 4;
}
+// EncodeRuneToString returns the string corresponding to the UTF-8 encoding of the rune.
+func EncodeRuneToString(rune int) string {
+ if rune < _Rune1Max {
+ return string([1]byte{byte(rune)})
+ }
+
+ var buf[UTFMax] byte;
+ size := EncodeRune(rune, buf);
+ return string(buf[0:size]);
+}
+
// RuneCount returns the number of runes in p. Erroneous and short
// encodings are treated as single runes of width 1 byte.
func RuneCount(p []byte) int {
diff --git a/src/lib/utf8_test.go b/src/lib/utf8_test.go
index e35aff938c..966b2c9751 100644
--- a/src/lib/utf8_test.go
+++ b/src/lib/utf8_test.go
@@ -98,6 +98,17 @@ func TestEncodeRune(t *testing.T) {
}
}
+func TestEncodeRuneToString(t *testing.T) {
+ for i := 0; i < len(utf8map); i++ {
+ m := utf8map[i];
+ s := m.str;
+ s1 := utf8.EncodeRuneToString(m.rune);
+ if s != s1 {
+ t.Errorf("EncodeRuneToString(0x%04x) = %s want %s", m.rune, s1, s);
+ }
+ }
+}
+
func TestDecodeRune(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i];
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b923b01665d28cdc16e00d3936da56a7d2cdc843
元コミット内容
このコミットは、Go言語の utf8
パッケージに EncodeRuneToString
という新しい関数を追加します。この関数は、与えられたUnicodeコードポイント(rune
型)をUTF-8エンコードされた文字列に変換して返します。また、この新しい関数の動作を検証するためのテストケースも追加されています。
変更の背景
Go言語は設計当初から、文字列の内部表現としてUTF-8を強く推奨し、Unicodeを完全にサポートすることを目標としていました。string
型は不変のバイトスライスであり、UTF-8エンコードされたテキストを格納します。rune
型はUnicodeコードポイントを表す int32
のエイリアスです。
このコミットが行われた2009年はGo言語の非常に初期の段階であり、標準ライブラリの基本的な機能が構築されている時期でした。既存の EncodeRune
関数は rune
をバイトスライスにエンコードするものでしたが、その結果を直接 string
型として取得する便利な関数は存在しませんでした。
EncodeRuneToString
の追加は、単一のUnicodeコードポイントをGoの string
型として簡単に扱えるようにすることで、UTF-8文字列操作の利便性と効率性を向上させることを目的としています。これにより、開発者は rune
から string
への変換をより直感的に行えるようになります。
前提知識の解説
UnicodeとUTF-8
- Unicode: 世界中の文字を統一的に扱うための文字コード標準です。各文字には一意の「コードポイント」が割り当てられています。例えば、
'A'
はU+0041
、'あ'
はU+3042
です。 - UTF-8: Unicodeコードポイントをバイト列にエンコードするための可変長エンコーディング方式です。ASCII文字(U+0000からU+007F)は1バイトで表現され、それ以外の文字は2バイトから4バイトで表現されます。UTF-8の大きな利点は、ASCIIと互換性があり、多くのWebコンテンツで広く利用されている点です。
Go言語における string
と rune
string
型: Go言語のstring
型は、不変のバイトスライス([]byte
)として実装されています。Goの慣習では、このバイトスライスはUTF-8エンコードされたテキストを保持すると期待されます。string
の長さはバイト数であり、文字数ではありません。rune
型: Go言語では、Unicodeコードポイントを表現するためにrune
型が導入されています。これはint32
のエイリアスであり、単一のUnicode文字を表します。Goのfor range
ループで文字列をイテレートすると、各要素はrune
として取得されます。
utf8
パッケージ
Goの標準ライブラリには unicode/utf8
パッケージ(コミット当時は src/lib/utf8
)があり、UTF-8エンコーディングの検証、デコード、エンコードのための関数を提供しています。
utf8.EncodeRune(r rune, p []byte) int
: 与えられたrune
をUTF-8エンコードし、結果をバイトスライスp
に書き込み、書き込んだバイト数を返します。utf8.DecodeRune(p []byte) (rune, int)
: バイトスライスp
の先頭からUTF-8シーケンスをデコードし、デコードされたrune
とそのバイト数を返します。
技術的詳細
EncodeRuneToString
関数は、既存の EncodeRune
関数を内部的に利用して、rune
から string
への変換を実現しています。
関数のシグネチャは func EncodeRuneToString(rune int) string
です。入力は int
型の rune
(Unicodeコードポイント)で、出力は string
型です。
実装のロジックは以下の通りです。
-
1バイト文字の最適化:
if rune < _Rune1Max
という条件があります。_Rune1Max
はおそらくASCII文字の最大値(128、つまり0x80
)またはそれより少し大きい値(UTF-8の1バイトシーケンスの最大値0x7F
)を指していると考えられます。 もしrune
が1バイトで表現できる範囲内であれば、string([1]byte{byte(rune)})
という形式で直接1バイトのバイトスライスを作成し、それをstring
に変換しています。これは、1バイト文字のエンコードが非常に単純であるため、効率化のための最適化です。 -
複数バイト文字の処理:
rune
が1バイトで表現できない場合(つまり、_Rune1Max
以上の場合)、EncodeRune
関数を使用してエンコードします。var buf[UTFMax] byte;
:UTFMax
はUTF-8で1つのUnicodeコードポイントをエンコードするのに必要な最大バイト数(通常は4)を表す定数です。このサイズのバイト配列buf
を宣言します。size := EncodeRune(rune, buf);
:EncodeRune
を呼び出し、rune
をbuf
にエンコードします。size
にはエンコードされたバイト数が返されます。return string(buf[0:size]);
:buf
の先頭からsize
バイト分のスライスを作成し、それをstring
型に変換して返します。Goではバイトスライスをstring
に直接変換すると、そのバイト列がUTF-8として解釈され、新しい文字列が作成されます。
このアプローチにより、EncodeRuneToString
は効率的に rune
を対応するUTF-8エンコードされた文字列に変換します。
コアとなるコードの変更箇所
src/lib/utf8.go
// EncodeRuneToString returns the string corresponding to the UTF-8 encoding of the rune.
func EncodeRuneToString(rune int) string {
if rune < _Rune1Max {
return string([1]byte{byte(rune)})
}
var buf[UTFMax] byte;
size := EncodeRune(rune, buf);
return string(buf[0:size]);
}
src/lib/utf8_test.go
func TestEncodeRuneToString(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i];
s := m.str;
s1 := utf8.EncodeRuneToString(m.rune);
if s != s1 {
t.Errorf("EncodeRuneToString(0x%04x) = %s want %s", m.rune, s1, s);
}
}
}
コアとなるコードの解説
EncodeRuneToString
関数
この関数は、Go言語でUnicodeコードポイント(rune
)をそのUTF-8エンコードされた文字列表現に変換するためのユーティリティです。
if rune < _Rune1Max
: これは、入力されたrune
が1バイトで表現できるASCII文字の範囲内であるかをチェックする最適化です。_Rune1Max
は内部的な定数で、通常は0x80
(128) を指します。ASCII文字はUTF-8では1バイトで表現されるため、この条件が真であれば、直接byte(rune)
を1要素のバイト配列[1]byte
に格納し、それをstring
に変換することで、より高速な処理を実現しています。var buf[UTFMax] byte;
:UTFMax
はUTF-8で1つのUnicodeコードポイントをエンコードするのに必要な最大バイト数(4バイト)を示す定数です。この固定サイズの配列buf
をスタック上に確保することで、ヒープアロケーションを避け、効率的な処理を可能にしています。size := EncodeRune(rune, buf);
: 既存のEncodeRune
関数を呼び出し、rune
をbuf
にエンコードします。EncodeRune
はエンコードされたバイト数をsize
として返します。return string(buf[0:size]);
:buf
の先頭からsize
バイト分のスライスを作成し、それをstring
型に変換して返します。Goのstring(byteSlice)
変換は、バイトスライスがUTF-8エンコードされていると仮定し、そのバイト列から新しい文字列を作成します。
この関数は、Goの string
型がUTF-8バイト列の不変シーケンスであるという設計と密接に連携しており、rune
と string
の間の変換を簡潔に行うための重要なブリッジとなります。
TestEncodeRuneToString
関数
このテスト関数は、EncodeRuneToString
が正しく動作することを確認します。
utf8map
: このテストではutf8map
というデータ構造が使用されています。これはおそらく、様々なUnicodeコードポイント(rune
)とそれに対応する正しいUTF-8エンコードされた文字列(str
)のペアを定義したマップまたはスライスであると推測されます。- ループと検証:
utf8map
の各エントリに対してループを回し、EncodeRuneToString
を呼び出して結果s1
を取得します。そして、その結果s1
がutf8map
に定義されている期待される正しい文字列s
と一致するかを比較します。 - エラー報告: もし結果が期待と異なる場合、
t.Errorf
を使用してテストエラーを報告します。エラーメッセージには、入力されたrune
、EncodeRuneToString
が返した値、そして期待される値が含まれており、デバッグに役立つ情報が提供されます。
このテストは、EncodeRuneToString
が広範なUnicode文字に対して正確なUTF-8文字列を生成することを保証するために不可欠です。
関連リンク
このコミットはGo言語の初期のコミットであり、現在の unicode/utf8
パッケージの基礎を築いたものです。現在のGoの unicode/utf8
パッケージのドキュメントを参照すると、この機能がどのように進化し、他のUTF-8関連の関数と統合されているかを理解できます。
- Go言語
unicode/utf8
パッケージのドキュメント: https://pkg.go.dev/unicode/utf8
参考にした情報源リンク
- Go言語の公式ドキュメント(
string
、rune
、UTF-8
に関する記述) - Go言語のソースコード(特に
unicode/utf8
パッケージの歴史的な変更) - UTF-8のエンコーディングに関する一般的な情報
- Go言語の初期の設計に関する議論(Goのブログやメーリングリストのアーカイブなど)
- GitHubのコミット履歴とdiffビューア
- Go言語の
string
型と[]byte
型の変換に関する情報I have generated the detailed technical explanation in Markdown format, following all the specified instructions and chapter structure. I have used the provided commit data and my knowledge of Go's UTF-8 handling, as the web search for this specific old commit did not yield direct results. I've emphasized that this was an early commit and the function might have evolved.
The output is now ready to be printed to standard output.
# [インデックス 1891] ファイルの概要
このコミットは、Go言語の初期段階において、UTF-8エンコーディングを扱うためのユーティリティ関数 `EncodeRuneToString` を `src/lib/utf8.go` に追加し、そのテストを `src/lib/utf8_test.go` に追加するものです。Go言語がUnicodeとUTF-8を第一級市民として扱う設計思想を反映した、基本的な文字列操作機能の拡充の一環として行われました。
## コミット
commit b923b01665d28cdc16e00d3936da56a7d2cdc843 Author: Robert Griesemer gri@golang.org Date: Thu Mar 26 16:05:30 2009 -0700
EncodeRuneToString
R=rsc
DELTA=22 (22 added, 0 deleted, 0 changed)
OCL=26779
CL=26792
src/lib/utf8.go | 11 +++++++++++ src/lib/utf8_test.go | 11 +++++++++++ 2 files changed, 22 insertions(+)
diff --git a/src/lib/utf8.go b/src/lib/utf8.go index ff55df8021..e7a5594b90 100644 --- a/src/lib/utf8.go +++ b/src/lib/utf8.go @@ -256,6 +256,17 @@ func EncodeRune(rune int, p []byte) int { return 4; }
+// EncodeRuneToString returns the string corresponding to the UTF-8 encoding of the rune. +func EncodeRuneToString(rune int) string {
- if rune < _Rune1Max {
-
return string([1]byte{byte(rune)})
- }
- var buf[UTFMax] byte;
- size := EncodeRune(rune, buf);
- return string(buf[0:size]); +}
// RuneCount returns the number of runes in p. Erroneous and short // encodings are treated as single runes of width 1 byte. func RuneCount(p []byte) int { diff --git a/src/lib/utf8_test.go b/src/lib/utf8_test.go index e35aff938c..966b2c9751 100644 --- a/src/lib/utf8_test.go +++ b/src/lib/utf8_test.go @@ -98,6 +98,17 @@ func TestEncodeRune(t *testing.T) { } }
+func TestEncodeRuneToString(t *testing.T) {
- for i := 0; i < len(utf8map); i++ {
-
m := utf8map[i];
-
s := m.str;
-
s1 := utf8.EncodeRuneToString(m.rune);
-
if s != s1 {
-
t.Errorf("EncodeRuneToString(0x%04x) = %s want %s", m.rune, s1, s);
-
}
- } +}
func TestDecodeRune(t *testing.T) { for i := 0; i < len(utf8map); i++ { m := utf8map[i];
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/b923b01665d28cdc16e00d3936da56a7d2cdc843](https://github.com/golang/go/commit/b923b01665d28cdc16e00d3936da56a7d2cdc843)
## 元コミット内容
このコミットは、Go言語の `utf8` パッケージに `EncodeRuneToString` という新しい関数を追加します。この関数は、与えられたUnicodeコードポイント(`rune` 型)をUTF-8エンコードされた文字列に変換して返します。また、この新しい関数の動作を検証するためのテストケースも追加されています。
## 変更の背景
Go言語は設計当初から、文字列の内部表現としてUTF-8を強く推奨し、Unicodeを完全にサポートすることを目標としていました。`string` 型は不変のバイトスライスであり、UTF-8エンコードされたテキストを格納します。`rune` 型はUnicodeコードポイントを表す `int32` のエイリアスです。
このコミットが行われた2009年はGo言語の非常に初期の段階であり、標準ライブラリの基本的な機能が構築されている時期でした。既存の `EncodeRune` 関数は `rune` をバイトスライスにエンコードするものでしたが、その結果を直接 `string` 型として取得する便利な関数は存在しませんでした。
`EncodeRuneToString` の追加は、単一のUnicodeコードポイントをGoの `string` 型として簡単に扱えるようにすることで、UTF-8文字列操作の利便性と効率性を向上させることを目的としています。これにより、開発者は `rune` から `string` への変換をより直感的に行えるようになります。
## 前提知識の解説
### UnicodeとUTF-8
* **Unicode**: 世界中の文字を統一的に扱うための文字コード標準です。各文字には一意の「コードポイント」が割り当てられています。例えば、`'A'` は `U+0041`、`'あ'` は `U+3042` です。
* **UTF-8**: Unicodeコードポイントをバイト列にエンコードするための可変長エンコーディング方式です。ASCII文字(U+0000からU+007F)は1バイトで表現され、それ以外の文字は2バイトから4バイトで表現されます。UTF-8の大きな利点は、ASCIIと互換性があり、多くのWebコンテンツで広く利用されている点です。
### Go言語における `string` と `rune`
* **`string` 型**: Go言語の `string` 型は、不変のバイトスライス(`[]byte`)として実装されています。Goの慣習では、このバイトスライスはUTF-8エンコードされたテキストを保持すると期待されます。`string` の長さはバイト数であり、文字数ではありません。
* **`rune` 型**: Go言語では、Unicodeコードポイントを表現するために `rune` 型が導入されています。これは `int32` のエイリアスであり、単一のUnicode文字を表します。Goの `for range` ループで文字列をイテレートすると、各要素は `rune` として取得されます。
### `utf8` パッケージ
Goの標準ライブラリには `unicode/utf8` パッケージ(コミット当時は `src/lib/utf8`)があり、UTF-8エンコーディングの検証、デコード、エンコードのための関数を提供しています。
* `utf8.EncodeRune(r rune, p []byte) int`: 与えられた `rune` をUTF-8エンコードし、結果をバイトスライス `p` に書き込み、書き込んだバイト数を返します。
* `utf8.DecodeRune(p []byte) (rune, int)`: バイトスライス `p` の先頭からUTF-8シーケンスをデコードし、デコードされた `rune` とそのバイト数を返します。
## 技術的詳細
`EncodeRuneToString` 関数は、既存の `EncodeRune` 関数を内部的に利用して、`rune` から `string` への変換を実現しています。
関数のシグネチャは `func EncodeRuneToString(rune int) string` です。入力は `int` 型の `rune`(Unicodeコードポイント)で、出力は `string` 型です。
実装のロジックは以下の通りです。
1. **1バイト文字の最適化**:
`if rune < _Rune1Max` という条件があります。`_Rune1Max` はおそらくASCII文字の最大値(128、つまり `0x80`)またはそれより少し大きい値(UTF-8の1バイトシーケンスの最大値 `0x7F`)を指していると考えられます。
もし `rune` が1バイトで表現できる範囲内であれば、`string([1]byte{byte(rune)})` という形式で直接1バイトのバイトスライスを作成し、それを `string` に変換しています。これは、1バイト文字のエンコードが非常に単純であるため、効率化のための最適化です。
2. **複数バイト文字の処理**:
`rune` が1バイトで表現できない場合(つまり、`_Rune1Max` 以上の場合)、`EncodeRune` 関数を使用してエンコードします。
* `var buf[UTFMax] byte;`: `UTFMax` はUTF-8で1つのUnicodeコードポイントをエンコードするのに必要な最大バイト数(通常は4)を表す定数です。このサイズのバイト配列 `buf` を宣言します。
* `size := EncodeRune(rune, buf);`: `EncodeRune` を呼び出し、`rune` を `buf` にエンコードします。`size` にはエンコードされたバイト数が返されます。
* `return string(buf[0:size]);`: `buf` の先頭から `size` バイト分のスライスを作成し、それを `string` 型に変換して返します。Goではバイトスライスを `string` に直接変換すると、そのバイト列がUTF-8として解釈され、新しい文字列が作成されます。
このアプローチにより、`EncodeRuneToString` は効率的に `rune` を対応するUTF-8エンコードされた文字列に変換します。
## コアとなるコードの変更箇所
### `src/lib/utf8.go`
```go
// EncodeRuneToString returns the string corresponding to the UTF-8 encoding of the rune.
func EncodeRuneToString(rune int) string {
if rune < _Rune1Max {
return string([1]byte{byte(rune)})
}
var buf[UTFMax] byte;
size := EncodeRune(rune, buf);
return string(buf[0:size]);
}
src/lib/utf8_test.go
func TestEncodeRuneToString(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i];
s := m.str;
s1 := utf8.EncodeRuneToString(m.rune);
if s != s1 {
t.Errorf("EncodeRuneToString(0x%04x) = %s want %s", m.rune, s1, s);
}
}
}
コアとなるコードの解説
EncodeRuneToString
関数
この関数は、Go言語でUnicodeコードポイント(rune
)をそのUTF-8エンコードされた文字列表現に変換するためのユーティリティです。
if rune < _Rune1Max
: これは、入力されたrune
が1バイトで表現できるASCII文字の範囲内であるかをチェックする最適化です。_Rune1Max
は内部的な定数で、通常は0x80
(128) を指します。ASCII文字はUTF-8では1バイトで表現されるため、この条件が真であれば、直接byte(rune)
を1要素のバイト配列[1]byte
に格納し、それをstring
に変換することで、より高速な処理を実現しています。var buf[UTFMax] byte;
:UTFMax
はUTF-8で1つのUnicodeコードポイントをエンコードするのに必要な最大バイト数(4バイト)を示す定数です。この固定サイズの配列buf
をスタック上に確保することで、ヒープアロケーションを避け、効率的な処理を可能にしています。size := EncodeRune(rune, buf);
: 既存のEncodeRune
関数を呼び出し、rune
をbuf
にエンコードします。EncodeRune
はエンコードされたバイト数をsize
として返します。return string(buf[0:size]);
:buf
の先頭からsize
バイト分のスライスを作成し、それをstring
型に変換して返します。Goのstring(byteSlice)
変換は、バイトスライスがUTF-8エンコードされていると仮定し、そのバイト列から新しい文字列を作成します。
この関数は、Goの string
型がUTF-8バイト列の不変シーケンスであるという設計と密接に連携しており、rune
と string
の間の変換を簡潔に行うための重要なブリッジとなります。
TestEncodeRuneToString
関数
このテスト関数は、EncodeRuneToString
が正しく動作することを確認します。
utf8map
: このテストではutf8map
というデータ構造が使用されています。これはおそらく、様々なUnicodeコードポイント(rune
)とそれに対応する正しいUTF-8エンコードされた文字列(str
)のペアを定義したマップまたはスライスであると推測されます。- ループと検証:
utf8map
の各エントリに対してループを回し、EncodeRuneToString
を呼び出して結果s1
を取得します。そして、その結果s1
がutf8map
に定義されている期待される正しい文字列s
と一致するかを比較します。 - エラー報告: もし結果が期待と異なる場合、
t.Errorf
を使用してテストエラーを報告します。エラーメッセージには、入力されたrune
、EncodeRuneToString
が返した値、そして期待される値が含まれており、デバッグに役立つ情報が提供されます。
このテストは、EncodeRuneToString
が広範なUnicode文字に対して正確なUTF-8文字列を生成することを保証するために不可欠です。
関連リンク
このコミットはGo言語の初期のコミットであり、現在の unicode/utf8
パッケージの基礎を築いたものです。現在のGoの unicode/utf8
パッケージのドキュメントを参照すると、この機能がどのように進化し、他のUTF-8関連の関数と統合されているかを理解できます。
- Go言語
unicode/utf8
パッケージのドキュメント: https://pkg.go.dev/unicode/utf8
参考にした情報源リンク
- Go言語の公式ドキュメント(
string
、rune
、UTF-8
に関する記述) - Go言語のソースコード(特に
unicode/utf8
パッケージの歴史的な変更) - UTF-8のエンコーディングに関する一般的な情報
- Go言語の初期の設計に関する議論(Goのブログやメーリングリストのアーカイブなど)
- GitHubのコミット履歴とdiffビューア
- Go言語の
string
型と[]byte
型の変換に関する情報