I want to check if a string is numeric.
For example:
"abcd123"should returnfalse."1.4"or"240"should returntrue.
I thought about using ParseInt and ParseFloat (from the strconv package), but am not sure if that is the right way.
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.
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.
I hit this in a high-throughput system today and did a benchmark of the three suggestions. Results:
BenchmarkNumDot-4: 657966132: 18.2 ns/op
BenchmarkNumeric-4: 49575919: 226 ns/op
BenchmarkRegexp-4: 18817201: 628 ns/op
Code follows since the playground does not support benchmarking.
package main
import (
"regexp"
"strconv"
"testing"
)
func BenchmarkNumDot(b *testing.B) {
for i := 0; i < b.N; i++ {
isNumDot("abc")
isNumDot("123")
isNumDot("12.34")
isNumDot("1.2.3.4")
}
}
func BenchmarkNumeric(b *testing.B) {
for i := 0; i < b.N; i++ {
isNumeric("abc")
isNumeric("123")
isNumeric("12.34")
isNumeric("1.2.3.4")
}
}
func BenchmarkRegexp(b *testing.B) {
re := regexp.MustCompile(`^[0-9]+(\.[0-9]+)?$`)
for i := 0; i < b.N; i++ {
isNumReg("abc", re)
isNumReg("123", re)
isNumReg("12.34", re)
isNumReg("1.2.3.4", re)
}
}
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 isNumReg(s string, re *regexp.Regexp) bool {
return re.Match([]byte(s))
}