diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 60de4515040..b86824087e5 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -138,6 +138,16 @@ func LastIndex(s, sep []byte) int { return -1 } +// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s. +func LastIndexByte(s []byte, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} + // IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points. // It returns the byte index of the first occurrence in s of the given rune. // It returns -1 if rune is not present in s. diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go index 980c41d754d..6245e481805 100644 --- a/src/bytes/bytes_test.go +++ b/src/bytes/bytes_test.go @@ -265,6 +265,23 @@ func TestIndexByte(t *testing.T) { } } +func TestLastIndexByte(t *testing.T) { + testCases := []BinOpTest{ + {"", "q", -1}, + {"abcdef", "q", -1}, + {"abcdefabcdef", "a", len("abcdef")}, // something in the middle + {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte + {"zabcdefabcdef", "z", 0}, // first byte + {"a☺b☻c☹d", "b", len("a☺")}, // non-ascii + } + for _, test := range testCases { + actual := LastIndexByte([]byte(test.a), test.b[0]) + if actual != test.i { + t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i) + } + } +} + // test a larger buffer with different sizes and alignments func TestIndexByteBig(t *testing.T) { var n = 1024 diff --git a/src/strings/strings.go b/src/strings/strings.go index c6085f51d59..7b8a6b536b5 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -271,6 +271,16 @@ func LastIndexAny(s, chars string) int { return -1 } +// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s. +func LastIndexByte(s string, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} + // Generic split: splits after each instance of sep, // including sepSave bytes of sep in the subarrays. func genSplit(s, sep string, sepSave, n int) []string { diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go index ee0c2607531..4e21deaecde 100644 --- a/src/strings/strings_test.go +++ b/src/strings/strings_test.go @@ -120,6 +120,23 @@ func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", l func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) } func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) } +func TestLastIndexByte(t *testing.T) { + testCases := []IndexTest{ + {"", "q", -1}, + {"abcdef", "q", -1}, + {"abcdefabcdef", "a", len("abcdef")}, // something in the middle + {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte + {"zabcdefabcdef", "z", 0}, // first byte + {"a☺b☻c☹d", "b", len("a☺")}, // non-ascii + } + for _, test := range testCases { + actual := LastIndexByte(test.s, test.sep[0]) + if actual != test.out { + t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out) + } + } +} + var indexRuneTests = []struct { s string rune rune