From a3f4b83018519895a3ff00b7a5a9a0623c3b1f17 Mon Sep 17 00:00:00 2001 From: Kim Bauters Date: Sat, 31 May 2014 07:30:03 +0100 Subject: [PATCH] add methods isspace(), isalpha(), isdigit(), isupper() and islower() to str --- py/misc.h | 2 + py/objstr.c | 75 +++++++++++++++++++++++++++++++++++ py/qstrdefs.h | 5 +++ tests/basics/string_istest.py | 20 ++++++++++ 4 files changed, 102 insertions(+) create mode 100644 tests/basics/string_istest.py diff --git a/py/misc.h b/py/misc.h index 013b5f123e..fd54147efd 100644 --- a/py/misc.h +++ b/py/misc.h @@ -96,6 +96,8 @@ bool unichar_isalpha(unichar c); bool unichar_isprint(unichar c); bool unichar_isdigit(unichar c); bool unichar_isxdigit(unichar c); +bool unichar_isupper(unichar c); +bool unichar_islower(unichar c); unichar unichar_tolower(unichar c); unichar unichar_toupper(unichar c); diff --git a/py/objstr.c b/py/objstr.c index d095c8b471..729ed7a855 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -1502,6 +1502,71 @@ STATIC mp_obj_t str_upper(mp_obj_t self_in) { return str_caseconv(CASE_UPPER, self_in); } +enum { IS_SPACE, IS_ALPHA, IS_DIGIT, IS_UPPER, IS_LOWER }; + +STATIC mp_obj_t str_uni_istype(int type, mp_obj_t self_in) { + GET_STR_DATA_LEN(self_in, self_data, self_len); + + if (self_len == 0) return mp_const_false; // default to False for empty str + + typedef bool (*check_function)(unichar); + check_function f; + + if (type != IS_UPPER && type != IS_LOWER) { + switch (type) { + case IS_SPACE: f = &unichar_isspace; break; + case IS_ALPHA: f = &unichar_isalpha; break; + case IS_DIGIT: f = &unichar_isdigit; break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unknown type provided for str_uni_istype")); + } + + for (int i = 0; i < self_len; i++) { + if (!f(*self_data++)) return mp_const_false; + } + } else { + switch (type) { + case IS_UPPER: f = &unichar_isupper; break; + case IS_LOWER: f = &unichar_islower; break; + default: + nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unknown type provided for str_uni_istype")); + } + + bool contains_alpha = false; + + for (int i = 0; i < self_len; i++) { // only check alphanumeric characters + if (unichar_isalpha(*self_data++)) { + contains_alpha = true; + if (!f(*(self_data-1))) return mp_const_false; // we already incremented + } + } + + if (!(contains_alpha)) return mp_const_false; + } + + return mp_const_true; +} + +STATIC mp_obj_t str_isspace(mp_obj_t self_in) { + return str_uni_istype(IS_SPACE, self_in); +} + +STATIC mp_obj_t str_isalpha(mp_obj_t self_in) { + return str_uni_istype(IS_ALPHA, self_in); +} + +STATIC mp_obj_t str_isdigit(mp_obj_t self_in) { + return str_uni_istype(IS_DIGIT, self_in); +} + +STATIC mp_obj_t str_isupper(mp_obj_t self_in) { + return str_uni_istype(IS_UPPER, self_in); +} + +STATIC mp_obj_t str_islower(mp_obj_t self_in) { + return str_uni_istype(IS_LOWER, self_in); +} + #if MICROPY_CPYTHON_COMPAT // These methods are superfluous in the presense of str() and bytes() // constructors. @@ -1569,6 +1634,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition); STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition); STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower); STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper); +STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower); STATIC const mp_map_elem_t str_locals_dict_table[] = { #if MICROPY_CPYTHON_COMPAT @@ -1594,6 +1664,11 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj }, }; STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table); diff --git a/py/qstrdefs.h b/py/qstrdefs.h index 2d4ddfea29..4ee56db909 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -246,6 +246,11 @@ Q(partition) Q(rpartition) Q(lower) Q(upper) +Q(isspace) +Q(isalpha) +Q(isdigit) +Q(isupper) +Q(islower) Q(iterable) Q(start) diff --git a/tests/basics/string_istest.py b/tests/basics/string_istest.py new file mode 100644 index 0000000000..7ea6c4508f --- /dev/null +++ b/tests/basics/string_istest.py @@ -0,0 +1,20 @@ +print("".isspace()) +print(" \t\n\r\v\f".isspace()) +print("a".isspace()) +print(" \t\n\r\v\fa".isspace()) +print("".isalpha()) +print("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha()) +print("0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha()) +print("this ".isalpha()) +print("".isdigit()) +print("0123456789".isdigit()) +print("0123456789a".isdigit()) +print("0123456789 ".isdigit()) +print("".isupper()) +print("CHEESE-CAKE WITH ... _FROSTING_*99".isupper()) +print("aB".isupper()) +print("".islower()) +print("cheese-cake with ... _frosting_*99".islower()) +print("aB".islower()) +print("123".islower()) +print("123a".islower())