Skip to content

Commit a8d18d2

Browse files
committed
Replace and ReplaceRune
1 parent 7d7d8d8 commit a8d18d2

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
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+
### Added
10+
- Added the following methods: `ReplaceRune`, `Replace`
11+
912
### Changed
1013
- Renamed `AsRune` to `AsRuneSlice` and included some more documentation to highlight that this is a shared memory block.
1114

stringbuilder.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ func (s *StringBuilder) Remove(start int, length int) error {
7979
return nil
8080
}
8181

82-
s.data = append(s.data[:start], s.data[endIndex])
82+
x := start + length
83+
s.data = append(s.data[:start], s.data[x:]...)
8384
s.position -= length
8485

8586
return nil
@@ -137,6 +138,47 @@ func (s *StringBuilder) FindAll(text string) []int {
137138
return findAll(s.AsRuneSlice(), text)
138139
}
139140

141+
// Replaces all occurrences of oldValue with newValue
142+
func (s *StringBuilder) ReplaceRune(oldValue rune, newValue rune) {
143+
occurrences := s.FindAll(string(oldValue))
144+
145+
for _, v := range occurrences {
146+
s.data[v] = newValue
147+
}
148+
}
149+
150+
// Replaces all occurrences of oldValue with newValue
151+
func (s *StringBuilder) Replace(oldValue string, newValue string) {
152+
if oldValue == newValue {
153+
return
154+
}
155+
156+
occurrences := s.FindAll(oldValue)
157+
158+
delta := len(newValue) - len(oldValue)
159+
160+
for i := 0; i < len(occurrences); i++ {
161+
index := occurrences[i] + delta*i
162+
163+
// newValue is smaller than old value
164+
// We can insert the slice and remove the overhead
165+
if delta < 0 {
166+
copy(s.data[index:], []rune(newValue))
167+
s.Remove(index+len(newValue), -delta)
168+
} else if delta == 0 {
169+
// Same length -> We can just replace the memory slice
170+
copy(s.data[index:], []rune(newValue))
171+
} else {
172+
// newValue is larger than the old value
173+
// First add until the old memory region
174+
// 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+
}
179+
}
180+
}
181+
140182
func (s *StringBuilder) grow(lenToAdd int) {
141183
// Grow times 2 until lenToAdd fits
142184
newLen := cap(s.data)

stringbuilder_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,19 @@ func TestRemoveWhenLengthZero(t *testing.T) {
124124
}
125125
}
126126

127+
func TestRemoveInTheMiddle(t *testing.T) {
128+
const expected string = "Hlo World"
129+
sb := NewStringBuilderFromString("Hello World")
130+
131+
if err := sb.Remove(1, 2); err != nil {
132+
t.Errorf("Remove threw an error: %v", err)
133+
}
134+
135+
if result := sb.ToString(); result != expected {
136+
t.Errorf("Actual %q, Expected: %q", result, expected)
137+
}
138+
}
139+
127140
func TestInsertAtIndex(t *testing.T) {
128141
const expected string = "Hello my dear and beautiful World"
129142
sb := NewStringBuilderFromString("Hello World")
@@ -259,6 +272,41 @@ func TestFindAll(t *testing.T) {
259272
}
260273
}
261274

275+
func TestReplaceRune(t *testing.T) {
276+
s := NewStringBuilderFromString("Hello")
277+
278+
s.ReplaceRune('l', 'm')
279+
280+
if got := s.ToString(); got != "Hemmo" {
281+
t.Errorf("StringBuilder.ReplaceRune() = %v, want %v", got, "Hemmo")
282+
}
283+
}
284+
285+
func TestReplace(t *testing.T) {
286+
tests := []struct {
287+
name string
288+
input string
289+
oldValue string
290+
newvalue string
291+
want string
292+
}{
293+
{"Replace Hello with Hallo", "Hello World", "Hello", "Hallo", "Hallo World"},
294+
{"Replace Hello with Ha", "Hello World", "Hello", "Ha", "Ha World"},
295+
{"Replace Hello with Hallöchen", "Hello World", "Hello", "Hallochen", "Hallochen World"},
296+
}
297+
for _, tt := range tests {
298+
t.Run(tt.name, func(t *testing.T) {
299+
s := NewStringBuilderFromString(tt.input)
300+
301+
s.Replace(tt.oldValue, tt.newvalue)
302+
303+
if got := s.ToString(); got != tt.want {
304+
t.Errorf("StringBuilder.FindLast() = %v, want %v", got, tt.want)
305+
}
306+
})
307+
}
308+
}
309+
262310
func slicesEqual(a []int, b []int) bool {
263311
if len(a) != len(b) {
264312
return false

0 commit comments

Comments
 (0)