[インデックス 13652] ファイルの概要
このコミットは、Go言語の実験的なロケールパッケージ exp/locale/collate
における変更に関するものです。このパッケージは、Unicode Collation Algorithm (UCA) に基づいて文字列をロケール(地域や言語)固有のルールに従ってソート(照合)するための機能を提供します。具体的には、AlternateHandling
という照合オプションのデフォルト値を変更し、国際的に広く利用されているICU (International Components for Unicode) ライブラリのデフォルト動作に合わせることを目的としています。
コミット
exp/locale/collate
パッケージにおいて、AlternateHandling
のデフォルト値を AltShifted
から AltNonIgnorable
に変更しました。これはICUのデフォルト設定と同じです。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2845e5881f80a717b33b3ab515e1306a7c0001dd
元コミット内容
exp/locale/collate: changed default AlternateHandling to non-ignorable, the same
default as ICU.
R=r
CC=golang-dev
https://golang.org/cl/6445080
変更の背景
文字列の照合(ソート)は、言語や地域によってそのルールが大きく異なります。例えば、ドイツ語では 'ä' は 'a' と 'e' の間に来ることもあれば、'a' の後に来ることもあります。また、句読点や記号、スペースといった「変数文字 (variable characters)」の扱いも、ソートの目的によって変える必要があります。
このコミットが行われた当時、Go言語の exp/locale/collate
パッケージは、AlternateHandling
のデフォルト値として AltShifted
を採用していました。しかし、Unicode Collation Algorithm (UCA) のリファレンス実装として広く使われているICUライブラリでは、デフォルトで AltNonIgnorable
が採用されています。
この不一致は、Goの照合結果がICUのそれと異なる可能性を生み出し、国際化されたアプリケーション開発において予期せぬソート順序の問題を引き起こす可能性がありました。特に、多くの開発者がICUの動作を標準的なものとして認識しているため、Goのパッケージもそれに合わせることで、より直感的で互換性の高い動作を提供できるようになります。
したがって、この変更の背景には、Goの国際化関連パッケージの標準化と、既存の国際的な慣習(ICUのデフォルト)への準拠という目的があります。
前提知識の解説
1. コレーション (Collation)
コレーションとは、文字列を特定の言語やロケールのルールに従って比較し、ソート順序を決定するプロセスです。単に文字コードの順序で比較するのではなく、アクセント記号、大文字・小文字、句読点、複合文字(例: ドイツ語のßとss)などを考慮に入れます。
2. Unicode Collation Algorithm (UCA)
UCAは、Unicode Consortiumによって定義された、Unicode文字列の比較に関する標準アルゴリズムです。これにより、異なるプラットフォームやアプリケーション間でも一貫したソート順序が保証されます。UCAは、文字列を複数の「レベル」で比較します。
- レベル1 (Primary Level): 基本的な文字の形状(例: 'a' と 'A' は同じとみなされる)。
- レベル2 (Secondary Level): アクセント記号やダイアクリティカルマーク(例: 'a' と 'á' は異なる)。
- レベル3 (Tertiary Level): 大文字・小文字の違い(例: 'a' と 'A' は異なる)。
- レベル4 (Quaternary Level):
AlternateHandling
がShifted
の場合にのみ使用され、変数文字のソート順を決定します。
3. ICU (International Components for Unicode)
ICUは、Unicodeおよび国際化対応のためのオープンソースライブラリ群です。C/C++およびJavaで提供されており、コレーション、日付・時刻のフォーマット、数値のフォーマット、テキストの境界検出など、多岐にわたる国際化機能を提供します。多くのオペレーティングシステムやアプリケーションで利用されており、UCAの事実上のリファレンス実装として機能しています。
4. Alternate Handling (代替処理)
AlternateHandling
は、UCAにおける重要な設定の一つで、句読点、記号、スペースなどの「変数文字 (variable characters)」をソート順にどのように組み込むかを制御します。主な設定値は以下の通りです。
-
AltNonIgnorable
(非無視可能):- 変数文字は、プライマリ、セカンダリ、ターシャリのすべてのレベルでソート順に影響を与えます。
- 例: "a-b" と "ab" を比較すると、ハイフンがソート順に影響します。
- これは、文字通りすべての文字がソートに寄与する「ワードソート」や「シンボルソート」に適しています。ICUのデフォルト設定です。
-
AltShifted
(シフト):- 変数文字は、プライマリ、セカンダリ、ターシャリのレベルでは無視されます。
- しかし、これらの文字は第4のレベル(クォータナリレベル)で考慮され、ソート順に影響を与えます。
- 例: "a-b" と "ab" を比較すると、まず「ab」として比較され、その後にハイフンの有無が考慮されます。
- これは、句読点やスペースが単語のソート順に影響を与えない「辞書順ソート」に適しています。
-
AltBlanked
:- 変数文字は、すべてのレベルで完全に無視されます。これは、変数文字を文字列から削除して比較するのと同等です。
このコミットは、Goの exp/locale/collate
パッケージのデフォルトの AlternateHandling
を AltShifted
から AltNonIgnorable
に変更することで、ICUのデフォルト動作に合わせ、より標準的なコレーション動作を提供することを目指しています。
技術的詳細
Go言語では、iota
キーワードを使って連続する整数定数を定義できます。iota
は const
ブロック内で0から始まり、各定数宣言ごとに1ずつ増加します。
変更前の AlternateHandling
定義は以下のようになっていました。
const (
// AltShifted sets variables to be ignorable for levels one through three and
// adds a fourth level based on the values of the ignored levels.
AltShifted AlternateHandling = iota // AltShifted = 0
// AltNonIgnorable turns off special handling of variables.
AltNonIgnorable // AltNonIgnorable = 1
// AltBlanked sets variables and all subsequent primary ignorables to be
// ignorable at all levels. This is identical to removing all variables
// and subsequent primary ignorables from the input.
AltBlanked // AltBlanked = 2
// AltShiftTrimmed is a slight variant of AltShifted that is used to
// emulate POSIX.
AltShiftTrimmed // AltShiftTrimmed = 3
)
この定義では、AlternateHandling
型の変数が明示的に初期化されない場合、Goのゼロ値セマンティクスにより AltShifted
(値が0) がデフォルトとして使用されていました。
このコミットでは、AlternateHandling
定数の順序が変更されました。
const (
// AltNonIgnorable turns off special handling of variables.
AltNonIgnorable AlternateHandling = iota // AltNonIgnorable = 0
// AltBlanked sets variables and all subsequent primary ignorables to be
// ignorable at all levels. This is identical to removing all variables
// and subsequent primary ignorables from the input.
AltBlanked // AltBlanked = 1
// AltShifted sets variables to be ignorable for levels one through three and
// adds a fourth level based on the values of the ignored levels.
AltShifted // AltShifted = 2
// AltShiftTrimmed is a slight variant of AltShifted that is used to
// emulate POSIX.
AltShiftTrimmed // AltShiftTrimmed = 3
)
この変更により、iota
の割り当て順序が変わり、AltNonIgnorable
が0の値を持つようになりました。結果として、AlternateHandling
型の変数が明示的に設定されない場合、そのデフォルト値は AltNonIgnorable
となります。
このデフォルト値の変更に伴い、既存のテストコードも修正されています。以前は AltShifted
がデフォルトであったため、テストケースによっては AlternateHandling
を明示的に指定していなくても AltShifted
の動作が期待されていました。しかし、デフォルトが AltNonIgnorable
に変わったため、これらのテストケースが引き続き AltShifted
の動作を検証するためには、opts
構造体内で alt: collate.AltShifted
を明示的に設定する必要が生じました。
また、TestKey
関数内でも、特定のコレーターインスタンス c
に対して c.Alternate = collate.AltShifted
と明示的に設定することで、そのテストが意図する AltShifted
の動作を保証しています。
この技術的な変更は、Goのコレーションパッケージが、国際的な標準であるICUのデフォルト動作に準拠し、より予測可能で互換性のある挙動を提供する上で重要な一歩となります。
コアとなるコードの変更箇所
src/pkg/exp/locale/collate/collate.go
AlternateHandling
型の定数定義の順序が変更されました。
--- a/src/pkg/exp/locale/collate/collate.go
+++ b/src/pkg/exp/locale/collate/collate.go
@@ -35,18 +35,18 @@ const (
type AlternateHandling int
const (
-- // AltShifted sets variables to be ignorable for levels one through three and
-- // adds a fourth level based on the values of the ignored levels.
-- AltShifted AlternateHandling = iota
--
- // AltNonIgnorable turns off special handling of variables.
-- AltNonIgnorable
-+ AltNonIgnorable AlternateHandling = iota
-
- // AltBlanked sets variables and all subsequent primary ignorables to be
- // ignorable at all levels. This is identical to removing all variables
- // and subsequent primary ignorables from the input.
- AltBlanked
-
-+ // AltShifted sets variables to be ignorable for levels one through three and
-+ // adds a fourth level based on the values of the ignored levels.
-+ AltShifted
-+
- // AltShiftTrimmed is a slight variant of AltShifted that is used to
- // emulate POSIX.
- AltShiftTrimmed
src/pkg/exp/locale/collate/collate_test.go
keyFromElemTests
配列内の複数のテストケースで、opts
構造体に alt: collate.AltShifted
が追加されました。また、TestKey
関数内でコレーターの Alternate
フィールドが明示的に設定されました。
--- a/src/pkg/exp/locale/collate/collate_test.go
+++ b/src/pkg/exp/locale/collate/collate_test.go
@@ -223,7 +223,7 @@ const sep = 0 // separator byte
var keyFromElemTests = []keyFromElemTest{
{ // simple primary and secondary weights.
- opts{},
+ opts{alt: collate.AltShifted},
ColElems{w(0x200), w(0x7FFF), w(0, 0x30), w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
@@ -232,7 +232,7 @@ var keyFromElemTests = []keyFromElemTest{
},
},
{ // same as first, but with zero element that need to be removed
- opts{},
+ opts{alt: collate.AltShifted},
ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
@@ -241,7 +241,7 @@ var keyFromElemTests = []keyFromElemTest{
},
},
{ // same as first, with large primary values
- opts{},
+ opts{alt: collate.AltShifted},
ColElems{w(0x200), w(0x8000), w(0, 0x30), w(0x12345)},
[]byte{0x2, 0, 0x80, 0x80, 0x00, 0x81, 0x23, 0x45, // primary
sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
@@ -250,7 +250,7 @@ var keyFromElemTests = []keyFromElemTest{
},
},
{ // same as first, but with the secondary level backwards
- opts{backwards: true},
+ opts{alt: collate.AltShifted, backwards: true},
ColElems{w(0x200), w(0x7FFF), w(0, 0x30), w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
sep, sep, 0, defS, 0, 0x30, 0, defS, 0, defS, // secondary
@@ -259,7 +259,7 @@ var keyFromElemTests = []keyFromElemTest{
},
},
{ // same as first, ignoring quaternary level
- opts{lev: 3},
+ opts{alt: collate.AltShifted, lev: 3},
ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
@@ -267,14 +267,14 @@ var keyFromElemTests = []keyFromElemTest{
},
},
{ // same as first, ignoring tertiary level
- opts{lev: 2},
+ opts{alt: collate.AltShifted, lev: 2},
ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
sep, sep, 0, defS, 0, defS, 0, 0x30, 0, defS, // secondary
},
},
{ // same as first, ignoring secondary level
- opts{lev: 1},
+ opts{alt: collate.AltShifted, lev: 1},
ColElems{w(0x200), zero, w(0x7FFF), w(0, 0x30), zero, w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00},
},
@@ -288,7 +288,7 @@ var keyFromElemTests = []keyFromElemTest{
},
},
{ // as first, primary with case level enabled
- opts{lev: 1, caseLevel: true},
+ opts{alt: collate.AltShifted, lev: 1, caseLevel: true},
ColElems{w(0x200), w(0x7FFF), w(0, 0x30), w(0x100)},
[]byte{0x2, 0, 0x7F, 0xFF, 0x1, 0x00, // primary
sep, sep, // secondary
@@ -378,6 +378,7 @@ var keyTests = []keyTest{
func TestKey(t *testing.T) {
c, _ := makeTable(appendNextTests[4].in)
+ c.Alternate = collate.AltShifted
buf := collate.Buffer{}
keys1 := [][]byte{}
keys2 := [][]byte{}
コアとなるコードの解説
collate.go
の変更
collate.go
で行われた変更は、AlternateHandling
型の定数 AltNonIgnorable
と AltShifted
の定義順序を入れ替えることです。Goの iota
は const
ブロック内で0から始まる連番を自動的に割り当てるため、この順序変更によって AltNonIgnorable
が 0
の値を持つようになります。
Goでは、構造体のフィールドが明示的に初期化されない場合、その型のゼロ値が割り当てられます。AlternateHandling
は int
型のエイリアスであるため、そのゼロ値は 0
です。したがって、この変更により、AlternateHandling
が指定されていないコレーターインスタンスは、デフォルトで AltNonIgnorable
の動作をするようになります。これは、ICUのデフォルト動作と一致します。
collate_test.go
の変更
collate_test.go
の変更は、上記のデフォルト値の変更に対応するためのものです。
-
keyFromElemTests
の修正:keyFromElemTests
は、コレーションキー生成のテストケースを定義しています。以前は、これらのテストケースの一部はAlternateHandling
を明示的に設定していませんでしたが、当時のデフォルトであるAltShifted
の動作を暗黙的に期待していました。collate.go
の変更によりデフォルトがAltNonIgnorable
になったため、これらのテストケースが引き続きAltShifted
の動作を検証するためには、opts
構造体内でalt: collate.AltShifted
を明示的に指定する必要が生じました。これにより、テストの意図が明確になり、デフォルト値の変更後もテストが正しく機能することが保証されます。 -
TestKey
関数の修正:TestKey
関数内でも、コレーターインスタンスc
を作成した後、c.Alternate = collate.AltShifted
という行が追加されています。これは、この特定のテストがAltShifted
のコレーション動作に依存しているため、デフォルト値の変更に関わらず、テストが常にAltShifted
モードで実行されるようにするための明示的な設定です。
これらのテストの変更は、コードの動作変更(デフォルト値の変更)が、既存の期待される動作(テストケースが検証する動作)に影響を与えないようにするための、適切な対応と言えます。
関連リンク
- Go言語の
exp/locale/collate
パッケージ: https://pkg.go.dev/golang.org/x/text/collate (現在はgolang.org/x/text/collate
に移動している可能性があります) - Unicode Collation Algorithm (UCA): https://unicode.org/reports/tr10/
- ICU - International Components for Unicode: https://icu.unicode.org/
- ICU Collation Service: https://unicode-org.github.io/icu/userguide/collation/
参考にした情報源リンク
- Go言語の
iota
に関するドキュメント - Unicode Collation Algorithm (UCA) の仕様
- ICUのコレーションに関するドキュメント
- Go言語のテストの書き方に関する一般的な知識