Skip to content

Commit a3f4b83

Browse files
committed
add methods isspace(), isalpha(), isdigit(), isupper() and islower() to str
1 parent 1f07b7e commit a3f4b83

4 files changed

Lines changed: 102 additions & 0 deletions

File tree

py/misc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ bool unichar_isalpha(unichar c);
9696
bool unichar_isprint(unichar c);
9797
bool unichar_isdigit(unichar c);
9898
bool unichar_isxdigit(unichar c);
99+
bool unichar_isupper(unichar c);
100+
bool unichar_islower(unichar c);
99101
unichar unichar_tolower(unichar c);
100102
unichar unichar_toupper(unichar c);
101103

py/objstr.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,6 +1502,71 @@ STATIC mp_obj_t str_upper(mp_obj_t self_in) {
15021502
return str_caseconv(CASE_UPPER, self_in);
15031503
}
15041504

1505+
enum { IS_SPACE, IS_ALPHA, IS_DIGIT, IS_UPPER, IS_LOWER };
1506+
1507+
STATIC mp_obj_t str_uni_istype(int type, mp_obj_t self_in) {
1508+
GET_STR_DATA_LEN(self_in, self_data, self_len);
1509+
1510+
if (self_len == 0) return mp_const_false; // default to False for empty str
1511+
1512+
typedef bool (*check_function)(unichar);
1513+
check_function f;
1514+
1515+
if (type != IS_UPPER && type != IS_LOWER) {
1516+
switch (type) {
1517+
case IS_SPACE: f = &unichar_isspace; break;
1518+
case IS_ALPHA: f = &unichar_isalpha; break;
1519+
case IS_DIGIT: f = &unichar_isdigit; break;
1520+
default:
1521+
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unknown type provided for str_uni_istype"));
1522+
}
1523+
1524+
for (int i = 0; i < self_len; i++) {
1525+
if (!f(*self_data++)) return mp_const_false;
1526+
}
1527+
} else {
1528+
switch (type) {
1529+
case IS_UPPER: f = &unichar_isupper; break;
1530+
case IS_LOWER: f = &unichar_islower; break;
1531+
default:
1532+
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "unknown type provided for str_uni_istype"));
1533+
}
1534+
1535+
bool contains_alpha = false;
1536+
1537+
for (int i = 0; i < self_len; i++) { // only check alphanumeric characters
1538+
if (unichar_isalpha(*self_data++)) {
1539+
contains_alpha = true;
1540+
if (!f(*(self_data-1))) return mp_const_false; // we already incremented
1541+
}
1542+
}
1543+
1544+
if (!(contains_alpha)) return mp_const_false;
1545+
}
1546+
1547+
return mp_const_true;
1548+
}
1549+
1550+
STATIC mp_obj_t str_isspace(mp_obj_t self_in) {
1551+
return str_uni_istype(IS_SPACE, self_in);
1552+
}
1553+
1554+
STATIC mp_obj_t str_isalpha(mp_obj_t self_in) {
1555+
return str_uni_istype(IS_ALPHA, self_in);
1556+
}
1557+
1558+
STATIC mp_obj_t str_isdigit(mp_obj_t self_in) {
1559+
return str_uni_istype(IS_DIGIT, self_in);
1560+
}
1561+
1562+
STATIC mp_obj_t str_isupper(mp_obj_t self_in) {
1563+
return str_uni_istype(IS_UPPER, self_in);
1564+
}
1565+
1566+
STATIC mp_obj_t str_islower(mp_obj_t self_in) {
1567+
return str_uni_istype(IS_LOWER, self_in);
1568+
}
1569+
15051570
#if MICROPY_CPYTHON_COMPAT
15061571
// These methods are superfluous in the presense of str() and bytes()
15071572
// constructors.
@@ -1569,6 +1634,11 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
15691634
STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
15701635
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_lower_obj, str_lower);
15711636
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_upper_obj, str_upper);
1637+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isspace_obj, str_isspace);
1638+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isalpha_obj, str_isalpha);
1639+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isdigit_obj, str_isdigit);
1640+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_isupper_obj, str_isupper);
1641+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(str_islower_obj, str_islower);
15721642

15731643
STATIC const mp_map_elem_t str_locals_dict_table[] = {
15741644
#if MICROPY_CPYTHON_COMPAT
@@ -1594,6 +1664,11 @@ STATIC const mp_map_elem_t str_locals_dict_table[] = {
15941664
{ MP_OBJ_NEW_QSTR(MP_QSTR_rpartition), (mp_obj_t)&str_rpartition_obj },
15951665
{ MP_OBJ_NEW_QSTR(MP_QSTR_lower), (mp_obj_t)&str_lower_obj },
15961666
{ MP_OBJ_NEW_QSTR(MP_QSTR_upper), (mp_obj_t)&str_upper_obj },
1667+
{ MP_OBJ_NEW_QSTR(MP_QSTR_isspace), (mp_obj_t)&str_isspace_obj },
1668+
{ MP_OBJ_NEW_QSTR(MP_QSTR_isalpha), (mp_obj_t)&str_isalpha_obj },
1669+
{ MP_OBJ_NEW_QSTR(MP_QSTR_isdigit), (mp_obj_t)&str_isdigit_obj },
1670+
{ MP_OBJ_NEW_QSTR(MP_QSTR_isupper), (mp_obj_t)&str_isupper_obj },
1671+
{ MP_OBJ_NEW_QSTR(MP_QSTR_islower), (mp_obj_t)&str_islower_obj },
15971672
};
15981673

15991674
STATIC MP_DEFINE_CONST_DICT(str_locals_dict, str_locals_dict_table);

py/qstrdefs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@ Q(partition)
246246
Q(rpartition)
247247
Q(lower)
248248
Q(upper)
249+
Q(isspace)
250+
Q(isalpha)
251+
Q(isdigit)
252+
Q(isupper)
253+
Q(islower)
249254
Q(iterable)
250255
Q(start)
251256

tests/basics/string_istest.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
print("".isspace())
2+
print(" \t\n\r\v\f".isspace())
3+
print("a".isspace())
4+
print(" \t\n\r\v\fa".isspace())
5+
print("".isalpha())
6+
print("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha())
7+
print("0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".isalpha())
8+
print("this ".isalpha())
9+
print("".isdigit())
10+
print("0123456789".isdigit())
11+
print("0123456789a".isdigit())
12+
print("0123456789 ".isdigit())
13+
print("".isupper())
14+
print("CHEESE-CAKE WITH ... _FROSTING_*99".isupper())
15+
print("aB".isupper())
16+
print("".islower())
17+
print("cheese-cake with ... _frosting_*99".islower())
18+
print("aB".islower())
19+
print("123".islower())
20+
print("123a".islower())

0 commit comments

Comments
 (0)