[インデックス 10499] ファイルの概要
このコミットは、Go言語の標準ライブラリである strings
パッケージに、文字列内に特定の文字(群)が含まれているかを効率的に判定するための新しい関数 ContainsAny
と ContainsRune
を追加するものです。既存の IndexAny
および IndexRune
関数に対応する形で、より直感的な真偽値判定を提供します。
コミット
commit 0f0c25dcccee52c4fae3b54ca8b185984ceff1f9
Author: Scott Lawrence <bytbox@gmail.com>
Date: Wed Nov 23 20:20:14 2011 -0800
strings: Add ContainsAny and ContainsRune to correspond to IndexAny etc.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5430046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0f0c25dcccee52c4fae3b54ca8b185984ceff1f9
元コミット内容
strings: Add ContainsAny and ContainsRune to correspond to IndexAny etc.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5430046
変更の背景
Go言語の strings
パッケージには、特定のサブストリングや文字が文字列内に存在するかどうかを判定するための Contains
関数や、その位置を返す Index
関数群が既に存在していました。しかし、IndexAny
(文字列内の任意のUnicodeコードポイントのいずれかが含まれる最初のインデックスを返す)や IndexRune
(文字列内の特定のUnicodeコードポイントの最初のインデックスを返す)に対応する、真偽値を直接返す Contains
系の関数が欠けていました。
このコミットは、このギャップを埋めることを目的としています。IndexAny
や IndexRune
が返すインデックス値が -1
でないことを確認する代わりに、よりセマンティックで読みやすい ContainsAny
および ContainsRune
関数を提供することで、コードの可読性と利便性を向上させます。これは、Goの標準ライブラリにおけるAPIの一貫性を保つための一般的なパターンであり、ユーザーが特定の機能を探す際に予測しやすいインターフェースを提供します。
前提知識の解説
Go言語の strings
パッケージ
strings
パッケージは、Go言語におけるUTF-8でエンコードされた文字列を操作するための基本的な関数群を提供します。文字列の検索、置換、分割、結合、大文字小文字変換など、多岐にわたる機能が含まれています。
UnicodeとRune
Go言語の文字列はUTF-8でエンコードされています。これは、1つの文字が1バイト以上で表現される可能性があることを意味します。Goでは、このようなUnicodeコードポイントを表現するために rune
型が導入されています。rune
は int32
のエイリアスであり、単一のUnicodeコードポイントを表します。文字列を range
でイテレートすると、各要素は rune
型として取得されます。
Index
系関数と Contains
系関数
Index(s, substr string) int
: 文字列s
内でsubstr
が最初に出現するインデックスを返します。見つからない場合は-1
を返します。IndexAny(s, chars string) int
: 文字列s
内でchars
に含まれる任意のUnicodeコードポイントが最初に出現するインデックスを返します。見つからない場合は-1
を返します。IndexRune(s string, r rune) int
: 文字列s
内でr
が最初に出現するインデックスを返します。見つからない場合は-1
を返します。Contains(s, substr string) bool
: 文字列s
がsubstr
を含む場合にtrue
を返します。これは内部的にIndex(s, substr) != -1
と同等です。
このコミットで追加される ContainsAny
と ContainsRune
は、それぞれ IndexAny
と IndexRune
の結果を真偽値に変換するラッパー関数として機能します。
技術的詳細
追加された ContainsAny
と ContainsRune
関数は、非常にシンプルに実装されています。それぞれ対応する IndexAny
および IndexRune
関数を呼び出し、その結果が -1
(見つからなかったことを示す) でない場合に true
を返します。
-
ContainsAny(s, chars string) bool
:- 引数:
s
: 検索対象の文字列。chars
: 検索するUnicodeコードポイントを含む文字列。この文字列内の任意の文字がs
に含まれているかを判定します。
- 戻り値:
s
内にchars
のいずれかの文字が含まれていればtrue
、そうでなければfalse
。 - 実装:
return IndexAny(s, chars) >= 0
- 引数:
-
ContainsRune(s string, r rune) bool
:- 引数:
s
: 検索対象の文字列。r
: 検索する単一のUnicodeコードポイント(rune
型)。
- 戻り値:
s
内にr
が含まれていればtrue
、そうでなければfalse
。 - 実装:
return IndexRune(s, r) >= 0
- 引数:
また、既存の Contains
関数も Index(s, substr) != -1
から Index(s, substr) >= 0
に変更されています。これは機能的には同じですが、-1
が「見つからない」ことを意味するインデックスの慣習的な表現であるため、>= 0
は「見つかった」(つまり、インデックスが0以上)という意図をより明確に示します。同様に、FieldsFunc
と makeCutsetFunc
内の条件式も != -1
から >= 0
に変更され、一貫性が保たれています。
テストコードでは、これらの新しい関数が期待通りに動作するかを確認するために、様々なケース(空文字列、単一文字、複数文字、Unicode文字、特殊文字など)を網羅したテストケースが追加されています。
コアとなるコードの変更箇所
src/pkg/strings/strings.go
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -64,7 +64,17 @@ func Count(s, sep string) int {
// Contains returns true if substr is within s.
func Contains(s, substr string) bool {
- return Index(s, substr) != -1
+ return Index(s, substr) >= 0
+}
+
+// ContainsAny returns true if any Unicode code points in chars are within s.
+func ContainsAny(s, chars string) bool {
+ return IndexAny(s, chars) >= 0
+}
+
+// ContainsRune returns true if the Unicode code point r is within s.
+func ContainsRune(s string, r rune) bool {
+ return IndexRune(s, r) >= 0
}
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
@@ -269,7 +279,7 @@ func FieldsFunc(s string, f func(rune) bool) []string {
fieldStart = i
}
}
- if fieldStart != -1 { // Last field might end at EOF.
+ if fieldStart >= 0 { // Last field might end at EOF.
a[na] = s[fieldStart:]
}
return a
@@ -512,7 +522,7 @@ func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
}
func makeCutsetFunc(cutset string) func(rune) bool {
- return func(r rune) bool { return IndexRune(cutset, r) != -1 }
+ return func(r rune) bool { return IndexRune(cutset, r) >= 0 }
}
// Trim returns a slice of the string s with all leading and
src/pkg/strings/strings_test.go
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -908,6 +908,56 @@ func TestContains(t *testing.T) {
}
}
+var ContainsAnyTests = []struct {
+ str, substr string
+ expected bool
+}{
+ {"", "", false},
+ {"", "a", false},
+ {"", "abc", false},
+ {"a", "", false},
+ {"a", "a", true},
+ {"aaa", "a", true},
+ {"abc", "xyz", false},
+ {"abc", "xcz", true},
+ {"a☺b☻c☹d", "uvw☻xyz", true},
+ {"aRegExp*", ".(|)*+?^$[]", true},
+ {dots + dots + dots, " ", false},
+}
+
+func TestContainsAny(t *testing.T) {
+ for _, ct := range ContainsAnyTests {
+ if ContainsAny(ct.str, ct.substr) != ct.expected {
+ t.Errorf("ContainsAny(%s, %s) = %v, want %v",
+ ct.str, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
+
+var ContainsRuneTests = []struct {
+ str string
+ r rune
+ expected bool
+}{
+ {"", 'a', false},
+ {"a", 'a', true},
+ {"aaa", 'a', true},
+ {"abc", 'y', false},
+ {"abc", 'c', true},
+ {"a☺b☻c☹d", 'x', false},
+ {"a☺b☻c☹d", '☻', true},
+ {"aRegExp*", '*', true},
+}
+
+func TestContainsRune(t *testing.T) {
+ for _, ct := range ContainsRuneTests {
+ if ContainsRune(ct.str, ct.r) != ct.expected {
+ t.Errorf("ContainsRune(%s, %s) = %v, want %v",
+ ct.str, ct.r, !ct.expected, ct.expected)
+ }
+ }
+}
+
var EqualFoldTests = []struct {
s, t string
out bool
コアとなるコードの解説
strings.go
の変更点
-
Contains
関数の修正:return Index(s, substr) != -1
からreturn Index(s, substr) >= 0
へ変更。- これは機能的な変更ではなく、インデックスが「見つかった」ことを示す条件をより明確にするための表現の変更です。
Index
関数は、部分文字列が見つからない場合に-1
を返すため、!= -1
と>= 0
は同じ論理結果をもたらします。
-
ContainsAny
関数の追加:IndexAny(s, chars)
の結果が>= 0
であるかを返します。- これにより、
chars
内の任意の文字がs
に含まれているかを簡潔に判定できます。
-
ContainsRune
関数の追加:IndexRune(s, r)
の結果が>= 0
であるかを返します。- これにより、特定の
rune
がs
に含まれているかを簡潔に判定できます。
-
FieldsFunc
およびmakeCutsetFunc
内の条件式の修正:- これらの関数内の
fieldStart != -1
やIndexRune(cutset, r) != -1
といった条件式も、>= 0
を使用するように変更されています。これは、Contains
関数の変更と同様に、コード全体でのインデックスチェックの慣習を統一するためのものです。
- これらの関数内の
strings_test.go
の変更点
-
ContainsAnyTests
とTestContainsAny
の追加:ContainsAny
関数の動作を検証するためのテストケースとテスト関数が追加されています。- 様々な文字列と文字セットの組み合わせに対して、期待される真偽値が正しく返されるかを確認します。Unicode文字や正規表現の特殊文字を含むケースも含まれています。
-
ContainsRuneTests
とTestContainsRune
の追加:ContainsRune
関数の動作を検証するためのテストケースとテスト関数が追加されています。- 空文字列、単一文字、複数文字、Unicode文字、特殊文字など、多様な
rune
と文字列の組み合わせでテストが行われます。
これらの変更により、strings
パッケージはより完全で使いやすくなり、開発者は文字列内の文字の存在をより直感的にチェックできるようになりました。
関連リンク
- Go言語
strings
パッケージのドキュメント: https://pkg.go.dev/strings - Go言語の
rune
について: https://go.dev/blog/strings
参考にした情報源リンク
- Go言語の公式ドキュメント (
pkg.go.dev/strings
) - Go言語のブログ記事 (
go.dev/blog/strings
) - GitHub上のGo言語リポジトリのコミット履歴
- 一般的なGo言語の文字列操作に関する知識The user wants a detailed explanation of a Git commit. I have already read the commit data. Now I need to perform a web search to gather more context and technical details, especially regarding Go's
strings
package,rune
type, and theIndexAny
/IndexRune
functions.
I will use google_web_search
to find relevant information.
Here's a refined plan:
- Parse the commit data: (Already done in the previous turn, I have the content of
10499.txt
). - Understand the changes: Analyze
strings.go
andstrings_test.go
to understand the new functionsContainsAny
andContainsRune
and the modifications to existingContains
,FieldsFunc
, andmakeCutsetFunc
. (This is an internal analysis step). - Research Go's
strings
package: Understand its purpose and common functions. - Research
IndexAny
andIndexRune
: Understand how these functions work, as the newContainsAny
andContainsRune
are based on them. - Explain the background: Why were these functions added? The commit message says "to correspond to IndexAny etc." which implies a consistency reason.
- Explain prerequisite knowledge: What are runes, Unicode, and string manipulation in Go?
- Detail the technical aspects: How do
ContainsAny
andContainsRune
work internally? What are their signatures and return values? - Describe core code changes: Point out the specific lines added/modified in
strings.go
andstrings_test.go
. - Explain core code: Elaborate on the implementation of the new functions and the minor changes to existing ones.
- Find related links: Search for Go documentation on the
strings
package, especially forContains
,IndexAny
,IndexRune
. - Identify sources: List the sources used for the explanation.
I will now perform the web searches.# [インデックス 10499] ファイルの概要
このコミットは、Go言語の標準ライブラリである strings
パッケージに、文字列内に特定の文字(群)が含まれているかを効率的に判定するための新しい関数 ContainsAny
と ContainsRune
を追加するものです。既存の IndexAny
および IndexRune
関数に対応する形で、より直感的な真偽値判定を提供します。
コミット
commit 0f0c25dcccee52c4fae3b54ca8b185984ceff1f9
Author: Scott Lawrence <bytbox@gmail.com>
Date: Wed Nov 23 20:20:14 2011 -0800
strings: Add ContainsAny and ContainsRune to correspond to IndexAny etc.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5430046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/0f0c25dcccee52c4fae3b54ca8b185984ceff1f9
元コミット内容
strings: Add ContainsAny and ContainsRune to correspond to IndexAny etc.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5430046
変更の背景
Go言語の strings
パッケージには、特定のサブストリングや文字が文字列内に存在するかどうかを判定するための Contains
関数や、その位置を返す Index
関数群が既に存在していました。しかし、IndexAny
(文字列内の任意のUnicodeコードポイントのいずれかが含まれる最初のインデックスを返す)や IndexRune
(文字列内の特定のUnicodeコードポイントの最初のインデックスを返す)に対応する、真偽値を直接返す Contains
系の関数が欠けていました。
このコミットは、このギャップを埋めることを目的としています。IndexAny
や IndexRune
が返すインデックス値が -1
でないことを確認する代わりに、よりセマンティックで読みやすい ContainsAny
および ContainsRune
関数を提供することで、コードの可読性と利便性を向上させます。これは、Goの標準ライブラリにおけるAPIの一貫性を保つための一般的なパターンであり、ユーザーが特定の機能を探す際に予測しやすいインターフェースを提供します。
前提知識の解説
Go言語の strings
パッケージ
strings
パッケージは、Go言語におけるUTF-8でエンコードされた文字列を操作するための基本的な関数群を提供します。文字列の検索、置換、分割、結合、大文字小文字変換など、多岐にわたる機能が含まれています。
UnicodeとRune
Go言語の文字列はUTF-8でエンコードされています。これは、1つの文字が1バイト以上で表現される可能性があることを意味します。Goでは、このようなUnicodeコードポイントを表現するために rune
型が導入されています。rune
は int32
のエイリアスであり、単一のUnicodeコードポイントを表します。文字列を range
でイテレートすると、各要素は rune
型として取得されます。
Index
系関数と Contains
系関数
Index(s, substr string) int
: 文字列s
内でsubstr
が最初に出現するインデックスを返します。見つからない場合は-1
を返します。IndexAny(s, chars string) int
: 文字列s
内でchars
に含まれる任意のUnicodeコードポイントが最初に出現するインデックスを返します。見つからない場合は-1
を返します。IndexRune(s string, r rune) int
: 文字列s
内でr
が最初に出現するインデックスを返します。見つからない場合は-1
を返します。Contains(s, substr string) bool
: 文字列s
がsubstr
を含む場合にtrue
を返します。これは内部的にIndex(s, substr) != -1
と同等です。
このコミットで追加される ContainsAny
と ContainsRune
は、それぞれ IndexAny
と IndexRune
の結果を真偽値に変換するラッパー関数として機能します。
技術的詳細
追加された ContainsAny
と ContainsRune
関数は、非常にシンプルに実装されています。それぞれ対応する IndexAny
および IndexRune
関数を呼び出し、その結果が -1
(見つからなかったことを示す) でない場合に true
を返します。
-
ContainsAny(s, chars string) bool
:- 引数:
s
: 検索対象の文字列。chars
: 検索するUnicodeコードポイントを含む文字列。この文字列内の任意の文字がs
に含まれているかを判定します。
- 戻り値:
s
内にchars
のいずれかの文字が含まれていればtrue
、そうでなければfalse
。 - 実装:
return IndexAny(s, chars) >= 0
- 引数:
-
ContainsRune(s string, r rune) bool
:- 引数:
s
: 検索対象の文字列。r
: 検索する単一のUnicodeコードポイント(rune
型)。
- 戻り値:
s
内にr
が含まれていればtrue
、そうでなければfalse
。 - 実装:
return IndexRune(s, r) >= 0
- 引数:
また、既存の Contains
関数も Index(s, substr) != -1
から Index(s, substr) >= 0
に変更されています。これは機能的には同じですが、-1
が「見つからない」ことを意味するインデックスの慣習的な表現であるため、>= 0
は「見つかった」(つまり、インデックスが0以上)という意図をより明確に示します。同様に、FieldsFunc
と makeCutsetFunc
内の条件式も != -1
から >= 0
に変更され、一貫性が保たれています。
テストコードでは、これらの新しい関数が期待通りに動作するかを確認するために、様々なケース(空文字列、単一文字、複数文字、Unicode文字、特殊文字など)を網羅したテストケースが追加されています。
コアとなるコードの変更箇所
src/pkg/strings/strings.go
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -64,7 +64,17 @@ func Count(s, sep string) int {
// Contains returns true if substr is within s.
func Contains(s, substr string) bool {
- return Index(s, substr) != -1
+ return Index(s, substr) >= 0
+}
+
+// ContainsAny returns true if any Unicode code points in chars are within s.
+func ContainsAny(s, chars string) bool {
+ return IndexAny(s, chars) >= 0
+}
+
+// ContainsRune returns true if the Unicode code point r is within s.
+func ContainsRune(s string, r rune) bool {
+ return IndexRune(s, r) >= 0
}
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
@@ -269,7 +279,7 @@ func FieldsFunc(s string, f func(rune) bool) []string {
fieldStart = i
}
}
- if fieldStart != -1 { // Last field might end at EOF.
+ if fieldStart >= 0 { // Last field might end at EOF.
a[na] = s[fieldStart:]
}
return a
@@ -512,7 +522,7 @@ func lastIndexFunc(s string, f func(rune) bool, truth bool) int {
}
func makeCutsetFunc(cutset string) func(rune) bool {
- return func(r rune) bool { return IndexRune(cutset, r) != -1 }\n+\treturn func(r rune) bool { return IndexRune(cutset, r) >= 0 }
}
// Trim returns a slice of the string s with all leading and
src/pkg/strings/strings_test.go
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -908,6 +908,56 @@ func TestContains(t *testing.T) {
}
}
+var ContainsAnyTests = []struct {
+ str, substr string
+ expected bool
+}{
+ {"", "", false},
+ {"", "a", false},
+ {"", "abc", false},
+ {"a", "", false},
+ {"a", "a", true},
+ {"aaa", "a", true},
+ {"abc", "xyz", false},
+ {"abc", "xcz", true},
+ {"a☺b☻c☹d", "uvw☻xyz", true},
+ {"aRegExp*", ".(|)*+?^$[]", true},
+ {dots + dots + dots, " ", false},
+}
+
+func TestContainsAny(t *testing.T) {
+ for _, ct := range ContainsAnyTests {
+ if ContainsAny(ct.str, ct.substr) != ct.expected {
+ t.Errorf("ContainsAny(%s, %s) = %v, want %v",
+ ct.str, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
+
+var ContainsRuneTests = []struct {
+ str string
+ r rune
+ expected bool
+}{
+ {"", 'a', false},
+ {"a", 'a', true},
+ {"aaa", 'a', true},
+ {"abc", 'y', false},
+ {"abc", 'c', true},
+ {"a☺b☻c☹d", 'x', false},
+ {"a☺b☻c☹d", '☻', true},
+ {"aRegExp*", '*', true},
+}
+
+func TestContainsRune(t *testing.T) {
+ for _, ct := range ContainsRuneTests {
+ if ContainsRune(ct.str, ct.r) != ct.expected {
+ t.Errorf("ContainsRune(%s, %s) = %v, want %v",
+ ct.str, ct.r, !ct.expected, ct.expected)
+ }
+ }
+}
+
var EqualFoldTests = []struct {
s, t string
out bool
コアとなるコードの解説
strings.go
の変更点
-
Contains
関数の修正:return Index(s, substr) != -1
からreturn Index(s, substr) >= 0
へ変更。- これは機能的な変更ではなく、インデックスが「見つかった」ことを示す条件をより明確にするための表現の変更です。
Index
関数は、部分文字列が見つからない場合に-1
を返すため、!= -1
と>= 0
は同じ論理結果をもたらします。
-
ContainsAny
関数の追加:IndexAny(s, chars)
の結果が>= 0
であるかを返します。- これにより、
chars
内の任意の文字がs
に含まれているかを簡潔に判定できます。
-
ContainsRune
関数の追加:IndexRune(s, r)
の結果が>= 0
であるかを返します。- これにより、特定の
rune
がs
に含まれているかを簡潔に判定できます。
-
FieldsFunc
およびmakeCutsetFunc
内の条件式の修正:- これらの関数内の
fieldStart != -1
やIndexRune(cutset, r) != -1
といった条件式も、>= 0
を使用するように変更されています。これは、Contains
関数の変更と同様に、コード全体でのインデックスチェックの慣習を統一するためのものです。
- これらの関数内の
strings_test.go
の変更点
-
ContainsAnyTests
とTestContainsAny
の追加:ContainsAny
関数の動作を検証するためのテストケースとテスト関数が追加されています。- 様々な文字列と文字セットの組み合わせに対して、期待される真偽値が正しく返されるかを確認します。Unicode文字や正規表現の特殊文字を含むケースも含まれています。
-
ContainsRuneTests
とTestContainsRune
の追加:ContainsRune
関数の動作を検証するためのテストケースとテスト関数が追加されています。- 空文字列、単一文字、複数文字、Unicode文字、特殊文字など、多様な
rune
と文字列の組み合わせでテストが行われます。
これらの変更により、strings
パッケージはより完全で使いやすくなり、開発者は文字列内の文字の存在をより直感的にチェックできるようになりました。
関連リンク
- Go言語
strings
パッケージのドキュメント: https://pkg.go.dev/strings - Go言語の
rune
について: https://go.dev/blog/strings
参考にした情報源リンク
- Go言語の公式ドキュメント (
pkg.go.dev/strings
) - Go言語のブログ記事 (
go.dev/blog/strings
) - GitHub上のGo言語リポジトリのコミット履歴
- 一般的なGo言語の文字列操作に関する知識