Comment comparer des chaînes dans GoLang?

88

Je suis incapable de produire un résultat «vrai» en ce qui concerne la comparaison de chaînes Go. J'ai écrit ce qui suit pour expliquer le problème et j'ai joint une capture d'écran de la sortie

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

}

exemple

user2202911
la source
les utilisateurs de Windows vérifient ma réponse :)
Daksh Miglani

Réponses:

127

==est l'opérateur correct pour comparer des chaînes dans Go. Cependant, les chaînes que vous lisez à partir de STDIN reader.ReadStringne contiennent pas "a", mais "a\n"(si vous regardez de près, vous verrez le saut de ligne supplémentaire dans votre sortie d'exemple).

Vous pouvez utiliser la strings.TrimRightfonction pour supprimer les espaces de fin de votre entrée:

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

Pour les utilisateurs indépendants de la plate-forme ou les utilisateurs Windows, vous pouvez:

import runtime:

import (
    "runtime"
    "strings"
)

puis coupez la chaîne comme ceci:

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

maintenant vous pouvez le comparer comme ça:

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

C'est une meilleure approche lorsque vous utilisez STDIN sur plusieurs plates-formes.

Explication

Cela se produit parce que sur Windows, les lignes se terminent par "\r\n"ce qui est connu sous le nom de CRLF, mais sur UNIX, les lignes se terminent par "\n"ce qui est connu sous le nom de LF et c'est pourquoi nous "\n"ajustons les systèmes d'exploitation basés sur unix pendant que nous ajustons "\r\n"les fenêtres.

Daksh Miglani
la source
4
Il n'y a pas besoin de se différencier. Le deuxième argument est un cutset, pas un suffixe, et tous les caractères du cutset seront coupés, dans n'importe quel ordre / combinaison. Le découpage "\ r \ n" suffira dans les deux cas.
Jason Carlson
1

En supposant qu'il n'y ait pas de caractères d'espacement précédant / suivant, il existe encore quelques façons d'affirmer l'égalité des chaînes. Certains d'entre eux sont:

Voici quelques résultats de référence de base (dans ces tests, strings.EqualFold(.., ..)semble être le choix le plus performant):

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

Puisqu'il y a pas mal d'options, voici donc le code pour générer des 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
la source
0

Le contenu à l'intérieur des chaînes de Golang peut être comparé à l'aide de l' ==opérateur. Si les résultats ne sont pas comme prévu il peut y avoir des personnages cachés comme \n, \respaces, etc. Donc , en règle générale, essayez de supprimer ceux qui utilisent les fonctions fournies par stringspaquet dans golang.

Pour l'instance, les espaces peuvent être supprimés à l'aide de la strings.TrimSpacefonction. Vous pouvez également définir une fonction personnalisée pour supprimer tout caractère dont vous avez besoin. strings.TrimFuncLa fonction peut vous donner plus de puissance.

Abhishek Srivastava
la source