【问题标题】:How can I convert string to integer in golanggolang中如何将字符串转换为整数
【发布时间】:2015-10-07 21:00:47
【问题描述】:

我想在 golang 中将字符串转换为整数。但我不知道字符串的格式。比如"10" -> 10, "65.0" -> 65, "xx" -> 0, "11xx" -> 11, "xx11"->0

我做了一些搜索并找到strconv.ParseInt()。但它无法处理"65.0"。所以我必须检查字符串的格式。

有没有更好的办法?

【问题讨论】:

标签: go casting type-conversion


【解决方案1】:

我相信你正在寻找的功能是

strconv.ParseFloat()

见例子here

但是这个函数的返回类型是float64。

如果您不需要作为字符串传递的数字的小数部分,下面的函数就可以完成这项工作:

func StrToInt(str string) (int, error) {
    nonFractionalPart := strings.Split(str, ".")
    return strconv.Atoi(nonFractionalPart[0])
}

【讨论】:

  • 这个解决方案不能处理 "11xx" -> 11 和 "xx11"->0
  • 没错。从问题中不清楚您是否需要处理“11xx”-> 11 之类的情况,我认为解析整数并保留其他字符不是一个好习惯。
  • 是的,我没有把我的问题说清楚。我会更新它。谢谢!
【解决方案2】:

您可以使用这三个函数将字符串值转换为整数或浮点数。 注意:必须导入 strconv 内置包才能执行这些功能。

  1. func Atoi(s string) (int, error)

  2. func ParseInt(s string, base int, bitSize int) (i int64, err error)

  3. func ParseFloat(s string, bitSize int) (float64, error)

    package main
    import (
        "fmt"
        "strconv"
    )
    func main() {
        i, _ := strconv.Atoi("-42")
        fmt.Println(i)
    
        j,_ := strconv.ParseInt("-42",10,8)
        fmt.Println(j)
    
        k,_ := strconv.ParseFloat("-42.8",8)
        fmt.Println(k)
    

    }

