From fa1e212dad5e375b1b0effc9a2f0a3a70cabbb52 Mon Sep 17 00:00:00 2001 From: AC Date: Mon, 12 Oct 2026 11:37:59 +0800 Subject: [PATCH] py: fix explicit string split limits and empty separators --- py/string.go | 11 +++++++++-- py/string_test.go | 33 +++++++++++++++++++++++++++++++++ py/tests/string.py | 5 +++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/py/string.go b/py/string.go index f88d6524..0b52705d 100644 --- a/py/string.go +++ b/py/string.go @@ -695,7 +695,7 @@ func (s String) find(args Tuple) (Object, error) { func (s String) Split(args Tuple, kwargs StringDict) (Object, error) { var ( pyval Object = None - pymax Object = Int(-2) + pymax Object = Int(-1) pyfmt = "|Oi:split" kwlst = []string{"sep", "maxsplit"} ) @@ -710,7 +710,14 @@ func (s String) Split(args Tuple, kwargs StringDict) (Object, error) { ) switch v := pyval.(type) { case String: - vs = strings.SplitN(string(s), string(v), int(max)+1) + if v == "" { + return nil, ExceptionNewf(ValueError, "empty separator") + } + n := -1 + if max >= 0 && max < Int(len(s)) { + n = int(max) + 1 + } + vs = strings.SplitN(string(s), string(v), n) case NoneType: vs = fieldsN(string(s), int(max)) default: diff --git a/py/string_test.go b/py/string_test.go index 053cd781..9ff54f29 100644 --- a/py/string_test.go +++ b/py/string_test.go @@ -144,3 +144,36 @@ func TestStringLower(t *testing.T) { }) } } + +func TestStringSplitLimits(t *testing.T) { + for _, limit := range []Int{-100, -2, -1, 0, 1, 2, Int(^uint(0) >> 1)} { + got, err := String("a,b,c").Split(Tuple{String(","), limit}, nil) + if err != nil { + t.Fatal(err) + } + want := Tuple{String("a"), String("b"), String("c")} + if limit == 0 { + want = Tuple{String("a,b,c")} + } else if limit == 1 { + want = Tuple{String("a"), String("b,c")} + } + items := got.(*List).Items + if len(items) != len(want) { + t.Errorf("limit %d: got %v, want %v", limit, items, want) + continue + } + for i := range want { + if items[i] != want[i] { + t.Errorf("limit %d: got %v, want %v", limit, items, want) + } + } + } + for _, s := range []String{"", "abc"} { + for _, limit := range []Int{-1, 0, 1} { + _, err := s.Split(Tuple{String(""), limit}, nil) + if !IsException(ValueError, err) { + t.Errorf("%q split empty with limit %d: %v, want ValueError", s, limit, err) + } + } + } +} diff --git a/py/tests/string.py b/py/tests/string.py index d71e8645..8b6e9e78 100644 --- a/py/tests/string.py +++ b/py/tests/string.py @@ -112,6 +112,11 @@ class C(): doc="split" assert ["0","1","2","4"] == list("0,1,2,4".split(",")) +assert ['a', 'b', 'c'] == 'a,b,c'.split(',', -1) +assert ['a,b,c'] == 'a,b,c'.split(',', 0) +assert ['a', 'b', 'c'] == 'a,b,c'.split(',', 2147483647) +assertRaisesText(ValueError, "empty separator", lambda: 'abc'.split('')) +assertRaisesText(ValueError, "empty separator", lambda: ''.split('', 0)) assert [""] == list("".split(",")) assert ['a', 'd,c'] == list("a,d,c".split(",",1)) assert ['a', 'd', 'b'] == list(" a d b ".split())