From f36f99d8282161f83da723d9132cda12e2309ed0 Mon Sep 17 00:00:00 2001 From: wwww-deeeee <192517353+wwww-deeeee@users.noreply.github.com> Date: Thu, 17 Sep 2026 15:02:38 +0800 Subject: [PATCH] fix: fallback to decimal for integer strings with leading zeros When parsing integer strings with leading zeros (e.g. '08', '09', '-08'), strconv.ParseInt with base 0 treats them as octal numbers, which fails due to digits 8 and 9 being invalid in base 8. This change adds a fallback to base 10 when base 0 parsing fails, allowing common business decimal values like months or dates with leading zeros to be parsed correctly while preserving support for 0x, 0b, and valid octal numbers. Closes #147 Signed-off-by: wwww-deeeee <192517353+wwww-deeeee@users.noreply.github.com> --- number.go | 12 ++++++++++-- number_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/number.go b/number.go index a58dc4d1..be102f6a 100644 --- a/number.go +++ b/number.go @@ -405,8 +405,12 @@ func parseNumber[T Number](s string) (T, error) { } func parseInt[T integer](s string) (T, error) { - v, err := strconv.ParseInt(trimDecimal(s), 0, 0) + trimmed := trimDecimal(s) + v, err := strconv.ParseInt(trimmed, 0, 0) if err != nil { + if v10, err10 := strconv.ParseInt(trimmed, 10, 0); err10 == nil { + return T(v10), nil + } return 0, err } @@ -414,8 +418,12 @@ 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) + trimmed := strings.TrimLeft(trimDecimal(s), "+") + v, err := strconv.ParseUint(trimmed, 0, 0) if err != nil { + if v10, err10 := strconv.ParseUint(trimmed, 10, 0); err10 == nil { + return T(v10), nil + } return 0, err } diff --git a/number_test.go b/number_test.go index 9d84d18d..e1f57b29 100644 --- a/number_test.go +++ b/number_test.go @@ -464,3 +464,36 @@ func BenchmarkNumber(b *testing.B) { }) } } + +func TestIssue147LeadingZeros(t *testing.T) { + c := qt.New(t) + + // Issue #147: cast.ToInt("08") returned 0 + // Strings with leading zeros should fall back to decimal parsing if not valid octal + c.Assert(cast.ToInt("08"), qt.Equals, 8) + c.Assert(cast.ToInt("09"), qt.Equals, 9) + c.Assert(cast.ToInt("-08"), qt.Equals, -8) + c.Assert(cast.ToInt("+09"), qt.Equals, 9) + c.Assert(cast.ToInt("007"), qt.Equals, 7) + c.Assert(cast.ToInt64("08"), qt.Equals, int64(8)) + c.Assert(cast.ToInt64("09"), qt.Equals, int64(9)) + c.Assert(cast.ToUint("08"), qt.Equals, uint(8)) + c.Assert(cast.ToUint("09"), qt.Equals, uint(9)) + c.Assert(cast.ToUint64("08"), qt.Equals, uint64(8)) + + v, err := cast.ToIntE("08") + c.Assert(err, qt.IsNil) + c.Assert(v, qt.Equals, 8) + + v64, err := cast.ToInt64E("09") + c.Assert(err, qt.IsNil) + c.Assert(v64, qt.Equals, int64(9)) + + u, err := cast.ToUintE("08") + c.Assert(err, qt.IsNil) + c.Assert(u, qt.Equals, uint(8)) + + // Invalid strings should still fail + _, err = cast.ToIntE("08abc") + c.Assert(err, qt.IsNotNil) +}