diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index bf61fa07..29c7c930 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -21,7 +21,7 @@ #include #include -#define PK_VERSION "1.1.7" +#define PK_VERSION "1.1.8" #include "config.h" #include "export.h" diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index caaaf4a8..36832d34 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -74,7 +74,8 @@ struct Str{ int index(const Str& sub, int start=0) const; Str replace(char old, char new_) const; Str replace(const Str& old, const Str& new_, int count=-1) const; - std::vector split(const Str& sep, bool remove_empty) const; + std::vector split(const Str& sep) const; + int count(const Str& sub) const; /*************unicode*************/ int _unicode_index_to_byte(int i) const; diff --git a/python/builtins.py b/python/builtins.py index 172b6e67..be85811b 100644 --- a/python/builtins.py +++ b/python/builtins.py @@ -7,7 +7,9 @@ def print(*args, sep=' ', end='\n'): def abs(x): return -x if x < 0 else x -def max(*args): +def max(*args, key=None): + if key is None: + key = lambda x: x if len(args) == 0: raise TypeError('max expected 1 arguments, got 0') if len(args) == 1: @@ -20,11 +22,13 @@ def max(*args): i = next(args) if i is StopIteration: break - if i > res: + if key(i) > key(res): res = i return res -def min(*args): +def min(*args, key=None): + if key is None: + key = lambda x: x if len(args) == 0: raise TypeError('min expected 1 arguments, got 0') if len(args) == 1: @@ -37,7 +41,7 @@ def min(*args): i = next(args) if i is StopIteration: break - if i < res: + if key(i) < key(res): res = i return res @@ -95,42 +99,6 @@ def sorted(iterable, reverse=False, key=None): return a ##### str ##### -def __f(self, sep=None): - flag = sep is None - sep = sep or ' ' - if sep == "": - return list(self) - res = [] - i = 0 - while i < len(self): - if self[i:i+len(sep)] == sep: - res.append(self[:i]) - self = self[i+len(sep):] - i = 0 - else: - ++i - res.append(self) - if flag: - return [i for i in res if i != ''] - return res -str.split = __f - -def __f(self, s: str): - if type(s) is not str: - raise TypeError('must be str, not ' + type(s).__name__) - if s == '': - return len(self) + 1 - res = 0 - i = 0 - while i < len(self): - if self[i:i+len(s)] == s: - ++res - i += len(s) - else: - ++i - return res -str.count = __f - def __f(self, *args): if '{}' in self: for i in range(len(args)): diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index ddd4af29..7b8d3d33 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -560,12 +560,18 @@ void init_builtins(VM* _vm) { _vm->bind(_vm->_t(_vm->tp_str), "split(self, sep=' ')", [](VM* vm, ArgsView args) { const Str& self = _CAST(Str&, args[0]); - std::vector parts = self.split(CAST(Str&, args[1]), false); + std::vector parts = self.split(CAST(Str&, args[1])); List ret(parts.size()); for(int i=0; ibind(_vm->_t(_vm->tp_str), "count(self, s: str)", [](VM* vm, ArgsView args) { + const Str& self = _CAST(Str&, args[0]); + const Str& s = CAST(Str&, args[1]); + return VAR(self.count(s)); + }); + _vm->bind_method<1>("str", "index", [](VM* vm, ArgsView args) { const Str& self = _CAST(Str&, args[0]); const Str& sub = CAST(Str&, args[1]); diff --git a/src/str.cpp b/src/str.cpp index 1f99da25..c1db0517 100644 --- a/src/str.cpp +++ b/src/str.cpp @@ -316,7 +316,7 @@ int utf8len(unsigned char c, bool suppress){ return _byte_index_to_unicode(size); } - std::vector Str::split(const Str& sep, bool remove_empty) const{ + std::vector Str::split(const Str& sep) const{ std::vector result; std::string_view tmp; int start = 0; @@ -324,14 +324,27 @@ int utf8len(unsigned char c, bool suppress){ int i = index(sep, start); if(i == -1) break; tmp = sv().substr(start, i - start); - if(!remove_empty || !tmp.empty()) result.push_back(tmp); + if(!tmp.empty()) result.push_back(tmp); start = i + sep.size; } tmp = sv().substr(start, size - start); - if(!remove_empty || !tmp.empty()) result.push_back(tmp); + if(!tmp.empty()) result.push_back(tmp); return result; } + int Str::count(const Str& sub) const{ + if(sub.empty()) return size + 1; + int cnt = 0; + int start = 0; + while(true){ + int i = index(sub, start); + if(i == -1) break; + cnt++; + start = i + sub.size; + } + return cnt; + } + std::ostream& operator<<(std::ostream& os, const StrName& sn){ return os << sn.sv(); } diff --git a/src/vm.cpp b/src/vm.cpp index bedecd5b..d5d3a65b 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -233,7 +233,7 @@ namespace pkpy{ Str curr_path = _import_context.pending.back(); bool curr_is_init = _import_context.pending_is_init.back(); // convert relative path to absolute path - std::vector cpnts = curr_path.split(".", true); + std::vector cpnts = curr_path.split("."); int prefix = 0; // how many dots in the prefix for(int i=0; i 128){ diff --git a/tests/04_str.py b/tests/04_str.py index 1709923c..dd4a1587 100644 --- a/tests/04_str.py +++ b/tests/04_str.py @@ -42,10 +42,10 @@ assert t.startswith('this') == True; assert t.split('w') == ['this is string example....', 'o', '!!!'] assert "a,b,c".split(',') == ['a', 'b', 'c'] -assert 'a,'.split(',') == ['a', ''] +assert 'a,'.split(',') == ['a'] assert 'foo!!bar!!baz'.split('!!') == ['foo', 'bar', 'baz'] assert ' 4 3 '.split() == ['4', '3'] -assert ' 4 3 '.split(' ') == ['', '', '4', '3', '', ''] +assert ' 4 3 '.split(' ') == ['4', '3'] assert '111'.count('1') == 3 assert '111'.count('11') == 1 diff --git a/tests/99_builtin_func.py b/tests/99_builtin_func.py index 90f4b3f3..210c0b4f 100644 --- a/tests/99_builtin_func.py +++ b/tests/99_builtin_func.py @@ -1120,3 +1120,20 @@ import dis def aaa(): pass assert dis.dis(aaa) is None + +# test min/max +assert min(1, 2) == 1 +assert min(1, 2, 3) == 1 +assert min([1, 2]) == 1 +assert min([1, 2], key=lambda x: -x) == 2 + +assert max(1, 2) == 2 +assert max(1, 2, 3) == 3 +assert max([1, 2]) == 2 +assert max([1, 2], key=lambda x: -x) == 1 + +assert min([ + (1, 2), + (1, 3), + (1, 4), +]) == (1, 2) \ No newline at end of file