Como posso comparar strings em GoLang?

88

Não sou capaz de produzir um resultado 'verdadeiro' quando se trata de comparação de strings de Go. Escrevi o seguinte para explicar o problema e anexei uma captura de tela da saída

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

}

exemplo

user2202911
fonte
usuários do Windows verifiquem minha resposta :)
Daksh Miglani

Respostas:

127

==é o operador correto para comparar strings em Go. No entanto, as cadeias de caracteres que você lê de STDIN com reader.ReadStringnão contêm "a", mas "a\n"(se você olhar com atenção, verá a quebra de linha extra em sua saída de exemplo).

Você pode usar a strings.TrimRightfunção para remover espaços em branco à direita de sua entrada:

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

Para os usuários independentes de plataforma ou usuários do Windows, o que você pode fazer é:

tempo de execução de importação:

import (
    "runtime"
    "strings"
)

e, em seguida, apare a string assim:

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

agora você pode compará-lo assim:

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

Esta é uma abordagem melhor quando você usa STDIN em várias plataformas.

Explicação

Isso acontece porque nas linhas do Windows terminam com o "\r\n"que é conhecido como CRLF, mas nas linhas do UNIX terminam com o "\n"que é conhecido como LF e é por isso que aparamos "\n"nos sistemas operacionais baseados em Unix enquanto aparamos "\r\n"nas janelas.

Daksh Miglani
fonte
4
Não há necessidade de diferenciar. O segundo argumento é um cutset, não um sufixo, e quaisquer caracteres no cutset serão aparados, em qualquer ordem / combinação. Cortar "\ r \ n" será suficiente em ambos.
Jason Carlson
1

Supondo que não haja caracteres de espaço em branco precedentes / posteriores, ainda há algumas maneiras de afirmar a igualdade da string. Alguns deles são:

Aqui estão alguns resultados básicos de benchmark (nestes testes, strings.EqualFold(.., ..)parece ser a escolha de melhor desempenho):

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

Como existem algumas opções, aqui está o código para gerar 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)
    }
}
Debosmit Ray
fonte
0

O conteúdo dentro das strings no Golang pode ser comparado usando o ==operador. Se os resultados não são os esperados, pode haver alguns personagens escondidos, como \n, \r, espaços, etc. Então, como uma regra geral, tente remover aqueles que utilizam funções fornecidas pelo stringspacote no golang.

Por exemplo, os espaços podem ser removidos usando a strings.TrimSpacefunção. Você também pode definir uma função personalizada para remover qualquer caractere necessário. strings.TrimFuncfunção pode lhe dar mais potência.

Abhishek Srivastava
fonte