我想用零替换字符串中的所有数字,理想情况下,连续数字应替换为一个零。
abc826def47应该成为abc0def0

我尝试了两种方法:
使用正则表达式:

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字符串时仍然非常慢,并且不能很好地替换连续数字。
有更好的方法吗?


最快的解决方案是(始终)即时构建输出。这需要循环一次输入的符文,并使用适当的初始输出"缓冲区"(在这种情况下为[]rune),还可以避免重新分配。

这是实现:

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你不能,所以有点开销。 但是,如果这样做却发现其中不包含数字,则可以立即返回输入字符串,而无需执行其他任何操作。