mirror of
https://github.com/micropython/micropython.git
synced 2025-09-05 17:30:41 +02:00
py/objstr: Support tuples and start/end args in startswith and endswith.
Some checks are pending
JavaScript code lint and formatting with Biome / eslint (push) Waiting to run
Check code formatting / code-formatting (push) Waiting to run
Check spelling with codespell / codespell (push) Waiting to run
Build docs / build (push) Waiting to run
Check examples / embedding (push) Waiting to run
Package mpremote / build (push) Waiting to run
.mpy file format and tools / test (push) Waiting to run
Build ports metadata / build (push) Waiting to run
cc3200 port / build (push) Waiting to run
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Waiting to run
esp32 port / build_idf (esp32_build_s3_c3) (push) Waiting to run
esp8266 port / build (push) Waiting to run
mimxrt port / build (push) Waiting to run
nrf port / build (push) Waiting to run
powerpc port / build (push) Waiting to run
qemu port / build_and_test_arm (push) Waiting to run
qemu port / build_and_test_rv32 (push) Waiting to run
renesas-ra port / build_renesas_ra_board (push) Waiting to run
rp2 port / build (push) Waiting to run
samd port / build (push) Waiting to run
stm32 port / build_stm32 (stm32_misc_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_nucleo_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_pyb_build) (push) Waiting to run
unix port / minimal (push) Waiting to run
unix port / reproducible (push) Waiting to run
unix port / standard (push) Waiting to run
unix port / standard_v2 (push) Waiting to run
unix port / coverage (push) Waiting to run
unix port / coverage_32bit (push) Waiting to run
unix port / nanbox (push) Waiting to run
unix port / float (push) Waiting to run
unix port / stackless_clang (push) Waiting to run
unix port / float_clang (push) Waiting to run
unix port / settrace (push) Waiting to run
unix port / settrace_stackless (push) Waiting to run
unix port / macos (push) Waiting to run
unix port / qemu_mips (push) Waiting to run
unix port / qemu_arm (push) Waiting to run
unix port / qemu_riscv64 (push) Waiting to run
webassembly port / build (push) Waiting to run
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-mingw (i686, mingw32, dev) (push) Waiting to run
windows port / build-mingw (i686, mingw32, standard) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, dev) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, standard) (push) Waiting to run
windows port / cross-build-on-linux (push) Waiting to run
zephyr port / build (push) Waiting to run
Python code lint and formatting with ruff / ruff (push) Waiting to run
Some checks are pending
JavaScript code lint and formatting with Biome / eslint (push) Waiting to run
Check code formatting / code-formatting (push) Waiting to run
Check spelling with codespell / codespell (push) Waiting to run
Build docs / build (push) Waiting to run
Check examples / embedding (push) Waiting to run
Package mpremote / build (push) Waiting to run
.mpy file format and tools / test (push) Waiting to run
Build ports metadata / build (push) Waiting to run
cc3200 port / build (push) Waiting to run
esp32 port / build_idf (esp32_build_cmod_spiram_s2) (push) Waiting to run
esp32 port / build_idf (esp32_build_s3_c3) (push) Waiting to run
esp8266 port / build (push) Waiting to run
mimxrt port / build (push) Waiting to run
nrf port / build (push) Waiting to run
powerpc port / build (push) Waiting to run
qemu port / build_and_test_arm (push) Waiting to run
qemu port / build_and_test_rv32 (push) Waiting to run
renesas-ra port / build_renesas_ra_board (push) Waiting to run
rp2 port / build (push) Waiting to run
samd port / build (push) Waiting to run
stm32 port / build_stm32 (stm32_misc_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_nucleo_build) (push) Waiting to run
stm32 port / build_stm32 (stm32_pyb_build) (push) Waiting to run
unix port / minimal (push) Waiting to run
unix port / reproducible (push) Waiting to run
unix port / standard (push) Waiting to run
unix port / standard_v2 (push) Waiting to run
unix port / coverage (push) Waiting to run
unix port / coverage_32bit (push) Waiting to run
unix port / nanbox (push) Waiting to run
unix port / float (push) Waiting to run
unix port / stackless_clang (push) Waiting to run
unix port / float_clang (push) Waiting to run
unix port / settrace (push) Waiting to run
unix port / settrace_stackless (push) Waiting to run
unix port / macos (push) Waiting to run
unix port / qemu_mips (push) Waiting to run
unix port / qemu_arm (push) Waiting to run
unix port / qemu_riscv64 (push) Waiting to run
webassembly port / build (push) Waiting to run
windows port / build-vs (Debug, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Debug, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x64, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, dev, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2019, standard, 2019, [16, 17)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, dev, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-2022, standard, 2022, [17, 18)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, dev, 2017, [15, 16)) (push) Waiting to run
windows port / build-vs (Release, x86, windows-latest, standard, 2017, [15, 16)) (push) Waiting to run
windows port / build-mingw (i686, mingw32, dev) (push) Waiting to run
windows port / build-mingw (i686, mingw32, standard) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, dev) (push) Waiting to run
windows port / build-mingw (x86_64, mingw64, standard) (push) Waiting to run
windows port / cross-build-on-linux (push) Waiting to run
zephyr port / build (push) Waiting to run
Python code lint and formatting with ruff / ruff (push) Waiting to run
This change allows tuples to be passed as the prefix/suffix argument to the `str.startswith()` and `str.endswith()` methods. The methods will return `True` if the string starts/ends with any of the prefixes/suffixes in the tuple. Also adds full support for the `start` and `end` arguments to both methods for compatibility with CPython. Tests have been updated for the new behaviour. Signed-off-by: Glenn Moloney <glenn.moloney@gmail.com>
This commit is contained in:
committed by
Damien George
parent
69ffd2aaf0
commit
eb45d97898
67
py/objstr.c
67
py/objstr.c
@@ -67,6 +67,26 @@ static void check_is_str_or_bytes(mp_obj_t self_in) {
|
||||
mp_check_self(mp_obj_is_str_or_bytes(self_in));
|
||||
}
|
||||
|
||||
static const byte *get_substring_data(const mp_obj_t obj, size_t n_args, const mp_obj_t *args, size_t *len) {
|
||||
// Get substring data from obj, using args[0,1] to specify start and end indices.
|
||||
GET_STR_DATA_LEN(obj, str, str_len);
|
||||
if (n_args > 0) {
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(obj);
|
||||
const byte *end = str + str_len;
|
||||
if (n_args > 1 && args[1] != mp_const_none) {
|
||||
end = str_index_to_ptr(self_type, str, str_len, args[1], true);
|
||||
}
|
||||
if (args[0] != mp_const_none) {
|
||||
str = str_index_to_ptr(self_type, str, str_len, args[0], true);
|
||||
}
|
||||
str_len = MAX(end - str, 0);
|
||||
}
|
||||
if (len) {
|
||||
*len = str_len;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* str */
|
||||
|
||||
@@ -802,37 +822,34 @@ static mp_obj_t str_rindex(size_t n_args, const mp_obj_t *args) {
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_rindex_obj, 2, 4, str_rindex);
|
||||
|
||||
// TODO: (Much) more variety in args
|
||||
static mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) {
|
||||
const mp_obj_type_t *self_type = mp_obj_get_type(args[0]);
|
||||
GET_STR_DATA_LEN(args[0], str, str_len);
|
||||
static mp_obj_t str_startendswith(size_t n_args, const mp_obj_t *args, bool ends_with) {
|
||||
size_t str_len;
|
||||
const byte *str = get_substring_data(args[0], n_args - 2, args + 2, &str_len);
|
||||
mp_obj_t *prefixes = (mp_obj_t *)&args[1];
|
||||
size_t n_prefixes = 1;
|
||||
if (mp_obj_is_type(args[1], &mp_type_tuple)) {
|
||||
mp_obj_tuple_get(args[1], &n_prefixes, &prefixes);
|
||||
}
|
||||
size_t prefix_len;
|
||||
const char *prefix = mp_obj_str_get_data(args[1], &prefix_len);
|
||||
const byte *start = str;
|
||||
if (n_args > 2) {
|
||||
start = str_index_to_ptr(self_type, str, str_len, args[2], true);
|
||||
for (size_t i = 0; i < n_prefixes; i++) {
|
||||
const char *prefix = mp_obj_str_get_data(prefixes[i], &prefix_len);
|
||||
const byte *s = str + (ends_with ? str_len - prefix_len : 0);
|
||||
if (prefix_len <= str_len && memcmp(s, prefix, prefix_len) == 0) {
|
||||
return mp_const_true;
|
||||
}
|
||||
}
|
||||
if (prefix_len + (start - str) > str_len) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return mp_obj_new_bool(memcmp(start, prefix, prefix_len) == 0);
|
||||
return mp_const_false;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 3, str_startswith);
|
||||
|
||||
static mp_obj_t str_startswith(size_t n_args, const mp_obj_t *args) {
|
||||
return str_startendswith(n_args, args, false);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_startswith_obj, 2, 4, str_startswith);
|
||||
|
||||
static mp_obj_t str_endswith(size_t n_args, const mp_obj_t *args) {
|
||||
GET_STR_DATA_LEN(args[0], str, str_len);
|
||||
size_t suffix_len;
|
||||
const char *suffix = mp_obj_str_get_data(args[1], &suffix_len);
|
||||
if (n_args > 2) {
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("start/end indices"));
|
||||
}
|
||||
|
||||
if (suffix_len > str_len) {
|
||||
return mp_const_false;
|
||||
}
|
||||
return mp_obj_new_bool(memcmp(str + (str_len - suffix_len), suffix, suffix_len) == 0);
|
||||
return str_startendswith(n_args, args, true);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 3, str_endswith);
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_endswith_obj, 2, 4, str_endswith);
|
||||
|
||||
enum { LSTRIP, RSTRIP, STRIP };
|
||||
|
||||
|
@@ -5,11 +5,28 @@ print("foobar".endswith("foobar"))
|
||||
print("foobar".endswith(""))
|
||||
print("foobar".endswith("foobarbaz"))
|
||||
|
||||
#print("1foobar".startswith("foo", 1))
|
||||
#print("1foo".startswith("foo", 1))
|
||||
#print("1foo".startswith("1foo", 1))
|
||||
#print("1fo".startswith("foo", 1))
|
||||
#print("1fo".startswith("foo", 10))
|
||||
print("foobar".endswith("bar", 3))
|
||||
print("foobar".endswith("bar", 4))
|
||||
print("foobar".endswith("foo", 0, 3))
|
||||
print("foobar".endswith("foo", 0, 4))
|
||||
print("foobar".endswith("foo", 1, 3))
|
||||
print("foobar".endswith("foo", 1, 3))
|
||||
print("foobar".endswith("oo", 1, 3))
|
||||
print("foobar".endswith("o", 2, 3))
|
||||
print("foobar".endswith("o", 3, 3))
|
||||
print("foobar".endswith("o", 4, 3))
|
||||
|
||||
print("foobar".endswith("bar", None, None))
|
||||
print("foobar".endswith("bar", None, 3))
|
||||
print("foobar".endswith("bar", 3, None))
|
||||
print("foobar".endswith("bar", 2, None))
|
||||
print("foobar".endswith("foo", None, 3))
|
||||
|
||||
print("foobar".endswith(("bar", "foo")))
|
||||
print("foobar".endswith(("foo", "bar")))
|
||||
print("foobar".endswith(("foo", "bar1")))
|
||||
print("foobar".endswith(("bar", )))
|
||||
print("foobar".endswith(("foo", )))
|
||||
|
||||
try:
|
||||
"foobar".endswith(1)
|
||||
|
@@ -1,6 +0,0 @@
|
||||
# MicroPython doesn't support tuple argument
|
||||
|
||||
try:
|
||||
"foobar".endswith(("bar", "sth"))
|
||||
except TypeError:
|
||||
print("TypeError")
|
@@ -1 +0,0 @@
|
||||
TypeError
|
@@ -10,6 +10,25 @@ print("1foo".startswith("1foo", 1))
|
||||
print("1fo".startswith("foo", 1))
|
||||
print("1fo".startswith("foo", 10))
|
||||
|
||||
print("1foobar".startswith("foo", 1, 5))
|
||||
print("1foobar".startswith("foo", 1, 4))
|
||||
print("1foobar".startswith("foo", 1, 3))
|
||||
print("1foobar".startswith("oo", 2, 4))
|
||||
print("1foobar".startswith("o", 3, 4))
|
||||
print("1foobar".startswith("o", 4, 4))
|
||||
print("1foobar".startswith("o", 5, 4))
|
||||
|
||||
print("foobar".startswith("foo", None, None))
|
||||
print("foobar".startswith("foo", None, 3))
|
||||
print("foobar".startswith("foo", None, 2))
|
||||
print("foobar".startswith("bar", 3, None))
|
||||
|
||||
|
||||
print("foobar".startswith(("foo", "sth")))
|
||||
print("foobar".startswith(("sth", "foo")))
|
||||
print("foobar".startswith(("sth", "foo2")))
|
||||
print("foobar".startswith(("foo", )))
|
||||
|
||||
try:
|
||||
"foobar".startswith(1)
|
||||
except TypeError:
|
||||
|
@@ -1,6 +0,0 @@
|
||||
# MicroPython doesn't support tuple argument
|
||||
|
||||
try:
|
||||
"foobar".startswith(("foo", "sth"))
|
||||
except TypeError:
|
||||
print("TypeError")
|
@@ -1 +0,0 @@
|
||||
TypeError
|
@@ -63,12 +63,6 @@ try:
|
||||
except NotImplementedError:
|
||||
print("NotImplementedError")
|
||||
|
||||
# str.endswith(s, start) not implemented
|
||||
try:
|
||||
"abc".endswith("c", 1)
|
||||
except NotImplementedError:
|
||||
print("NotImplementedError")
|
||||
|
||||
# str subscr with step!=1 not implemented
|
||||
try:
|
||||
print("abc"[1:2:3])
|
||||
|
@@ -13,7 +13,6 @@ NotImplementedError
|
||||
NotImplementedError
|
||||
NotImplementedError
|
||||
NotImplementedError
|
||||
NotImplementedError
|
||||
b'\x01\x02'
|
||||
b'\x01\x00'
|
||||
NotImplementedError
|
||||
|
Reference in New Issue
Block a user