我想用零替换字符串中的所有数字,理想情况下,连续数字应替换为一个零。
我尝试了两种方法:
使用正则表达式:
1 2 3 4 | var numbersRegExp = regexp.MustCompile("[0-9]+") func normalizeNumbers(str string) string{ return numbersRegExp.ReplaceAllString(str,"0") } |
使用字符串替换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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字符串时仍然非常慢,并且不能很好地替换连续数字。
有更好的方法吗?
最快的解决方案是(始终)即时构建输出。这需要循环一次输入的符文,并使用适当的初始输出"缓冲区"(在这种情况下为
这是实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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]) } |
测试它:
1 2 3 4 5 6 7 8 9 10 | fmt.Printf("%q ", repNums("abc826def47")) //"abc0def0" fmt.Printf("%q ", repNums("1234")) //"0" fmt.Printf("%q ", repNums("asdf")) //"asdf" fmt.Printf("%q ", repNums("")) //"" fmt.Printf("%q ", repNums("a12b34c9d")) //"a0b0c0d" |
在Go Playground上尝试一下。
笔记:
-
我用
len(s) 估计了输出缓冲区(符文数),它不是输入的符文数,而是字节数。这是一个较高的估计,但不需要任何努力。如果愿意,您可以使用utf8.RuneCountInString() 来获取输入string 中的符文的确切数量(但是这样做会解码并循环输入string 的符文,这并不值得)。 -
我用条件
r >= '0' && r <= '9' 测试数字。或者,您可以使用unicode.IsDigit() -
根据输入字符串的性质,如果不包含数字的输入频率很高(因此输出等于输入),则可以通过首先测试输入中是否有数字来提高性能,如果没有,只需返回输入
string (不可变)。
- 谢谢,使用这种方法,性能提高了约50%。 我将等待看看是否还有其他答案。
- 如何在不迭代整个字符串的情况下检测输入中是否有数字?
- @paradite你不能,所以有点开销。 但是,如果这样做却发现其中不包含数字,则可以立即返回输入字符串,而无需执行其他任何操作。