【讨论】:

    【解决方案3】:
    package main
    
    import "strconv"
    import "fmt"
    
    // The built-in package "strconv" provides the number parsing.
    
    // For `ParseInt`, the `0` means infer the base from
    // the string. `64` requires that the result fit in 64
    // bits.
    
    
    value, err := strconv.ParseInt("123", 0, 64)
    if err != nil {
        panic(err)
    }
    fmt.Println(value)
    

    For reference, Click Here

    如果你总是想要同样的东西,你也可以传递一个非零基数(比如10)。

    【讨论】:

      【解决方案4】:

      我想在 golang 中将字符串转换为整数。

      正如您已经提到的,有一个 strconv.ParseInt 函数可以做到这一点!

      但是我不知道字符串的格式。

      这听起来很可怕(也很有挑战性),但是在查看您的示例后,我可以很容易地得出结论,您知道格式并且问题可以这样表述:

      如何将字符串的初始部分解析为整数?

      strconv.ParseInt 在语法错误时返回 0,因此不太合适;好吧,至少直接不合适。但如果您提取它,它可以解析您的初始部分。我相信你已经弄清楚了,但这确实是最干净的解决方案:从字符串中提取你的内容,解析它。

      您可以通过几种方式提取前导整数,其中一种是使用regexp

      package main
      
      import (
          "fmt"
          "regexp"
          "strconv"
      )
      
      // Extract what you need
      var leadingInt = regexp.MustCompile(`^[-+]?\d+`)
      
      func ParseLeadingInt(s string) (int64, error) {
          s = leadingInt.FindString(s)
          if s == "" { // add this if you don't want error on "xx" etc
              return 0, nil
          }
          return strconv.ParseInt(s, 10, 64)
      }
      
      func main() {
          for _, s := range []string{"10", "65.0", "xx", "11xx", "xx11"} {
              i, err := ParseLeadingInt(s)
              fmt.Printf("%s\t%d\t%v\n", s, i, err)
          }
      }
      

      http://play.golang.org/p/d7sS5_WpLj

      我相信这段代码很简单,并且清楚地表明了意图。您还使用了标准的ParseInt,它工作并为您提供所需的所有错误检查。

      如果由于任何原因您无法提取前导整数(您需要它快速解析数 TB 的数据,而您的老板对您大喊大叫,他们现在需要它,昨天更好,所以抓紧时间交付它:嘶嘶声:) 我建议深入研究source code 并修改标准解析器,使其不报告语法错误,但返回字符串的解析部分。

      【讨论】:

        【解决方案5】:

        补充@MayankPatel 和@DeepakG 的出色答案。可以将字符串设置为各种数字类型。可以将各种数字类型设置为字符串。同样,“true”可以设置为布尔值,true 可以设置为字符串。

        package main
        
        import (
            "fmt"
            "strconv"
        )
        
        func main() {
            //convert a string to another type
            f, _ := strconv.ParseFloat("70.99", 64)
            i, _ := strconv.Atoi(fmt.Sprintf("%.f", f))
            t, _ := strconv.ParseBool("true")
            c := []interface{}{[]byte("70.99"), f, i, rune(i), t}
            checkType(c) //[]uint8 [55 48 46 57 57], float64 70.99, int 71, int32 71, bool true
        
            //convert another type to a string
            c = []interface{}{fmt.Sprintf("%s", []byte("70.99")), fmt.Sprintf("%.f", f), strconv.Itoa(i), string(rune(i)), strconv.FormatBool(t)}
            checkType(c) //string 70.99, string 71, string 71, string G, string true
        }
        
        func checkType(s []interface{}) {
            for k, _ := range s {
                fmt.Printf("%T %v\n", s[k], s[k])
            }
        }
        

        字符串类型表示字符串值的集合。字符串值是一个(可能为空的)字节序列。字节数称为字符串的长度,永远不会是负数。字符串是不可变的。见https://Golang.org/ref/spec#String_types

        这里有三种将字符串解析为整数的方法,从最快的运行时间到最慢的运行时间:1. strconv.ParseInt(...) 最快 2. strconv.Atoi(...) 仍然非常快 3. fmt.Sscanf(. ..) 不是非常快但最灵活。见https://stackoverflow.com/a/47317150/12817546

        避免将字符串转换为 []byte:b := []byte(s)。它分配一个新的内存空间并将整个内容复制到其中。见https://stackoverflow.com/a/52943136/12817546。见https://stackoverflow.com/a/41460993/12817546。引用已编辑。

        【讨论】:

        【解决方案6】:

        你可以写一个FieldsFunc来单独解析和获取数值。

        Play it here

        package main
        
        import (
            "fmt"
            "strconv"
            "strings"
            "unicode"
        )
        
        func stripNonIntFloat(s string) string {
            f := func(c rune) bool {
                return !unicode.IsNumber(c) && (c != 46)
            }
            output := strings.FieldsFunc(s, f)
            if len(output) > 0 {
                return output[0]
            } else {
                return ""
            }
        }
        
        func main() {
            strList := []string{"10", "65.0", "xx", "11xx", "xx11"}
            for i := 0; i < len(strList); i++ {
                s := stripNonIntFloat(strList[i])
                v, err := strconv.ParseFloat(s, 10)
                if err != nil {
                    fmt.Println(strList[i], 0)
                } else {
                    fmt.Println(strList[i], v)
                }
            }
        }
        

        这里的输出是

        10 10
        65.0 65
        xx 0
        11xx 11
        xx11 11
        

        请注意,您的 xx11 的最后一个条件将其处理为 11。

        【讨论】:

          【解决方案7】:

          从字符串的开头提取一个 int 是我最常做的事情之一。在 C 中,您可以使用 atoi() 或 strtol()。 Go 没有标准库函数来做这件事,这很荒谬。无论如何,这是我刚刚卷起来的一个:

          // strToInt gets the integer from the start of the string.
          // It returns the value and the offset of the first non-digit.
          func StrToInt(s string) (v int, offset int) {
              offset = strings.IndexFunc(s, func(r rune) bool { return r < '0' || r > '9' })
              if offset == -1 { offset = len(s) }
              if offset == 0 { return }   // Avoid Atoi on empty string
              v, _ = strconv.Atoi(s[:offset])
              return
          }
          

          如果您想处理 -ve 整数,您需要稍作修正。

          【讨论】:

          • 除了检查前导减号之外,您可能首先要跳过前导空格,以确保完整性。我把它留作练习。
          【解决方案8】:

          我目前的解决方案是:

          // Convert string to integer in best effort.                                                                                
           // TODO: handle overflow and add unittest                                                                                   
          func StrToInt(str string) (int64, error) {                                                                                  
              if len(str) == 0 {                                                                                                      
                  return 0, nil                                                                                                       
               }                                                                                                                       
               negative := false                                                                                                       
               i := 0                                                                                                                  
               if str[i] == '-' {                                                                                                      
                   negative = true                                                                                                     
                   i++                                                                                                                 
               } else if str[i] == '+' {                                                                                               
                   i++                                                                                                                 
               }                                                                                                                       
               r := int64(0)                                                                                                           
               for ; i < len(str); i++ {                                                                                             
                   if unicode.IsDigit(rune(str[i])) {                                                                                  
                       r = r*10 + int64(str[i]-'0')                                                                                    
                   } else {
                       break
                    }                                                                                                                   
               }                                                                                                                       
               if negative {                                                                                                           
                   r = -r                                                                                                              
               }                                                                                                                       
               // TODO: if i < len(str), we should return error                                                                        
               return r, nil                                                                                                           
           }    
          

          【讨论】:

          • 您按字节循环遍历str,但将其作为符文进行比较。我只是使用 for _, r := range str[i:] 通过符文循环字符串(或者不要打扰 unicode,只需针对 ASCII 0 和 9 文字进行测试)。
          • IMO,如果您想要一个能够提前停止解析并忽略尾随字符的 API,您应该让 API 返回消耗/解析的字节数或输入的剩余未解析部分(除了当然是现有的返回值)。
          猜你喜欢
          • 2017-08-22
          • 2017-08-18
          • 2014-12-17
          • 2010-10-13
          • 1970-01-01
          相关资源
          最近更新 更多