diff --git a/number.go b/number.go index a58dc4d..51e09ed 100644 --- a/number.go +++ b/number.go @@ -414,12 +414,38 @@ func parseInt[T integer](s string) (T, error) { } func parseUint[T unsigned](s string) (T, error) { - v, err := strconv.ParseUint(strings.TrimLeft(trimDecimal(s), "+"), 0, 0) - if err != nil { - return 0, err + s = strings.TrimLeft(trimDecimal(s), "+") + v, err := strconv.ParseUint(s, 0, 0) + if err == nil { + return T(v), nil + } + if isLikelyHexString(s) { + v, err = strconv.ParseUint(s, 16, 0) + if err == nil { + return T(v), nil + } } - return T(v), nil + return 0, err +} + +func isLikelyHexString(s string) bool { + if s == "" { + return false + } + hasLetter := false + for _, r := range s { + switch { + case r >= '0' && r <= '9': + case r >= 'a' && r <= 'f': + hasLetter = true + case r >= 'A' && r <= 'F': + hasLetter = true + default: + return false + } + } + return hasLetter } func parseFloat[T float](s string) (T, error) { diff --git a/number_test.go b/number_test.go index 9d84d18..8c62a34 100644 --- a/number_test.go +++ b/number_test.go @@ -390,6 +390,21 @@ func TestNumber(t *testing.T) { } } +func TestIssue334_HexStringToUint64(t *testing.T) { + c := qt.New(t) + + const hex = "882d5422d5fffff" + const want uint64 = 613286979481632767 + + c.Assert(cast.ToUint64(hex), qt.Equals, want) + + got, err := cast.ToUint64E(hex) + c.Assert(err, qt.IsNil) + c.Assert(got, qt.Equals, want) + + c.Assert(cast.ToUint64("0x"+hex), qt.Equals, want) +} + func BenchmarkNumber(b *testing.B) { type testCase struct { name string