去比较字符串

时间:2018-10-16 07:42:44

标签: string go

给出两个字符串ab,有时我想确定三个语句之一:a < ba == ba > b是正确的。

在像C或C ++这样的语言中,一次调用相应的函数或方法后,我将得到一个整数值v。然后,我可以通过检查v < 0v == 0还是v > 0来确定上述哪种说法是正确的。

但是在Go中,我必须至少进行两次比较(例如,首先测试a < b,然后测试a == b),以找出这三个语句中哪一个是正确的。

我的问题是Go中有办法让我可以做一个比较吗?

事实证明,此功能称为three way comparison

3 个答案:

答案 0 :(得分:4)

即使此比较器功能存在于strings软件包(strings.Compare())中,即使其文档也建议不要使用它:

  

Compare返回一个按字典顺序比较两个字符串的整数。如果a == b,结果将为0;如果a b,结果将为+1。

     

仅包含与包字节对称的比较信息。使用内置的字符串比较运算符==,<,>等,通常更清晰,总是更快。

为什么使用strings.Compare()不切实际?

有几个原因。

首先,在这种Compare()实用/通用的语言中,通常这些语言支持基于具有此签名的函数的排序。

例如,在Java中,您可以将Comparator接口传递给Collections.sort()。因此,在Java中,您不得不/执行这种比较(返回-101)。

在Go中,排序不基于此类比较器功能。在Go语言中,排序是基于单个Less(i, j int) bool函数的,该函数基本上是a[i] < a[j]的比较,只是“少了吗?”。为此,您不需要strings.Compare(),只需要a < b。例如,请参见sort.Slice()

第二个原因:strings.Compare()没有被有意优化 ,因此您不习惯使用它。 strings.Compare()的实现有以下注释:

// NOTE(rsc): This function does NOT call the runtime cmpstring function,
// because we do not want to provide any performance justification for
// using strings.Compare. Basically no one should use strings.Compare.
// As the comment above says, it is here only for symmetry with package bytes.
// If performance is important, the compiler should be changed to recognize
// the pattern so that all code doing three-way comparisons, not just code
// using strings.Compare, can benefit.

这意味着a < b比调用strings.Compare(a, b)更快。

第三,strings.Compare()的返回值是一个单个整数,其中包含以下信息:a小于b还是a等于{{1} }或b是否大于a。如果确实需要使用所有三个分支(而不仅仅是“较少”或“等于”分支),则通常需要对b的返回值进行进一步检查,如以下简单示例所示:

strings.Compare()

现在考虑一下:比较首先在switch strings.Compare("a", "b") { case -1: fmt.Println("less") case 0: fmt.Println("equal") case 1: // or default: fmt.Println("greater") } 内部执行,然后在代码中再次进行比较(比较返回值)。这是多余的,而且性能较低。

上面的代码可以这样写(会更快):

strings.Compare()

关于效率的更多信息

如前所述,switch { case a == b: fmt.Println("equal") case a < b: fmt.Println("less") default: fmt.Println("greater") } 并未针对性能进行优化。但是Go的排序库不需要strings.Compare()-10的结果来对字符串进行排序,只需要1的结果即可,获取结果的效率与获取a < b用其他语言的结果。

还要注意,Compare()首先检查是否相等strings.Compare(),并且只有在它们不相等时才检查a == b。这很重要,因为Go中的a < b值存储string的长度(有关详细信息,请参见reflect.StringHeader),这意味着如果2个字符串的长度不同,则可以立即确定它们的长度不相等。 C和C ++使用string终止的字符串值,这意味着要知道两个字符串是否相等,即使一个字符串是一千个字符而另一个字符串少了一个,也总是需要比较整个字符串。实际上,这并不是完全正确的,因为如果比较字符时检测到不匹配,则比较结束,但是这仍然比比较2个整数慢很多。

另请参阅相关问题:Using the == symbol in golang and using a loop to compare if string a equals string b,which performance is better?

答案 1 :(得分:3)

比较功能呢?

Golang Doc

答案 2 :(得分:1)

Go是由程序员为程序员设计的。如果要使用C strcmp函数,请在Go中编写一个。

例如,

package main

import "fmt"

func strcmp(s1, s2 string) int {
    lens := len(s1)
    if lens > len(s2) {
        lens = len(s2)
    }
    for i := 0; i < lens; i++ {
        if s1[i] != s2[i] {
            return int(s1[i]) - int(s2[i])
        }
    }
    return len(s1) - len(s2)
}

func main() {
    tests := []struct {
        s1, s2 string
        cmp    int
    }{
        {"", "", 0},
        {"a", "a", 0},
        {"a", "b", -1},
        {"b", "a", +1},
        {"a", "aa", -1},
        {"aa", "a", 1},
    }
    for _, t := range tests {
        cmp := strcmp(t.s1, t.s2)
        fmt.Printf("%q %q %d %t\n", t.s1, t.s2, cmp, cmp == t.cmp)
    }
}

游乐场:https://play.golang.org/p/EAzV5_ouDI2

输出:

"" "" 0 true
"a" "a" 0 true
"a" "b" -1 true
"b" "a" 1 true
"a" "aa" -1 true
"aa" "a" 1 true

GNU C库(glibc):strcmp.c