我想用零替换字符串中的所有数字,理想情况下连续的数字应该用一个零替换。
abc826def47
应该变成 abc0def0
我试过两种方法:
使用正则表达式:
var numbersRegExp = regexp.MustCompile("[0-9]+")
func normalizeNumbers(str string) string{
return numbersRegExp.ReplaceAllString(str, "0")
}
使用字符串替换
import s "strings"
func normalizeNumbers(str string) string{
str = s.Replace(str, "1", "0", -1)
str = s.Replace(str, "2", "0", -1)
str = s.Replace(str, "3", "0", -1)
str = s.Replace(str, "4", "0", -1)
str = s.Replace(str, "5", "0", -1)
str = s.Replace(str, "6", "0", -1)
str = s.Replace(str, "7", "0", -1)
str = s.Replace(str, "8", "0", -1)
str = s.Replace(str, "9", "0", -1)
str = s.Replace(str, "00", "0", -1)
return str
}
不使用正则表达式的第二种方法似乎快一点,但在处理大约 100k 个字符串时仍然很慢,而且它不能很好地替换连续数字。
有更好的方法吗?
最佳答案
最快的解决方案是(始终)即时构建输出。这需要循环一次输入的 rune ,并使用适当的初始输出“缓冲区”(在本例中为 []rune
),您还可以避免重新分配。
实现如下:
func repNums(s string) string {
out := make([]rune, len(s)) // len(s) is bytes not runes, this is just estimation
i, added := 0, false
for _, r := range s {
if r >= '0' && r <= '9' {
if added {
continue
}
added, out[i] = true, '0'
} else {
added, out[i] = false, r
}
i++
}
return string(out[:i])
}
测试它:
fmt.Printf("%q\n", repNums("abc826def47")) // "abc0def0"
fmt.Printf("%q\n", repNums("1234")) // "0"
fmt.Printf("%q\n", repNums("asdf")) // "asdf"
fmt.Printf("%q\n", repNums("")) // ""
fmt.Printf("%q\n", repNums("a12b34c9d")) // "a0b0c0d"
在 Go Playground 上试试.
注意事项:
- 我用
len(s)
估计输出缓冲区( rune 数)这不是输入的 rune 计数,而是字节数。这是一个较高的估计,但不需要任何努力。您可以使用utf8.RuneCountInString()
获取输入中 rune 的确切数量string
如果你愿意的话(但这会解码并循环输入string
的 rune ,这真的不值得)。 - 我用条件
r >= '0' && r <= '9'
测试数字.或者你可以使用unicode.IsDigit()
- 根据输入字符串的性质,如果不包含数字的输入频率很高(因此输出等于输入),您可以通过首先测试输入中是否有数字来提高性能,并且如果不是,只需返回输入
string
(这是不可变的)。
关于regex - 在golang中用零替换数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31378833/