Reputation: 3014
I am unable to produce a 'true' result when it comes to Go string comparison. I wrote the following to explain the issue and attached a screenshot of the output
// 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)
}
Upvotes: 129
Views: 237768
Reputation: 5413
Assuming there are no prepending/succeeding whitespace characters, there are still a few ways to assert string equality. Some of those are:
strings.ToLower(..)
then ==
strings.EqualFold(.., ..)
cases#Lower
paired with ==
cases#Fold
paired with ==
Here are some basic benchmark results (in these tests, strings.EqualFold(.., ..)
seems like the most performant choice):
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
Since there are quite a few options, so here's the code to generate benchmarks.
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)
}
}
Upvotes: 6
Reputation: 561
The content inside strings in Golang can be compared using ==
operator. If the results are not as expected there may be some hidden characters like \n
, \r
, spaces, etc. So as a general rule of thumb, try removing those using functions provided by strings
package in golang.
For Instance, spaces can be removed using strings.TrimSpace
function. You can also define a custom function to remove any character you need. strings.TrimFunc
function can give you more power.
Upvotes: 2
Reputation: 4809
For the Platform Independent Users or Windows users, what you can do is:
import runtime:
import (
"runtime"
"strings"
)
and then trim the string like this:
if runtime.GOOS == "windows" {
input = strings.TrimRight(input, "\r\n")
} else {
input = strings.TrimRight(input, "\n")
}
now you can compare it like that:
if strings.Compare(input, "a") == 0 {
//....yourCode
}
This is a better approach when you're making use of STDIN on multiple platforms.
This happens because on windows lines end with "\r\n"
which is known as CRLF, but on UNIX lines end with "\n"
which is known as LF and that's why we trim "\n"
on unix based operating systems while we trim "\r\n"
on windows.
Upvotes: 14
Reputation: 38024
==
is the correct operator to compare strings in Go. However, the strings that you read from STDIN with reader.ReadString
do not contain "a"
, but "a\n"
(if you look closely, you'll see the extra line break in your example output).
You can use the strings.TrimRight
function to remove trailing whitespaces from your input:
if strings.TrimRight(input, "\n") == "a" {
// ...
}
Upvotes: 168