]> Cypherpunks repositories - gostls13.git/commitdiff
bytes, strings: add new function Fields
authorAndrey Mirtchovski <mirtchovski@gmail.com>
Wed, 16 Dec 2009 05:09:55 +0000 (21:09 -0800)
committerRuss Cox <rsc@golang.org>
Wed, 16 Dec 2009 05:09:55 +0000 (21:09 -0800)
R=rsc, r, phf
CC=golang-dev
https://golang.org/cl/170046

src/pkg/bytes/bytes.go
src/pkg/bytes/bytes_test.go
src/pkg/strings/strings.go
src/pkg/strings/strings_test.go

index 0a21464133a880405b2619643a7fec6b74464a8b..d69af0136ab446d50f0542ff3176f86444cfbb7f 100644 (file)
@@ -163,6 +163,44 @@ func SplitAfter(s, sep []byte, n int) [][]byte {
        return genSplit(s, sep, len(sep), n)
 }
 
+// Fields splits the array s around each instance of one or more consecutive white space
+// characters, returning a slice of subarrays of s or an empty list if s contains only white space.
+func Fields(s []byte) [][]byte {
+       n := 0
+       inField := false
+       for i := 0; i < len(s); {
+               rune, size := utf8.DecodeRune(s[i:])
+               wasInField := inField
+               inField = !unicode.IsSpace(rune)
+               if inField && !wasInField {
+                       n++
+               }
+               i += size
+       }
+
+       a := make([][]byte, n)
+       na := 0
+       fieldStart := -1
+       for i := 0; i <= len(s) && na < n; {
+               rune, size := utf8.DecodeRune(s[i:])
+               if fieldStart < 0 && size > 0 && !unicode.IsSpace(rune) {
+                       fieldStart = i
+                       i += size
+                       continue
+               }
+               if fieldStart >= 0 && (size == 0 || unicode.IsSpace(rune)) {
+                       a[na] = s[fieldStart:i]
+                       na++
+                       fieldStart = -1
+               }
+               if size == 0 {
+                       break
+               }
+               i += size
+       }
+       return a[0:na]
+}
+
 // Join concatenates the elements of a to create a single byte array.   The separator
 // sep is placed between elements in the resulting array.
 func Join(a [][]byte, sep []byte) []byte {
index 4c6d4166a0133ef3ae445237ac6df6eafa0118e6..28ec55e3a9c84db4c0d489486eaad58dac02a05a 100644 (file)
@@ -254,6 +254,36 @@ func TestSplitAfter(t *testing.T) {
        }
 }
 
+type FieldsTest struct {
+       s string
+       a []string
+}
+
+var fieldstests = []FieldsTest{
+       FieldsTest{"", []string{}},
+       FieldsTest{" ", []string{}},
+       FieldsTest{" \t ", []string{}},
+       FieldsTest{"  abc  ", []string{"abc"}},
+       FieldsTest{"1 2 3 4", []string{"1", "2", "3", "4"}},
+       FieldsTest{"1  2  3  4", []string{"1", "2", "3", "4"}},
+       FieldsTest{"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+       FieldsTest{"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+       FieldsTest{"\u2000\u2001\u2002", []string{}},
+       FieldsTest{"\n™\t™\n", []string{"™", "™"}},
+       FieldsTest{faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+       for _, tt := range fieldstests {
+               a := Fields(strings.Bytes(tt.s))
+               result := arrayOfString(a)
+               if !eq(result, tt.a) {
+                       t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+                       continue
+               }
+       }
+}
+
 // Test case for any function which accepts and returns a byte array.
 // For ease of creation, we write the byte arrays as strings.
 type StringTest struct {
index ae34a5f3c30f0e5362ab8385701b4017fc439228..48d4f0e96a3f411335ecd99f557371706db7f965 100644 (file)
@@ -134,6 +134,40 @@ func SplitAfter(s, sep string, n int) []string {
        return genSplit(s, sep, len(sep), n)
 }
 
+// Fields splits the string s around each instance of one or more consecutive white space
+// characters, returning an array of substrings of s or an empty list if s contains only white space.
+func Fields(s string) []string {
+       n := 0
+       inField := false
+       for _, rune := range s {
+               wasInField := inField
+               inField = !unicode.IsSpace(rune)
+               if inField && !wasInField {
+                       n++
+               }
+       }
+
+       a := make([]string, n)
+       na := 0
+       fieldStart := -1
+       for i, rune := range s {
+               if unicode.IsSpace(rune) {
+                       if fieldStart >= 0 {
+                               a[na] = s[fieldStart:i]
+                               na++
+                               fieldStart = -1
+                       }
+               } else if fieldStart == -1 {
+                       fieldStart = i
+               }
+       }
+       if fieldStart != -1 {
+               a[na] = s[fieldStart:]
+               na++
+       }
+       return a[0:na]
+}
+
 // Join concatenates the elements of a to create a single string.   The separator string
 // sep is placed between elements in the resulting string.
 func Join(a []string, sep string) string {
index eb0f8d1fb554fdb37bcd54629d279a7d72919ce7..05df55ca94e164d349d30ccb726190f3cf3a76f8 100644 (file)
@@ -180,6 +180,36 @@ func TestSplitAfter(t *testing.T) {
        }
 }
 
+type FieldsTest struct {
+       s string
+       a []string
+}
+
+var fieldstests = []FieldsTest{
+       FieldsTest{"", []string{}},
+       FieldsTest{" ", []string{}},
+       FieldsTest{" \t ", []string{}},
+       FieldsTest{"  abc  ", []string{"abc"}},
+       FieldsTest{"1 2 3 4", []string{"1", "2", "3", "4"}},
+       FieldsTest{"1  2  3  4", []string{"1", "2", "3", "4"}},
+       FieldsTest{"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+       FieldsTest{"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+       FieldsTest{"\u2000\u2001\u2002", []string{}},
+       FieldsTest{"\n™\t™\n", []string{"™", "™"}},
+       FieldsTest{faces, []string{faces}},
+}
+
+func TestFields(t *testing.T) {
+       for _, tt := range fieldstests {
+               a := Fields(tt.s)
+               if !eq(a, tt.a) {
+                       t.Errorf("Fields(%q) = %v; want %v", tt.s, a, tt.a)
+                       continue
+               }
+       }
+}
+
+
 // Test case for any function which accepts and returns a single string.
 type StringTest struct {
        in, out string