How do I compare strings in GoLang?

Go

Go Problem Overview


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)

}

example

Go Solutions


Solution 1 - Go

== 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" {
    // ...
}

Solution 2 - Go

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.

Explanation

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.

Solution 3 - Go

Assuming there are no prepending/succeeding whitespace characters, there are still a few ways to assert string equality. Some of those are:

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)
	}
}

Solution 4 - Go

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2202911View Question on Stackoverflow
Solution 1 - GohelmbertView Answer on Stackoverflow
Solution 2 - GoDaksh M.View Answer on Stackoverflow
Solution 3 - GoDebosmit RayView Answer on Stackoverflow
Solution 4 - GoAbhishek SrivastavaView Answer on Stackoverflow