Skip to content

Commit 23553ea

Browse files
committed
Find/REplace works with Umlauts
1 parent e93c44a commit 23553ea

File tree

4 files changed

+38
-20
lines changed

4 files changed

+38
-20
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T
66

77
## [Unreleased]
88

9+
### Fixed
10+
- Fixed a bug where find and friends and Replace did not work properly with umlauts or 2 (or more) byte character
11+
912
## [0.5.0] - 2022-12-26
1013

1114
### Added

search.go

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,22 @@ package Text
33
// Returns all occurences of needle in haystack
44
func findAll(haystack []rune, needle string) []int {
55

6-
if len(haystack) == 0 || len(needle) == 0 || len(needle) > len(haystack) {
6+
needleAsRunes := []rune(needle)
7+
lenNeedle := len(needleAsRunes)
8+
9+
if len(haystack) == 0 || len(needle) == 0 || lenNeedle > len(haystack) {
710
return []int{}
811
}
912

1013
items := make([]int, 0, 8)
1114

1215
for i := 0; i < len(haystack); i++ {
13-
for j := 0; j < len(needle); j++ {
14-
if haystack[i+j] != rune(needle[j]) {
16+
for j := 0; j < lenNeedle; j++ {
17+
if haystack[i+j] != needleAsRunes[j] {
1518
break
1619
}
1720

18-
if j == len(needle)-1 {
21+
if j == lenNeedle-1 {
1922
items = append(items, i)
2023
}
2124
}
@@ -26,16 +29,18 @@ func findAll(haystack []rune, needle string) []int {
2629

2730
// Returns the first occurrence of haystack in needle or -1 if not found.
2831
func findFirst(haystack []rune, needle string) int {
29-
if len(haystack) == 0 || len(needle) == 0 || len(needle) > len(haystack) {
32+
needleAsRunes := []rune(needle)
33+
lenNeedle := len(needleAsRunes)
34+
35+
if len(haystack) == 0 || len(needle) == 0 || lenNeedle > len(haystack) {
3036
return -1
3137
}
3238

3339
lenHaystack := len(haystack)
34-
lenNeedle := len(needle)
3540

3641
for i := 0; i <= lenHaystack-lenNeedle; i++ {
3742
for j := 0; j < lenNeedle; j++ {
38-
if haystack[i+j] != rune(needle[j]) {
43+
if haystack[i+j] != needleAsRunes[j] {
3944
break
4045
}
4146

@@ -50,16 +55,18 @@ func findFirst(haystack []rune, needle string) int {
5055

5156
// Returns the last occurrence of haystack in needle or -1 if not found.
5257
func findLast(haystack []rune, needle string) int {
53-
if len(haystack) == 0 || len(needle) == 0 || len(needle) > len(haystack) {
58+
needleAsRunes := []rune(needle)
59+
lenNeedle := len(needleAsRunes)
60+
61+
if len(haystack) == 0 || len(needle) == 0 || lenNeedle > len(haystack) {
5462
return -1
5563
}
5664

5765
lenHaystack := len(haystack)
58-
lenNeedle := len(needle)
5966

60-
for i := lenHaystack - lenNeedle + 1; i >= 0; i-- {
67+
for i := lenHaystack - lenNeedle; i >= 0; i-- {
6168
for j := 0; j < lenNeedle; j++ {
62-
if haystack[i+j] != rune(needle[j]) {
69+
if haystack[i+j] != needleAsRunes[j] {
6370
break
6471
}
6572

stringbuilder.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func NewStringBuilder(initialCapacity int) *StringBuilder {
1616
func NewStringBuilderFromString(text string) *StringBuilder {
1717
return &StringBuilder{
1818
data: []rune(text),
19-
position: len(text),
19+
position: len([]rune(text)),
2020
}
2121
}
2222

@@ -155,26 +155,29 @@ func (s *StringBuilder) Replace(oldValue string, newValue string) {
155155

156156
occurrences := s.FindAll(oldValue)
157157

158-
delta := len(newValue) - len(oldValue)
158+
oldValueRunes := []rune(oldValue)
159+
newValueRunes := []rune(newValue)
160+
161+
delta := len(newValueRunes) - len(oldValueRunes)
159162

160163
for i := 0; i < len(occurrences); i++ {
161164
index := occurrences[i] + delta*i
162165

163166
// newValue is smaller than old value
164167
// We can insert the slice and remove the overhead
165168
if delta < 0 {
166-
copy(s.data[index:], []rune(newValue))
167-
s.Remove(index+len(newValue), -delta)
169+
copy(s.data[index:], newValueRunes)
170+
s.Remove(index+len(newValueRunes), -delta)
168171
} else if delta == 0 {
169172
// Same length -> We can just replace the memory slice
170-
copy(s.data[index:], []rune(newValue))
173+
copy(s.data[index:], newValueRunes)
171174
} else {
172175
// newValue is larger than the old value
173176
// First add until the old memory region
174177
// and insert afterwards the rest
175-
x := len(oldValue)
176-
copy(s.data[index:], []rune(newValue[:x]))
177-
s.Insert(index+len(oldValue), newValue[len(oldValue):])
178+
oldLen := len(oldValueRunes)
179+
copy(s.data[index:], []rune(newValueRunes[:oldLen]))
180+
s.Insert(index+oldLen, string(newValueRunes[len(oldValueRunes):]))
178181
}
179182
}
180183
}

stringbuilder_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ func TestFindFirst(t *testing.T) {
217217
{"Empty needle", "n", "", -1},
218218
{"Needle longer than haystack", "a", "ab", -1},
219219
{"Hello in Hello World", "Hello World", "Hello", 0},
220+
{"ö in Helöö", "Hellöö", "ö", 4},
220221
}
221222
for _, tt := range tests {
222223
t.Run(tt.name, func(t *testing.T) {
@@ -239,6 +240,7 @@ func TestFindLast(t *testing.T) {
239240
{"Empty needle", "n", "", -1},
240241
{"Needle longer than haystack", "a", "ab", -1},
241242
{"Hello in Hello World", "Hello World", "Hello", 0},
243+
{"ö in Helöö", "Hellöö", "ö", 5},
242244
}
243245
for _, tt := range tests {
244246
t.Run(tt.name, func(t *testing.T) {
@@ -261,6 +263,7 @@ func TestFindAll(t *testing.T) {
261263
{"Empty needle", "n", "", []int{}},
262264
{"Needle longer than haystack", "a", "ab", []int{}},
263265
{"Hello in Hello World", "Hello World", "Hello", []int{0}},
266+
{"ö in Helöö", "Hellöö", "ö", []int{4, 5}},
264267
}
265268
for _, tt := range tests {
266269
t.Run(tt.name, func(t *testing.T) {
@@ -292,7 +295,9 @@ func TestReplace(t *testing.T) {
292295
}{
293296
{"Replace Hello with Hallo", "Hello World", "Hello", "Hallo", "Hallo World"},
294297
{"Replace Hello with Ha", "Hello World", "Hello", "Ha", "Ha World"},
295-
{"Replace Hello with Hallöchen", "Hello World", "Hello", "Hallochen", "Hallochen World"},
298+
{"Replace Hello with Hallochen", "Hello World", "Hello", "Hallochen", "Hallochen World"},
299+
{"Replace Hello with Hallöchen", "Hello World", "Hello", "Hallöchen", "Hallöchen World"},
300+
{"Replace ö with ä", "äö", "ö", "ä", "ää"},
296301
}
297302
for _, tt := range tests {
298303
t.Run(tt.name, func(t *testing.T) {

0 commit comments

Comments
 (0)