Czy konwertować ciąg znaków na liczbę całkowitą w Go?

236

Próbuję przekonwertować ciąg zwrócony z flag.Arg(n)na int. Jak idiomatyczny sposób to zrobić w Go?

Matt Joiner
źródło

Odpowiedzi:

298

Na przykład,

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)
}
peterSO
źródło
14
func main() { ... }nie przyjmuje argumentów i nie zwraca wartości. Użyj funkcji ospakietu, Exitnp.os.Exit(2).
peterSO
2
Alternatywnie po prostu wykonaj fatalny przykładpanic(err)
Peter Bengtsson
70

Konwertowanie prostych ciągów

Najprostszym sposobem jest użycie tej strconv.Atoi()funkcji.

Pamiętaj, że istnieje wiele innych sposobów. Na przykład fmt.Sscan()i strconv.ParseInt()które dają większą elastyczność, ponieważ można na przykład określić bazę i rozmiar bitów. Również zgodnie z dokumentacją strconv.Atoi():

Atoi jest równoważne ParseInt (s, 10, 0), przekonwertowane na typ int.

Oto przykład wykorzystujący wspomniane funkcje (wypróbuj na 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)
}

Dane wyjściowe (jeśli wywoływane z argumentem "123"):

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

Analiza niestandardowych ciągów

Jest także przydatny, fmt.Sscanf()który daje jeszcze większą elastyczność, ponieważ w łańcuchu formatu możesz określić format liczb (np. Szerokość, podstawa itp.) Wraz z dodatkowymi dodatkowymi znakami na wejściu string.

Jest to doskonałe do analizowania niestandardowych ciągów zawierających liczbę. Na przykład, jeśli dane wejściowe są dostarczane w postaci, w "id:00123"której masz prefiks, "id:"a liczba jest stała, to 5 cyfr, wypełnionych zerami, jeśli są krótsze, można to bardzo łatwo przetworzyć w następujący sposób:

s := "id:00123"

var i int
if _, err := fmt.Sscanf(s, "id:%5d", &i); err == nil {
    fmt.Println(i) // Outputs 123
}
icza
źródło
Co określa drugi argument ParseInt?
kaushik94
1
@ kaushik94 Kliknij na strconv.ParseInt()link i zobaczysz natychmiast: ParseInt(s string, base int, bitSize int). Jest to więc podstawa: „ParseInt interpretuje ciąg s w podanej bazie (2 do 36)”
icza
Zauważ, że argument bitSize na strconv.ParseInt () nie przekształci ciągu na wybrany przez ciebie typ, ale zamiast tego jest tylko po to, aby ograniczyć wynik do określonej „bitowości”. Zobacz także: stackoverflow.com/questions/55925894/…
viv
@viv Tak, to prawda. Jeśli intwymagana jest wartość typu i strconv.ParseInt()jest ona używana, konieczna jest ręczna konwersja typu (z int64na int).
icza
16

Oto trzy sposoby przetwarzania ciągów znaków na liczby całkowite, od najszybszego środowiska uruchomieniowego do najwolniejszego:

  1. strconv.ParseInt(...) najszybszy
  2. strconv.Atoi(...) wciąż bardzo szybko
  3. fmt.Sscanf(...) nie strasznie szybki, ale najbardziej elastyczny

Oto test porównawczy, który pokazuje użycie i przykładowe czasy dla każdej funkcji:

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

Możesz go uruchomić, zapisując jako atoi_test.goi uruchamiając 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
maerika
źródło
2

Spróbuj tego

import ("strconv")

value : = "123"
number,err := strconv.ParseUint(value, 10, 32)
MD Mahedi hasan
źródło
0

Jeśli kontrolujesz dane wejściowe, możesz użyć wersji 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
    }   
}

najszybsza opcja (w razie potrzeby wpisz czek). Wynik:

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
Jenyokcoder
źródło
1
Co ? Naprawdę Ludzie, którzy napisali „idź”, bardzo ułatwiają. Nie zakręć kołem :)
Balaji Boggaram Ramanarayan 30.04.2018
Co z Atoi („- 9999”)?
Oleksiy Chechel