【问题标题】:How do I compare strings in GoLang?如何比较 GoLang 中的字符串?
【发布时间】:2016-03-26 19:41:43
【问题描述】:

当涉及到 Go 字符串比较时,我无法产生“真实”的结果。我写了以下内容来解释这个问题并附上了输出的截图

// string comparison in Go
package main
import "fmt"
import "bufio"
import "os"

func main() {
    var isLetterA bool 

    fmt.Println("Enter the letter a")
    reader := bufio.NewReader(os.Stdin)
    input, _ := reader.ReadString('\n')

    if(input == "a") {
        isLetterA = true
    } else {
        isLetterA = false 
    }

    fmt.Println("You entered",input)
    fmt.Println("Is it the letter a?",isLetterA)

}

【问题讨论】:

  • windows 用户检查我的答案 :)

标签: go


【解决方案1】:

== 是在 Go 中比较字符串的正确运算符。但是,您使用 reader.ReadString 从 STDIN 读取的字符串不包含 "a",而是包含 "a\n"(如果仔细观察,您会在示例输出中看到额外的换行符)。

您可以使用strings.TrimRight 函数从输入中删除尾随空格:

if strings.TrimRight(input, "\n") == "a" {
    // ...
}

【讨论】:

    【解决方案2】:

    对于平台无关用户或 Windows 用户,您可以做的是:

    导入运行时:

    import (
        "runtime"
        "strings"
    )
    

    然后像这样修剪字符串:

    if runtime.GOOS == "windows" {
      input = strings.TrimRight(input, "\r\n")
    } else {
      input = strings.TrimRight(input, "\n")
    }
    

    现在你可以这样比较:

    if strings.Compare(input, "a") == 0 {
      //....yourCode
    }
    

    当您在多个平台上使用 STDIN 时,这是一种更好的方法。

    说明

    发生这种情况是因为在 windows 上的行以 "\r\n" 结尾,这称为 CRLF,但在 UNIX 上,行以 "\n" 结尾,这就是所谓的 LF,这就是我们在基于 unix 的操作系统上修剪 "\n" 的原因,同时我们修剪"\r\n" 在 Windows 上。

    【讨论】:

    • 没有必要区分。第二个参数是一个cutset,而不是后缀,cutset 中的任何字符都将被修剪,以任何顺序/组合。修剪“\r\n”就足够了。
    【解决方案3】:

    假设没有前置/后续空白字符,仍然有几种方法可以断言字符串相等。其中一些是:

    以下是一些基本的基准测试结果(在这些测试中,strings.EqualFold(.., ..) 似乎是性能最高的选择):

    goos: darwin
    goarch: amd64
    BenchmarkStringOps/both_strings_equal::equality_op-4               10000        182944 ns/op
    BenchmarkStringOps/both_strings_equal::strings_equal_fold-4        10000        114371 ns/op
    BenchmarkStringOps/both_strings_equal::fold_caser-4                10000       2599013 ns/op
    BenchmarkStringOps/both_strings_equal::lower_caser-4               10000       3592486 ns/op
    
    BenchmarkStringOps/one_string_in_caps::equality_op-4               10000        417780 ns/op
    BenchmarkStringOps/one_string_in_caps::strings_equal_fold-4        10000        153509 ns/op
    BenchmarkStringOps/one_string_in_caps::fold_caser-4                10000       3039782 ns/op
    BenchmarkStringOps/one_string_in_caps::lower_caser-4               10000       3861189 ns/op
    
    BenchmarkStringOps/weird_casing_situation::equality_op-4           10000        619104 ns/op
    BenchmarkStringOps/weird_casing_situation::strings_equal_fold-4    10000        148489 ns/op
    BenchmarkStringOps/weird_casing_situation::fold_caser-4            10000       3603943 ns/op
    BenchmarkStringOps/weird_casing_situation::lower_caser-4           10000       3637832 ns/op
    

    由于有很多选项,所以这里是生成基准的代码。

    package main
    
    import (
        "fmt"
        "strings"
        "testing"
    
        "golang.org/x/text/cases"
        "golang.org/x/text/language"
    )
    
    func BenchmarkStringOps(b *testing.B) {
        foldCaser := cases.Fold()
        lowerCaser := cases.Lower(language.English)
    
        tests := []struct{
            description string
            first, second string
        }{
            {
                description: "both strings equal",
                first: "aaaa",
                second: "aaaa",
            },
            {
                description: "one string in caps",
                first: "aaaa",
                second: "AAAA",
            },
            {
                description: "weird casing situation",
                first: "aAaA",
                second: "AaAa",
            },
        }
    
        for _, tt := range tests {
            b.Run(fmt.Sprintf("%s::equality op", tt.description), func(b *testing.B) {
                for i := 0; i < b.N; i++ {
                    benchmarkStringEqualsOperation(tt.first, tt.second, b)
                }
            })
    
            b.Run(fmt.Sprintf("%s::strings equal fold", tt.description), func(b *testing.B) {
                for i := 0; i < b.N; i++ {
                    benchmarkStringsEqualFold(tt.first, tt.second, b)
                }
            })
    
            b.Run(fmt.Sprintf("%s::fold caser", tt.description), func(b *testing.B) {
                for i := 0; i < b.N; i++ {
                    benchmarkStringsFoldCaser(tt.first, tt.second, foldCaser, b)
                }
            })
    
            b.Run(fmt.Sprintf("%s::lower caser", tt.description), func(b *testing.B) {
                for i := 0; i < b.N; i++ {
                    benchmarkStringsLowerCaser(tt.first, tt.second, lowerCaser, b)
                }
            })
        }
    }
    
    func benchmarkStringEqualsOperation(first, second string, b *testing.B) {
        for n := 0; n < b.N; n++ {
            _ = strings.ToLower(first) == strings.ToLower(second)
        }
    }
    
    func benchmarkStringsEqualFold(first, second string, b *testing.B) {
        for n := 0; n < b.N; n++ {
            _ = strings.EqualFold(first, second)
        }
    }
    
    func benchmarkStringsFoldCaser(first, second string, caser cases.Caser, b *testing.B) {
        for n := 0; n < b.N; n++ {
            _ = caser.String(first) == caser.String(second)
        }
    }
    
    func benchmarkStringsLowerCaser(first, second string, caser cases.Caser, b *testing.B) {
        for n := 0; n < b.N; n++ {
            _ = caser.String(first) == caser.String(second)
        }
    }
    

    【讨论】:

      【解决方案4】:

      可以使用== 运算符比较 Golang 中字符串中的内容。如果结果不符合预期,可能会有一些隐藏字符,如\n\r、空格等。因此,作为一般经验法则,请尝试使用 golang 中 strings 包提供的函数删除这些字符。

      例如,可以使用strings.TrimSpace 函数删除空格。您还可以定义一个自定义函数来删除您需要的任何字符。 strings.TrimFunc 功能可以给你更多的力量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-26
        • 2020-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多