diff --git a/py/string.go b/py/string.go index a987a11a..f88d6524 100644 --- a/py/string.go +++ b/py/string.go @@ -148,6 +148,13 @@ func init() { return Bool(false), nil }, 0, "endswith(suffix[, start[, end]]) -> bool") + StringType.Dict["count"] = MustNewMethod("count", func(self Object, args Tuple) (Object, error) { + return self.(String).Count(args) + }, 0, `count(sub[, start[, end]]) -> int +Return the number of non-overlapping occurrences of substring sub in +string S[start:end]. Optional arguments start and end are +interpreted as in slice notation.`) + StringType.Dict["find"] = MustNewMethod("find", func(self Object, args Tuple) (Object, error) { return self.(String).find(args) }, 0, `find(...) @@ -612,6 +619,40 @@ func (s String) M__contains__(item Object) (Object, error) { return NewBool(strings.Contains(string(s), string(needle))), nil } +func (s String) Count(args Tuple) (Object, error) { + var ( + pysub Object + pybeg Object = Int(0) + pyend Object = Int(s.len()) + pyfmt = "s|ii:count" + ) + err := ParseTuple(args, pyfmt, &pysub, &pybeg, &pyend) + if err != nil { + return nil, err + } + + var ( + beg = int(pybeg.(Int)) + end = int(pyend.(Int)) + size = s.len() + ) + if beg > size { + beg = size + } + if end < 0 { + end = size + } + if end > size { + end = size + } + + var ( + str = string(s.slice(beg, end, s.len())) + sub = string(pysub.(String)) + ) + return Int(strings.Count(str, sub)), nil +} + func (s String) find(args Tuple) (Object, error) { var ( pysub Object diff --git a/py/tests/string.py b/py/tests/string.py index d1d16cfd..d71e8645 100644 --- a/py/tests/string.py +++ b/py/tests/string.py @@ -944,5 +944,14 @@ def __index__(self): else: assert False, "TypeError not raised" +doc="count" +assert 'hello world'.count('l') == 3 +assert 'hello world'.count('l', 3) == 2 +assert 'hello world'.count('l', 3, 10) == 2 +assert 'hello world'.count('l', 3, 100) == 2 +assert 'hello world'.count('l', 3, 5) == 1 +assert 'hello world'.count('l', 3, 1) == 0 +assert 'hello world'.count('z') == 0 + doc="finished"