从字符串中删除空字符

时间:2019-01-21 07:40:41

标签: string go replace removing-whitespace

我想检查字符串是否为空并及时解析该字符串。

请找到以下代码

valueStr = strings.Replace(string(valueStr), " ", "", -1)
valueStr = strings.Replace(string(valueStr), "\t", "", -1)
valueStr = strings.Replace(string(valueStr), "\n", "", -1)
valueStr = strings.Replace(string(valueStr), "\r", "", -1)
var re = regexp.MustCompile(`\s`)
valueStr = re.ReplaceAllString(valueStr, "")

if valueStr != "" {
    fmt.Printf("-------- valueStr %c: \n", valueStr)         // o/p =>  -------- valueStr %!c(string= ):
    fmt.Printf("-------- valueStr %#v: \n", valueStr)        // o/p => -------- valueStr "\x00":
    fmt.Printf("-------- valueStr %x: \n", valueStr)         // o/p =>  -------- valueStr 00:
    fmt.Println("-------- valueStr length: ", len(valueStr)) // o/p => -------- valueStr length:  1

    // considering valueStr is not empty, parse string to time

    time, err := time.Parse(TIME_FORMAT, strings.TrimSpace(valueStr))
    if err != nil {
        fmt.Println("-------- Error converting time: ", err) // o/p => -------- Error converting time:  parsing time " " as "15:04:05": cannot parse " " as "15"
        return
    }
} else {
    // another code
}

如何从字符串中删除该空字符?还是检查字符串是否包含这个空字符?

1 个答案:

答案 0 :(得分:9)

您可以从字符串中删除\x00符文,就像删除其他符文一样:

valueStr = strings.Replace(valueStr, "\x00", "", -1)

示例:

s := "a\x00b"
fmt.Printf("%q\n", s)
s = strings.Replace(s, "\x00", "", -1)
fmt.Printf("%q\n", s)

输出(在Go Playground上尝试):

"a\x00b"
"ab"

使用strings.Replacer

还请注意,您可以使用strings.Replacer用一个操作替换多个替换,它也将更加高效,因为它仅对输入进行一次迭代(并且只有一个{{1} }分配给结果,无论您要替换多少个子字符串。

例如:

string

输出(在Go Playground上尝试):

s := " \t\n\rabc\x00"
fmt.Printf("%q\n", s)

r := strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\x00", "")
s = r.Replace(s)
fmt.Printf("%q\n", s)

还要注意,一次创建一个" \t\n\rabc\x00" "abc" 就足够了,您可以将其存储在(全局)变量中并重用它,甚至可以安全地从多个goroutine中同时使用它。

使用string.Replacer

还请注意,如果您只想替换(删除)单个strings.Map()而不是多符文(或多字节)子字符串,则也可以使用strings.Map(),它可能更有效比rune

首先定义一个函数,该函数指示要替换的strings.Replacer(或如果返回负值则删除):

rune

然后使用它:

func remove(r rune) rune {
    switch r {
    case ' ', '\t', '\n', '\r', 0:
        return -1
    }
    return r
}

输出(在Go Playground上尝试):

s := " \t\n\rabc\x00"
fmt.Printf("%q\n", s)

s = strings.Map(remove, s)
fmt.Printf("%q\n", s)

基准

我们可能认为" \t\n\rabc\x00" "abc" 会更好,因为它只需要处理strings.Map()个数字中的rune,而int32必须处理{{1 }}的值是标头(长度+数据指针)加上一系列字节。

但是我们应该知道strings.Replacer值作为UTF-8字节序列存储在内存中,这意味着string必须从UTF-8字节序列中解码string(并最终将符文编码回UTF-8),而strings.Map()则没有:它可以简单地查找字节序列匹配项而无需解码rune。并且strings.Replacer经过了高度优化,可以利用这种“技巧”。

因此,让我们创建一个基准进行比较:

我们将这些用作基准:

rune

我们在不同的输入字符串上运行基准测试

strings.Replacer

现在让我们看一下基准测试结果:

var r = strings.NewReplacer(" ", "", "\t", "", "\n", "", "\r", "", "\x00", "")

func remove(r rune) rune {
    switch r {
    case ' ', '\t', '\n', '\r', 0:
        return -1
    }
    return r
}

尽管有期望,func BenchmarkReplaces(b *testing.B) { cases := []struct { title string input string }{ { title: "None", input: "abc", }, { title: "Normal", input: " \t\n\rabc\x00", }, { title: "Long", input: "adsfWR \t\rab\nc\x00 \t\n\rabc\x00asdfWER\n\r", }, } for _, c := range cases { b.Run("Replacer-"+c.title, func(b *testing.B) { for i := 0; i < b.N; i++ { r.Replace(c.input) } }) b.Run("Map-"+c.title, func(b *testing.B) { for i := 0; i < b.N; i++ { strings.Map(remove, c.input) } }) } } 的表现还是不错的,与BenchmarkReplaces/Replacer-None-4 100000000 12.3 ns/op 0 B/op 0 allocs/op BenchmarkReplaces/Map-None-4 100000000 16.1 ns/op 0 B/op 0 allocs/op BenchmarkReplaces/Replacer-Normal-4 20000000 92.7 ns/op 6 B/op 2 allocs/op BenchmarkReplaces/Map-Normal-4 20000000 92.4 ns/op 16 B/op 2 allocs/op BenchmarkReplaces/Replacer-Long-4 5000000 234 ns/op 64 B/op 2 allocs/op BenchmarkReplaces/Map-Long-4 5000000 235 ns/op 80 B/op 2 allocs/op 一样好,因为它不必解码和编码符文。