แปลงสตริงเป็นประเภทจำนวนเต็มใน Go หรือไม่


236

ฉันพยายามที่จะแปลงสตริงกลับมาจากการไปยังflag.Arg(n) intเป็นวิธีสำนวนที่จะทำใน Go?

คำตอบ:


298

ตัวอย่างเช่น,

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() { ... }ไม่รับข้อโต้แย้งและไม่คืนค่าใด ๆ ใช้ฟังก์ชั่นosบรรจุภัณฑ์Exitเช่นos.Exit(2).
peterSO

2
หรือเพียงแค่ทำตัวอย่างร้ายแรงเช่นpanic(err)
Peter Bengtsson

70

การแปลงสตริงธรรมดา

วิธีที่ง่ายที่สุดคือการใช้strconv.Atoi()ฟังก์ชั่น

โปรดทราบว่ามีวิธีอื่น ๆ อีกมากมาย ตัวอย่างเช่นfmt.Sscan()และstrconv.ParseInt()ที่ให้ความยืดหยุ่นมากขึ้นในขณะที่คุณสามารถระบุฐานและบิตตัวอย่างเช่น ตามที่ระบุไว้ในเอกสารของstrconv.Atoi():

Atoi เทียบเท่ากับ ParseInt (s, 10, 0), แปลงเป็นประเภท int

นี่คือตัวอย่างการใช้ฟังก์ชั่นที่กล่าวถึง (ลองใช้งานใน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)
}

เอาท์พุท (ถ้าเรียกว่ามีข้อโต้แย้ง"123"):

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

การแยกสตริงที่กำหนดเอง

นอกจากนี้ยังมีประโยชน์fmt.Sscanf()ซึ่งจะช่วยให้มีความยืดหยุ่นมากยิ่งขึ้นเช่นเดียวกับสตริงรูปแบบที่คุณสามารถระบุรูปแบบตัวเลข (เช่นความกว้างฐาน ฯลฯ ) stringพร้อมด้วยอักขระพิเศษเพิ่มเติมในการป้อนข้อมูล

นี่คือที่ดีสำหรับการแยกสตริงที่กำหนดเองถือตัวเลข ตัวอย่างเช่นหากการป้อนข้อมูลของคุณมีให้ในรูปแบบ"id:00123"ที่คุณมีคำนำหน้า"id:"และหมายเลขได้รับการแก้ไข 5 หลักเบาะด้วยศูนย์ถ้าสั้นกว่านี้จะแยกวิเคราะห์ได้ง่ายเช่นนี้:

s := "id:00123"

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

อาร์กิวเมนต์ที่สองที่ParseIntระบุคืออะไร
kaushik94

1
@ kaushik94 คลิกที่ลิงค์และคุณจะเห็นได้ทันที:strconv.ParseInt() ParseInt(s string, base int, bitSize int)ดังนั้นมันจึงเป็นฐาน: "ParseInt ตีความสตริง s ในฐานที่กำหนด (2 ถึง 36)"
icza

โปรดทราบว่าอาร์กิวเมนต์ bitSize เป็น strconv.ParseInt () จะไม่แปลงสตริงเป็นประเภทที่คุณเลือก แต่จะมีเพียงเพื่อ จำกัด ผลลัพธ์ให้เป็น 'bitness' ดูเพิ่มเติมที่: stackoverflow.com/questions/55925894/…
viv

@viv ใช่ถูกต้องแล้ว หากintจำเป็นต้องstrconv.ParseInt()ใช้ค่าประเภทและจะต้องใช้การแปลงประเภทด้วยตนเอง (จากint64ถึงint)
icza

16

ต่อไปนี้เป็นสามวิธีในการวิเคราะห์สตริงเป็นจำนวนเต็มจากรันไทม์ที่เร็วที่สุดจนถึงช้าที่สุด:

  1. strconv.ParseInt(...) เร็วที่สุด
  2. strconv.Atoi(...) ยังเร็วมาก
  3. fmt.Sscanf(...) ไม่เร็วอย่างน่ากลัว แต่มีความยืดหยุ่นมากที่สุด

นี่คือมาตรฐานที่แสดงการใช้งานและเวลาตัวอย่างสำหรับแต่ละฟังก์ชั่น:

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

คุณสามารถเรียกใช้งานโดยการบันทึกเป็นและทำงานatoi_test.gogo 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


0

หากคุณควบคุมข้อมูลอินพุตคุณสามารถใช้รุ่นมินิได้

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

ตัวเลือกที่เร็วที่สุด (เขียนเช็คของคุณหากจำเป็น) ผลลัพธ์ :

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
อะไร ? จริงเหรอ คนที่เขียนว่า "ไป" ทำได้ง่ายมาก อย่าหมุนวงล้อของคุณ :)
Balaji Boggaram Ramanarayan

แล้ว Atoi ("- 9999") ล่ะ?
Oleksiy Chechel
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.