繁体   English   中英

如何从 Golang 中的字符串中删除多余的空格/空格?

[英]How to remove redundant spaces/whitespace from a string in Golang?

我想知道如何删除:

  • 所有前导/尾随空格或换行符、null 个字符等。
  • 字符串中的任何冗余空格(例如“hello[space][space]world”将被转换为“hello[space]world”)

这是否可能使用单个正则表达式,unicode 支持国际空格字符等?

您可以使用strings包作为strings.Fields为您完成大部分工作:

package main

import (
    "fmt"
    "strings"
)

func standardizeSpaces(s string) string {
    return strings.Join(strings.Fields(s), " ")
}

func main() {
    tests := []string{" Hello,   World  ! ", "Hello,\tWorld ! ", " \t\n\t Hello,\tWorld\n!\n\t"}
    for _, test := range tests {
        fmt.Println(standardizeSpaces(test))
    }
}
// "Hello, World !"
// "Hello, World !"
// "Hello, World !"

似乎您可能想要同时使用\\s速记字符类和\\p{Zs} Unicode 属性来匹配 Unicode 空格。 但是,这两个步骤都不能用 1 个正则表达式替换完成,因为您需要两个不同的替换,并且ReplaceAllStringFunc只允许整个匹配字符串作为参数(我不知道如何检查匹配的组)。

因此,我建议使用两个正则表达式:

  • ^[\\s\\p{Zs}]+|[\\s\\p{Zs}]+$ - 匹配所有前导/尾随空格
  • [\\s\\p{Zs}]{2,} - 匹配字符串中的 2 个或更多空白符号

示例代码:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    input := "   Text   More here     "
    re_leadclose_whtsp := regexp.MustCompile(`^[\s\p{Zs}]+|[\s\p{Zs}]+$`)
    re_inside_whtsp := regexp.MustCompile(`[\s\p{Zs}]{2,}`)
    final := re_leadclose_whtsp.ReplaceAllString(input, "")
    final = re_inside_whtsp.ReplaceAllString(final, " ")
    fmt.Println(final)
}

strings.Fields() 在任意数量的空白处拆分,因此:

strings.Join(strings.Fields(strings.TrimSpace(s)), " ")

避免使用浪费时间的正则表达式或外部库
我选择使用普通的 golang 而不是 regexp,因为在每种语言中都有不是 ASCII 的特殊字符。

去高朗!

func RemoveDoubleWhiteSpace(str string) string {
    var b strings.Builder
    b.Grow(len(str))
    for i := range str {
        if !(str[i] == 32 && (i+1 < len(str) && str[i+1] == 32)) {
            b.WriteRune(rune(str[i]))
        }
    }
    return b.String()
}

以及相关测试

func TestRemoveDoubleWhiteSpace(t *testing.T) {
    data := []string{`  test`, `test  `, `te  st`}
    for _, item := range data {
        str := RemoveDoubleWhiteSpace(item)
        t.Log("Data ->|"+item+"|Found: |"+str+"| Len: ", len(str))
        if len(str) != 5 {
            t.Fail()
        }
    }
}

使用单个 regexp 使用 regexp.MustCompile() 获取所有空间并将它们替换为单个空格,最后修剪前导空格。

    package main

    import (
        "fmt"
        "regexp"
        "strings"
    )
    
    func main() {
        input := "    Text   More here        "
        re := regexp.MustCompile(`\s+`)
        out := re.ReplaceAllString(input, " ")
        out = strings.TrimSpace(out)
        fmt.Println(out)
    } 

或者,使用“_”代替空格。

package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {
    input := "___Text___More_here______"
    re := regexp.MustCompile(`_+`)
    out := re.ReplaceAllString(input, "_")
    out = strings.Trim(out, "_")
    fmt.Println(out)
}
// Ref: https://stackoverflow.com/a/42251527/18152508
func StrFields(input string) string {
    return strings.Join(strings.Fields(input), " ")
}

// Ref: https://stackoverflow.com/a/37293398/18152508
func RegexReplace(input string) string {
    re_leadclose_whtsp := regexp.MustCompile(`^[\s\p{Zs}]+|[\s\p{Zs}]+$`)
    re_inside_whtsp := regexp.MustCompile(`[\s\p{Zs}]{2,}`)

    return re_inside_whtsp.ReplaceAllString(
        re_leadclose_whtsp.ReplaceAllString(input, ""),
        " ",
    )
}

// Ref: https://stackoverflow.com/a/67152714/18152508
func SingleRegexp(input string) string {
    re := regexp.MustCompile(`\s+`)

    return strings.TrimSpace(re.ReplaceAllString(input, " "))
}

对上述 3 个函数进行基准测试,使用strings.Fields function 的 @ifross 方法比接受的答案和使用正则表达式要快得多。

因此,我更喜欢strings.Fieldsstrings.Join的组合,只是为了减少字符串中冗余和重复的空格。

$ go test -bench . -count 30 ./... > bench.txt && benchstat bench.txt
name            time/op
StrFields-4      204ns ± 1%
RegexReplace-4  8.35µs ± 2%
SingleRegexp-4  2.49µs ± 1%
var testData = []string{
    " Hello,   World  ! ",
    // "Hello,\tWorld ! ",
    // " \t\n\t Hello,\tWorld\n!\n\t",
}

var testFunc = []struct {
    name string
    exec func(string) string
}{
    {name: "StrFields", exec: StrFields},
    {name: "RegexReplace", exec: RegexReplace},
    {name: "SingleRegexp", exec: SingleRegexp},
}

func Test(t *testing.T) {
    for _, targetFunc := range testFunc {
        t.Run(targetFunc.name, func(t *testing.T) {
            for index, input := range testData {
                expect := "Hello, World !"
                actual := targetFunc.exec(input)

                if expect != actual {
                    t.Errorf("#%d: expect %q, actual %q", index+1, expect, actual)
                }
            }
        })
    }
}

func BenchmarkStrFields(b *testing.B) {
    const data = " Hello,   World  ! "

    for i := 0; i < b.N; i++ {
        _ = StrFields(data)
    }
}

func BenchmarkRegexReplace(b *testing.B) {
    const data = " Hello,   World  ! "

    for i := 0; i < b.N; i++ {
        _ = RegexReplace(data)
    }
}

func BenchmarkSingleRegexp(b *testing.B) {
    const data = " Hello,   World  ! "

    for i := 0; i < b.N; i++ {
        _ = SingleRegexp(data)
    }
}

为此使用正则表达式。

func main() {
    data := []byte("   Hello,   World !   ")
    re := regexp.MustCompile("  +")
    replaced := re.ReplaceAll(bytes.TrimSpace(data), []byte(" "))
    fmt.Println(string(replaced))
    // Hello, World !
}

为了还修剪换行符和空字符,您可以使用bytes.Trim(src []byte, cutset string) bytes.TrimSpace bytes.Trim(src []byte, cutset string)函数而不是bytes.TrimSpace

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM