我想替换字符串中特定索引处的字母:aaaaaaa- > aaabaaa.有没有内置的方法来做到这一点?我编写了以下辅助函数来同时使用:
func main() {
input := "aaaaaaa"
output := replaceAtIndex(input, 'b', 3)
}
func replaceAtIndex(input string, replacement byte, index int) string {
return strings.Join([]string{input[:index], string(replacement), input[index+1:]}, "")
}
Run Code Online (Sandbox Code Playgroud)
One*_*One 22
字符串在Go中是不可变的,你必须将其转换为符文然后修改它然后将其转换回字符串.
@ chendesheng的解决方案是半正确的,除了你可以使用rune而不是byte,这样它也可以用于unicode.
func replaceAtIndex(in string, r rune, i int) string {
out := []rune(in)
out[i] = r
return string(out)
}
Run Code Online (Sandbox Code Playgroud)
Sal*_*ali 15
这两个答案(OneOfOne和DenysSéguret)都是正确的.我只想展示它们之间的性能差异(当字符串很大时这是非常明显的).
事实证明,使用str [:index] + string(替换)+ str [index + 1:]会更快.
所以基准:
package main
import (
"testing"
)
func replaceAtIndex1(str string, replacement rune, index int) string {
out := []rune(str)
out[index] = replacement
return string(out)
}
func replaceAtIndex2(str string, replacement rune, index int) string {
return str[:index] + string(replacement) + str[index+1:]
}
func generateString(n int) string{
s := ""
for i := 0; i < n; i++{
s += "a"
}
return s
}
func BenchmarkSmall1(b *testing.B) {
n := 10
str, index, replacement := generateString(n), n / 2, 'B'
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceAtIndex1(str, replacement, index)
}
}
func BenchmarkSmall2(b *testing.B) {
n := 10
str, index, replacement := generateString(n), n / 2, 'B'
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceAtIndex2(str, replacement, index)
}
}
func BenchmarkMedium1(b *testing.B) {
n := 100
str, index, replacement := generateString(n), n / 2, 'B'
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceAtIndex1(str, replacement, index)
}
}
func BenchmarkMedium2(b *testing.B) {
n := 100
str, index, replacement := generateString(n), n / 2, 'B'
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceAtIndex2(str, replacement, index)
}
}
func BenchmarkBig1(b *testing.B) {
n := 10000
str, index, replacement := generateString(n), n / 2, 'B'
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceAtIndex1(str, replacement, index)
}
}
func BenchmarkBig2(b *testing.B) {
n := 10000
str, index, replacement := generateString(n), n / 2, 'B'
b.ResetTimer()
for i := 0; i < b.N; i++ {
replaceAtIndex2(str, replacement, index)
}
}
func main(){}
Run Code Online (Sandbox Code Playgroud)
显示以下结果(感谢Thomasz发现一个copypasting错误):
BenchmarkSmall1-4 10000000 228 ns/op
BenchmarkSmall2-4 10000000 126 ns/op
BenchmarkMedium1-4 500000 2091 ns/op
BenchmarkMedium2-4 10000000 190 ns/op
BenchmarkBig1-4 10000 209232 ns/op
BenchmarkBig2-4 500000 3629 ns/op
Run Code Online (Sandbox Code Playgroud)
您可以使用+运算符连接字符串:
return input[:index] + string(replacement) + input[index+1:]
Run Code Online (Sandbox Code Playgroud)
只是为了好玩:
package main
import (
"fmt"
"reflect"
"syscall"
"unsafe"
)
// We should do this because by default strings in Go are read-only.
func mprotect(ptr uintptr, w bool) {
// Need to avoid "EINVAL addr is not a valid pointer,
// or not a multiple of PAGESIZE."
start := ptr & ^(uintptr(syscall.Getpagesize() - 1))
prot := syscall.PROT_READ
if w {
prot |= syscall.PROT_WRITE
}
_, _, err := syscall.Syscall(
syscall.SYS_MPROTECT,
start, uintptr(syscall.Getpagesize()),
uintptr(prot),
)
if err != 0 {
panic(err.Error())
}
}
// This function is very, very very very unsafe.
// Nowhere and never use it!
func replaceAtIndex(s string, b byte, i int) {
h := *(*reflect.StringHeader)(unsafe.Pointer(&s))
mprotect(h.Data, true)
defer mprotect(h.Data, false)
*(*byte)(unsafe.Pointer(h.Data + uintptr(i))) = b
}
func main() {
h := "Hello, playground"
replaceAtIndex(h, 'x', 0)
fmt.Println(h)
}
Run Code Online (Sandbox Code Playgroud)
永远不要尝试在代码中的某处使用它。它比上面的任何标准解决方案或示例都慢,而且更不安全。=)
(它在操场上不起作用,因为syscall那里没有定义)。
| 归档时间: |
|
| 查看次数: |
13679 次 |
| 最近记录: |