douzhongjiu2263
2017-08-15 03:40
浏览 206
已采纳

如何在Golang中编写isNumeric函数?

I want to check if a string is numeric.

For example:

  • "abcd123" should return false.
  • "1.4" or "240" should return true.

I thought about using ParseInt and ParseFloat (from the strconv package), but am not sure if that is the right way.

图片转代码服务由CSDN问答提供 功能建议

我要检查字符串是否为数字。

例如:

  • “ abcd123” 应该返回 false
  • “ 1.4” “ 240” 应该返回 true

    我考虑过使用 ParseInt ParseFloat (来自 strconv 包) ),但不确定是否正确。

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

5条回答 默认 最新

  • doushe8577 2017-08-15 04:21
    已采纳

    I was thinking of using strconv ParseInt and ParseFloat but not sure if that is the right way.

    Well, it's certainly a right way.

    You don't need to use ParseInt, though. ParseFloat will do the job.

    func isNumeric(s string) bool {
        _, err := strconv.ParseFloat(s, 64)
        return err == nil
    }
    

    See an example here: https://play.golang.org/p/D53HRS-KIL

    打赏 评论
  • dtbsezxw28056 2017-08-15 03:58

    You can use the strconv.Atoi function for check integer values, and the strconv.ParseFloat for float values. Below is an example:

    package main
    
    import (
        "fmt"
        "strconv"
    )
    
    func main() {
        v1 := "14"
    
        if _, err := strconv.Atoi(v1); err == nil {
            fmt.Printf("%q looks like a number.
    ", v1)
        } else {
            fmt.Printf("%q is not a number.
    ", v1)
        }
    
        v2 := "1.4"
        if _, err := strconv.ParseFloat(v2, 64); err == nil {
            fmt.Printf("%q looks like a float.
    ", v2)
        } else {
            fmt.Printf("%q is not a float.
    ", v2)
        }
    }
    
    /* Output:
    "14" looks like a number.
    "1.4" looks like a float.
    */
    

    You can check it on the Go Playground.

    打赏 评论
  • dqqxkq4047 2017-08-15 07:15

    If you need to convert the string to a floating-point number strconv.ParseFloat is the first choice.
    Here you just need to know that there is only "0123456789" and maximum one '.' in your string, here for me isNumDot is 12x faster than isNumeric, see:
    Consider this (1.7 seconds) - optimized for performance:

    func isNumDot(s string) bool {
        dotFound := false
        for _, v := range s {
            if v == '.' {
                if dotFound {
                    return false
                }
                dotFound = true
            } else if v < '0' || v > '9' {
                return false
            }
        }
        return true
    }
    

    and this (21.7 seconds - doing more extra works "converts the string to a floating-point number"):

    func isNumeric(s string) bool {
        _, err := strconv.ParseFloat(s, 64)
        return err == nil
    }
    

    try it:

    package main
    
    import (
        "fmt"
        "strconv"
        "time"
    )
    
    func isNumDot(s string) bool {
        dotFound := false
        for _, v := range s {
            if v == '.' {
                if dotFound {
                    return false
                }
                dotFound = true
            } else if v < '0' || v > '9' {
                return false
            }
        }
        return true
    }
    
    func isNumeric(s string) bool {
        _, err := strconv.ParseFloat(s, 64)
        return err == nil
    }
    
    func main() {
        fmt.Println(isNumDot("240"))     //true
        fmt.Println(isNumDot("abcd123")) //false
        fmt.Println(isNumDot("0.4."))    //false
        fmt.Println(isNumDot("240 "))    //false
        benchmark(isNumDot)
        benchmark(isNumeric)
    }
    
    func benchmark(f func(string) bool) {
        var res bool
        t := time.Now()
        for i := 0; i < 100000000; i++ {
            res = f("a 240") || f("abcd123") || f("0.4.") || f("240 ")
        }
        fmt.Println(time.Since(t))
        fmt.Println(res)
    }
    

    output:

    true
    false
    false
    false
    1.7822s
    false
    21.723s
    false
    
    打赏 评论
  • douke1891 2017-08-15 13:52

    All the answers are valid, but there's another option not yet suggested:

    re := regexp.MustCompile(`^[0-9]+(\.[0-9]+)?$`)
    isNum := re.Match([]byte("ab123"))
    

    Playground demo

    打赏 评论
  • douchun5976 2019-04-10 04:34

    I tried to comment on Adrian's answer but I guess I don't have enough reputation points. Building on his excellent response, here is a variation using PCRE. Some brief explanation on the symbols if you are unfamiliar with regular expressions:

    "^" matches the start of input (i.e. beginning of your string)

    "$" matches the end of input (i.e. the end of your string)

    "()" are grouping operators

    "*" matches 0 or more

    "+" matches 1 or more

    "?" matches exactly 0 or 1

    "\d" is a character class which represents the character values 0 through 9

    So, the following would require at least a leading 0, permit "0.", and everything else that is normally identified as a floating point value. You can experiment with this a bit.

    func isFloat(s string) bool {
        return regexp.MatchString(`^\d+(\.\d*)?$`, s)
    }
    

    Naturally, if you are calling this function to validate data, it should be cleaned:

    str := strings.TrimSpace(someString)
    if isFloat(str) {
      ...
    }
    

    That only works on ASCII characters. If you are dealing with UTF8 or another multi-byte character set (MBCS), it can be done with regexp but more work would be required and perhaps another approach altogether.

    打赏 评论

相关推荐 更多相似问题