Convertir cadena a tipo entero en Go?


236

Estoy tratando de convertir una cadena devuelta de flag.Arg(n)a un int. ¿Cuál es la forma idiomática de hacer esto en Go?

Respuestas:


298

Por ejemplo,

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() { ... }no toma argumentos y no devuelve ningún valor. Utilice la función de ospaquete Exit, pos.Exit(2).
PeterSO

2
Alternativamente, solo haz un fatal Eg.panic(err)
Peter Bengtsson

70

Convertir cadenas simples

La forma más fácil es usar la strconv.Atoi()función.

Tenga en cuenta que hay muchas otras formas. Por ejemplo, fmt.Sscan()y strconv.ParseInt()que dan una mayor flexibilidad, ya que puede especificar la base y el tamaño de bits, por ejemplo. También como se señala en la documentación de strconv.Atoi():

Atoi es equivalente a ParseInt (s, 10, 0), convertido al tipo int.

Aquí hay un ejemplo usando las funciones mencionadas (pruébelo en 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)
}

Salida (si se llama con argumento "123"):

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

Analizando cadenas personalizadas

También hay una práctica fmt.Sscanf()que brinda una flexibilidad aún mayor, ya que con la cadena de formato puede especificar el formato de número (como ancho, base, etc.) junto con caracteres adicionales adicionales en la entrada string.

Esto es ideal para analizar cadenas personalizadas que contienen un número. Por ejemplo, si su entrada se proporciona en una forma "id:00123"en la que tiene un prefijo "id:"y el número está fijado en 5 dígitos, rellenado con ceros si es más corto, esto es muy fácil de analizar de esta manera:

s := "id:00123"

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

¿Qué significa el segundo argumento para ParseIntespecificar?
kaushik94

1
@ kaushik94 clic en el strconv.ParseInt()enlace y verá de inmediato: ParseInt(s string, base int, bitSize int). Entonces es la base: "ParseInt interpreta una cadena s en la base dada (2 a 36)"
icza

Tenga en cuenta que el argumento bitSize para strconv.ParseInt () no convertirá la cadena a su elección de tipo, sino que solo estará allí para limitar el resultado a un 'bitness' específico. Ver también: stackoverflow.com/questions/55925894/…
vivió el

@viv Sí, eso es correcto. Si intse requiere y strconv.ParseInt()se usa un valor de tipo, se necesita la conversión manual de tipo (de int64a int).
icza

16

Aquí hay tres formas de analizar cadenas en enteros, desde el tiempo de ejecución más rápido hasta el más lento:

  1. strconv.ParseInt(...) lo más rápido
  2. strconv.Atoi(...) todavía muy rápido
  3. fmt.Sscanf(...) no es terriblemente rápido pero es más flexible

Aquí hay un punto de referencia que muestra el uso y el tiempo de ejemplo para cada función:

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

Puede ejecutarlo guardando como atoi_test.goy ejecutándolo 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

Prueba esto

import ("strconv")

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

0

Si controla los datos de entrada, puede usar la versión mini

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

La opción más rápida (escriba su cheque si es necesario). Resultado:

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
Qué ? De Verdad ? Las personas que escribieron "ir" lo hicieron mucho más fácil. No gire la rueda :)
Balaji Boggaram Ramanarayan

¿Qué pasa con Atoi ("- 9999")?
Oleksiy Chechel
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.