Convertir une chaîne en type entier dans Go?


236

J'essaie de convertir une chaîne renvoyée par flag.Arg(n)un int. Quelle est la façon idiomatique de le faire dans Go?

Réponses:


298

Par exemple,

package main

import (
    "flag"
    "fmt"
    "os"
    "strconv"
)

func main() {
    flag.Parse()
    s := flag.Arg(0)
    // string to int
    i, err := strconv.Atoi(s)
    if err != nil {
        // handle error
        fmt.Println(err)
        os.Exit(2)
    }
    fmt.Println(s, i)
}

14
func main() { ... }ne prend aucun argument et ne renvoie aucune valeur. Utilisez la fonction de ospackage Exitpar exempleos.Exit(2).
peterSO

2
Sinon, faites juste un Eg fatalpanic(err)
Peter Bengtsson

70

Conversion de chaînes simples

La façon la plus simple est d'utiliser la strconv.Atoi()fonction.

Notez qu'il existe de nombreuses autres façons. Par exemple fmt.Sscan()et strconv.ParseInt()qui offrent une plus grande flexibilité car vous pouvez spécifier la base et la taille des bits par exemple. Aussi, comme indiqué dans la documentation de strconv.Atoi():

Atoi est équivalent à ParseInt (s, 10, 0), converti en type int.

Voici un exemple utilisant les fonctions mentionnées (essayez-le sur le Go Playground ):

flag.Parse()
s := flag.Arg(0)

if i, err := strconv.Atoi(s); err == nil {
    fmt.Printf("i=%d, type: %T\n", i, i)
}

if i, err := strconv.ParseInt(s, 10, 64); err == nil {
    fmt.Printf("i=%d, type: %T\n", i, i)
}

var i int
if _, err := fmt.Sscan(s, &i); err == nil {
    fmt.Printf("i=%d, type: %T\n", i, i)
}

Sortie (si appelée avec argument "123"):

i=123, type: int
i=123, type: int64
i=123, type: int

Analyse de chaînes personnalisées

Il y a aussi un fmt.Sscanf() qui donne encore plus de flexibilité car avec la chaîne de format, vous pouvez spécifier le format numérique (comme la largeur, la base, etc.) ainsi que des caractères supplémentaires supplémentaires dans l'entrée string.

C'est idéal pour analyser des chaînes personnalisées contenant un nombre. Par exemple, si votre entrée est fournie sous la forme d' "id:00123"un préfixe "id:"et que le nombre est fixé à 5 chiffres, complété par des zéros si plus court, c'est très facilement analysable comme ceci:

s := "id:00123"

var i int
if _, err := fmt.Sscanf(s, "id:%5d", &i); err == nil {
    fmt.Println(i) // Outputs 123
}

Quel est le deuxième argument à ParseIntpréciser?
kaushik94

1
@ kaushik94 Cliquez sur le strconv.ParseInt()lien et vous verrez immédiatement: ParseInt(s string, base int, bitSize int). C'est donc la base: "ParseInt interprète une chaîne s dans la base donnée (2 à 36)"
icza

Notez que l'argument bitSize à strconv.ParseInt () ne convertira pas la chaîne en votre type de choix mais est uniquement là pour limiter le résultat à un «témoin» spécifique. Voir aussi: stackoverflow.com/questions/55925894/…
viv

@viv Oui, c'est exact. Si une valeur de type intest requise et strconv.ParseInt()utilisée, une conversion de type manuelle est nécessaire (de int64à int).
icza

16

Voici trois façons d'analyser des chaînes en nombres entiers, de l'exécution la plus rapide à la plus lente:

  1. strconv.ParseInt(...) le plus rapide
  2. strconv.Atoi(...) toujours très rapide
  3. fmt.Sscanf(...) pas terriblement rapide mais plus flexible

Voici un benchmark qui montre l'utilisation et un exemple de synchronisation pour chaque fonction:

package main

import "fmt"
import "strconv"
import "testing"

var num = 123456
var numstr = "123456"

func BenchmarkStrconvParseInt(b *testing.B) {
  num64 := int64(num)
  for i := 0; i < b.N; i++ {
    x, err := strconv.ParseInt(numstr, 10, 64)
    if x != num64 || err != nil {
      b.Error(err)
    }
  }
}

func BenchmarkAtoi(b *testing.B) {
  for i := 0; i < b.N; i++ {
    x, err := strconv.Atoi(numstr)
    if x != num || err != nil {
      b.Error(err)
    }
  }
}

func BenchmarkFmtSscan(b *testing.B) {
  for i := 0; i < b.N; i++ {
    var x int
    n, err := fmt.Sscanf(numstr, "%d", &x)
    if n != 1 || x != num || err != nil {
      b.Error(err)
    }
  }
}

Vous pouvez l'exécuter en enregistrant sous atoi_test.goet en exécutant go test -bench=. atoi_test.go.

goos: darwin
goarch: amd64
BenchmarkStrconvParseInt-8      100000000           17.1 ns/op
BenchmarkAtoi-8                 100000000           19.4 ns/op
BenchmarkFmtSscan-8               2000000          693   ns/op
PASS
ok      command-line-arguments  5.797s

2

Essaye ça

import ("strconv")

value : = "123"
number,err := strconv.ParseUint(value, 10, 32)

0

Si vous contrôlez les données d'entrée, vous pouvez utiliser la mini version

package main

import (
    "testing"
    "strconv"
)

func Atoi (s string) int {
    var (
        n uint64
        i int
        v byte
    )   
    for ; i < len(s); i++ {
        d := s[i]
        if '0' <= d && d <= '9' {
            v = d - '0'
        } else if 'a' <= d && d <= 'z' {
            v = d - 'a' + 10
        } else if 'A' <= d && d <= 'Z' {
            v = d - 'A' + 10
        } else {
            n = 0; break        
        }
        n *= uint64(10) 
        n += uint64(v)
    }
    return int(n)
}

func BenchmarkAtoi(b *testing.B) {
    for i := 0; i < b.N; i++ {
        in := Atoi("9999")
        _ = in
    }   
}

func BenchmarkStrconvAtoi(b *testing.B) {
    for i := 0; i < b.N; i++ {
        in, _ := strconv.Atoi("9999")
        _ = in
    }   
}

l'option la plus rapide (écrivez votre chèque si nécessaire). Résultat :

Path>go test -bench=. atoi_test.go
goos: windows
goarch: amd64
BenchmarkAtoi-2                 100000000               14.6 ns/op
BenchmarkStrconvAtoi-2          30000000                51.2 ns/op
PASS
ok      path     3.293s

1
Quelle ? Vraiment ? Les gens qui ont écrit "go" ont rendu les choses beaucoup plus faciles. Ne faites pas tourner votre roue :)
Balaji Boggaram Ramanarayan

Et Atoi ("- 9999")?
Oleksiy Chechel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.