From d7b4851586a912e0166bc405cf8aace5f77d96d7 Mon Sep 17 00:00:00 2001 From: Kyle Consalus Date: Tue, 20 Apr 2010 22:18:26 -0700 Subject: [PATCH] strings: add ReadRune to Reader R=rsc CC=golang-dev https://golang.org/cl/940041 --- src/pkg/strings/reader.go | 27 +++++++++++++++++++++++++-- src/pkg/strings/strings_test.go | 23 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/pkg/strings/reader.go b/src/pkg/strings/reader.go index 7cefbd24bbe..914faa00359 100644 --- a/src/pkg/strings/reader.go +++ b/src/pkg/strings/reader.go @@ -4,9 +4,12 @@ package strings -import "os" +import ( + "os" + "utf8" +) -// A Reader satisfies calls to Read and ReadByte by +// A Reader satisfies calls to Read, ReadByte, and ReadRune by // reading from a string. type Reader string @@ -33,6 +36,26 @@ func (r *Reader) ReadByte() (b byte, err os.Error) { return } +// ReadRune reads and returns the next UTF-8-encoded +// Unicode code point from the buffer. +// If no bytes are available, the error returned is os.EOF. +// If the bytes are an erroneous UTF-8 encoding, it +// consumes one byte and returns U+FFFD, 1. +func (r *Reader) ReadRune() (rune int, size int, err os.Error) { + s := *r + if len(s) == 0 { + return 0, 0, os.EOF + } + c := s[0] + if c < utf8.RuneSelf { + *r = s[1:] + return int(c), 1, nil + } + rune, size = utf8.DecodeRuneInString(string(s)) + *r = s[size:] + return +} + // NewReader returns a new Reader reading from s. // It is similar to bytes.NewBufferString but more efficient and read-only. func NewReader(s string) *Reader { return (*Reader)(&s) } diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go index 3c9dc5847a7..2c99a6ec360 100644 --- a/src/pkg/strings/strings_test.go +++ b/src/pkg/strings/strings_test.go @@ -5,6 +5,7 @@ package strings_test import ( + "os" . "strings" "testing" "unicode" @@ -576,3 +577,25 @@ func TestRunes(t *testing.T) { } } } + +func TestReadRune(t *testing.T) { + testStrings := []string{"", abcd, faces, commas} + for _, s := range testStrings { + reader := NewReader(s) + res := "" + for { + r, _, e := reader.ReadRune() + if e == os.EOF { + break + } + if e != nil { + t.Errorf("Reading %q: %s", s, e) + break + } + res += string(r) + } + if res != s { + t.Errorf("Reader(%q).ReadRune() produced %q", s, res) + } + } +}