Convertir cadena a tipo entero en Go?


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

Author: peterSO, 2010-11-25

4 answers

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)
}
 203
Author: peterSO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-28 03:44:15

Conversión de cadenas simples

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

Note que hay muchas otras maneras. Por ejemplo fmt.Sscan() y strconv.ParseInt() lo que le da mayor flexibilidad ya que puede especificar la base y el tamaño de bits, por ejemplo. También como se indica en la documentación de strconv.Atoi():

Atoi es la abreviatura de parseInt(s, 10, 0).

Aquí hay un ejemplo usando las funciones mencionadas (pruébelo en el Ir Parque Infantil):

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 un práctico fmt.Sscanf() lo que le da una flexibilidad aún mayor, ya que con la cadena de formato puede especificar el formato del número (como ancho, base, etc.) junto con caracteres 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 de "id:00123" donde usted tiene un prefijo "id:" y el número es fijo de 5 dígitos, rellenado con ceros si es más corto, esto es muy fácilmente parsable así:

s := "id:00123"

var i int
if _, err := fmt.Sscanf(s, "id:%5d", &i); err == nil {
    fmt.Println(i) // Outputs 123
}
 37
Author: icza,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-22 06:31:50

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(...) más rápido
  2. strconv.Atoi(...) todavía muy rápido
  3. fmt.Sscanf(...) no terriblemente rápido, pero 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.go y ejecutando 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
 5
Author: maerics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-05 02:46:25

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
 0
Author: Jenyokcoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-20 16:03:45