I am performing a replace of characters on a string like this:
result = strings.ReplaceAll(result, ".", "_")
This works as expected, but I want to preserve the last occurence of the .
and not replace it, just leave it alone.
Is there a fancy way doing this?
The most obvious way to handle this would be to combine Replace
and Count
:
func ReplaceAllExceptLast(d string, o string, n string) string {
strings.Replace(d, o, n, strings.Count(d, o) - 1)
}
I don't think this would be the most optimal solution, however. For me, the best option would be to do this:
func ReplaceAllExceptLast(d string, o string, n string) string {
ln := strings.LastIndex(d, o)
if ln == -1 {
return d
}
return strings.ReplaceAll(d[:ln], o, n) + d[ln:]
}
This works by getting the index of the last occurrence of the value you want to replace, and then doing a replace-all on the string up to that point. For example:
println(ReplaceAllExceptLast("a", ".", "_"))
println(ReplaceAllExceptLast("a.b", ".", "_"))
println(ReplaceAllExceptLast("a.b.c", ".", "_"))
println(ReplaceAllExceptLast("a.b.c.d", ".", "_"))
will produce:
a
a.b
a_b.c
a_b_c.d
Split into []string
, then Join
all but last ;)
func ReplaceAllButLast(data, old, new string) string {
split := strings.Split(data, old)
if len(split) < 3 {
return data
}
last := len(split) - 1
return strings.Join(split[:last], new) + old + split[last]
}
https://go.dev/play/p/j8JJP-p_Abk
func main() {
println(ReplaceAllButLast("a", ".", "_"))
println(ReplaceAllButLast("a.b", ".", "_"))
println(ReplaceAllButLast("a.b.c", ".", "_"))
println(ReplaceAllButLast("a.b.c.d", ".", "_"))
}
produced
a
a.b
a_b.c
a_b_c.d
UPDATE
That was a joke, just to be fancy
Best way is to count the number of matches and replace Count()-1
, the second it to ReplaceAll
until last match position and using Join
to be the slowest
func ReplaceAllButLast_Count(data, old, new string) string {
cnt := strings.Count(data, old)
if cnt < 2 {
return data
}
return strings.Replace(data, old, new, cnt-1)
}
func ReplaceAllButLast_Replace(data, old, new string) string {
idx := strings.LastIndex(data, old)
if idx <= 0 {
return data
}
return strings.ReplaceAll(data[:idx], old, new) + data[idx:]
}
func ReplaceAllButLast_Join(data, old, new string) string {
split := strings.Split(data, old)
if len(split) < 3 {
return data
}
last := len(split) - 1
return strings.Join(split[:last], new) + old + split[last]
}
Benchmark using a.b.c.d -> a_b_c.d
goos: windows
goarch: amd64
pkg: example.org
cpu: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
Benchmark_Count-8 16375098 70.05 ns/op 8 B/op 1 allocs/op
Benchmark_Replace-8 11213830 108.5 ns/op 16 B/op 2 allocs/op
Benchmark_Slice-8 5460445 217.6 ns/op 80 B/op 3 allocs/op
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With