From 496c61de7e17e8247e52a2ed09f8d8e027d9a0f1 Mon Sep 17 00:00:00 2001 From: Timmy Welch Date: Sun, 5 May 2024 14:08:27 -0700 Subject: [PATCH] x/text/internal/colltab: Improve numeric sorting Sorts zero (0) as the first number instead of the last Sorts numbers with leading zeros after numbers with less leading zeros Fixes golang/go#25554 --- collate/collate_test.go | 10 +++++- internal/colltab/numeric.go | 21 ++++++++++-- internal/colltab/numeric_test.go | 59 ++++++++++++++++++++++---------- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/collate/collate_test.go b/collate/collate_test.go index 0e78b96fa..65b3be468 100644 --- a/collate/collate_test.go +++ b/collate/collate_test.go @@ -473,7 +473,15 @@ func TestNumeric(t *testing.T) { {"A-1", "A-2", -1}, {"A-2", "A-12", -1}, {"A-12", "A-2", 1}, - {"A-0001", "A-1", 0}, + {"A-0001", "A-1", 1}, + {"A-0000", "A-1", -1}, + {"0000-", "1-", -1}, + {"00001", "1", 1}, + {"00", "01", -1}, + {"0", "00", -1}, + {"01", "001", -1}, + {"01", "1", 1}, + {"1", "01", -1}, } { if got := c.CompareString(tt.a, tt.b); got != tt.want { t.Errorf("%d: CompareString(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want) diff --git a/internal/colltab/numeric.go b/internal/colltab/numeric.go index 53b819cc3..ebc2acf38 100644 --- a/internal/colltab/numeric.go +++ b/internal/colltab/numeric.go @@ -80,6 +80,7 @@ func (nw *numericWeighter) AppendNext(buf []Elem, s []byte) (ce []Elem, n int) { } // ce might have been grown already, so take it instead of buf. nc.init(ce, len(buf), isZero) + old_index := len(nc.elems) for n < len(s) { ce, sz := nw.Weighter.AppendNext(nc.elems, s[n:]) nc.b = s @@ -87,7 +88,12 @@ func (nw *numericWeighter) AppendNext(buf []Elem, s []byte) (ce []Elem, n int) { if !nc.update(ce) { break } + old_index = len(nc.elems) } + nc.elems = append(nc.elems, 0) + copy(nc.elems[old_index+1:], nc.elems[old_index:]) + nc.elems[old_index], _ = MakeElem(nc.zero+1, defaultSecondary, defaultTertiary, 0) + return nc.result(), n } @@ -105,6 +111,7 @@ func (nw *numericWeighter) AppendNextString(buf []Elem, s string) (ce []Elem, n return ce, n } nc.init(ce, len(buf), isZero) + old_index := len(nc.elems) for n < len(s) { ce, sz := nw.Weighter.AppendNextString(nc.elems, s[n:]) nc.s = s @@ -112,7 +119,12 @@ func (nw *numericWeighter) AppendNextString(buf []Elem, s string) (ce []Elem, n if !nc.update(ce) { break } + old_index = len(nc.elems) } + nc.elems = append(nc.elems, 0) + copy(nc.elems[old_index+1:], nc.elems[old_index:]) + nc.elems[old_index], _ = MakeElem(nc.zero+1, defaultSecondary, defaultTertiary, 0) + return nc.result(), n } @@ -122,6 +134,7 @@ type numberConverter struct { elems []Elem nDigits int lenIndex int + zero int s string // set if the input was of type string b []byte // set if the input was of type []byte @@ -133,6 +146,7 @@ func (nc *numberConverter) init(elems []Elem, oldLen int, isZero bool) { // Insert a marker indicating the start of a number and a placeholder // for the number of digits. if isZero { + nc.zero++ elems = append(elems[:oldLen], nc.w.numberStart, 0) } else { elems = append(elems, 0, 0) @@ -217,6 +231,9 @@ const maxDigits = 1<