douping7975 2015-07-13 08:39
浏览 183
已采纳

在Golang中将数字替换为零

I want to replace all the numbers in a string with zeros, and ideally consecutive numbers should be replaced with one zero.
abc826def47 should become abc0def0

I have tried two methods:
Using regex:

var numbersRegExp = regexp.MustCompile("[0-9]+")
func normalizeNumbers(str string) string{
    return numbersRegExp.ReplaceAllString(str, "0")
}

Using strings.Replace

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
}

The second method without using regex seems to be a little faster, but still very slow when working with about 100k strings, and it does not replace consecutive numbers well.
Is there a better way of doing this?

  • 写回答

1条回答 默认 最新

  • douju9272 2015-07-13 08:48
    关注

    The fastest solution is (always) building output on-the-fly. This requires to loop over the runes of the input once, and with a proper initial output "buffer" (which is []rune in this case) you can also avoid reallocation.

    Here is the implementation:

    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])
    }
    

    Testing it:

    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"
    

    Try it on the Go Playground.

    Notes:

    • I estimated output buffer (number of runes) with len(s) which is not the rune count of the input but the bytes count. This is an upper estimation but requires no effort. You may use utf8.RuneCountInString() to get the exact number of runes in input string if you wish so (but this decodes and loops over the runes of the input string, not really worth it).
    • I test digits with the condition r >= '0' && r <= '9'. Alternatively you may use unicode.IsDigit()
    • Depending on the nature of your input strings, if the frequency of inputs where no digit is contained is high (and therefore output is equal to input), you may improve performance by first testing if there is a digit in input, and if not, simply return the input string (which is immutable).
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 delta降尺度计算的一些细节,有偿
  • ¥15 Arduino红外遥控代码有问题
  • ¥15 数值计算离散正交多项式
  • ¥30 数值计算均差系数编程
  • ¥15 redis-full-check比较 两个集群的数据出错
  • ¥15 Matlab编程问题
  • ¥15 训练的多模态特征融合模型准确度很低怎么办
  • ¥15 kylin启动报错log4j类冲突
  • ¥15 超声波模块测距控制点灯,灯的闪烁很不稳定,经过调试发现测的距离偏大
  • ¥15 import arcpy出现importing _arcgisscripting 找不到相关程序