bpo-39939: Add str.removeprefix and str.removesuffix (GH-18939)

Added str.removeprefix and str.removesuffix methods and corresponding
bytes, bytearray, and collections.UserString methods to remove affixes
from a string if present. See PEP 616 for a full description.
This commit is contained in:
sweeneyde 2020-04-22 17:05:48 -04:00 committed by GitHub
parent 39652cd8bd
commit a81849b031
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 597 additions and 6 deletions

View File

@ -1549,6 +1549,33 @@ expression support in the :mod:`re` module).
interpreted as in slice notation. interpreted as in slice notation.
.. method:: str.removeprefix(prefix, /)
If the string starts with the *prefix* string, return
``string[len(prefix):]``. Otherwise, return a copy of the original
string::
>>> 'TestHook'.removeprefix('Test')
'Hook'
>>> 'BaseTestCase'.removeprefix('Test')
'BaseTestCase'
.. versionadded:: 3.9
.. method:: str.removesuffix(suffix, /)
If the string ends with the *suffix* string and that *suffix* is not empty,
return ``string[:-len(suffix)]``. Otherwise, return a copy of the
original string::
>>> 'MiscTests'.removesuffix('Tests')
'Misc'
>>> 'TmpDirMixin'.removesuffix('Tests')
'TmpDirMixin'
.. versionadded:: 3.9
.. method:: str.encode(encoding="utf-8", errors="strict") .. method:: str.encode(encoding="utf-8", errors="strict")
Return an encoded version of the string as a bytes object. Default encoding Return an encoded version of the string as a bytes object. Default encoding
@ -1831,6 +1858,14 @@ expression support in the :mod:`re` module).
>>> 'www.example.com'.lstrip('cmowz.') >>> 'www.example.com'.lstrip('cmowz.')
'example.com' 'example.com'
See :meth:`str.removeprefix` for a method that will remove a single prefix
string rather than all of a set of characters. For example::
>>> 'Arthur: three!'.lstrip('Arthur: ')
'ee!'
>>> 'Arthur: three!'.removeprefix('Arthur: ')
'three!'
.. staticmethod:: str.maketrans(x[, y[, z]]) .. staticmethod:: str.maketrans(x[, y[, z]])
@ -1911,6 +1946,13 @@ expression support in the :mod:`re` module).
>>> 'mississippi'.rstrip('ipz') >>> 'mississippi'.rstrip('ipz')
'mississ' 'mississ'
See :meth:`str.removesuffix` for a method that will remove a single suffix
string rather than all of a set of characters. For example::
>>> 'Monty Python'.rstrip(' Python')
'M'
>>> 'Monty Python'.removesuffix(' Python')
'Monty'
.. method:: str.split(sep=None, maxsplit=-1) .. method:: str.split(sep=None, maxsplit=-1)
@ -2591,6 +2633,50 @@ arbitrary binary data.
Also accept an integer in the range 0 to 255 as the subsequence. Also accept an integer in the range 0 to 255 as the subsequence.
.. method:: bytes.removeprefix(prefix, /)
bytearray.removeprefix(prefix, /)
If the binary data starts with the *prefix* string, return
``bytes[len(prefix):]``. Otherwise, return a copy of the original
binary data::
>>> b'TestHook'.removeprefix(b'Test')
b'Hook'
>>> b'BaseTestCase'.removeprefix(b'Test')
b'BaseTestCase'
The *prefix* may be any :term:`bytes-like object`.
.. note::
The bytearray version of this method does *not* operate in place -
it always produces a new object, even if no changes were made.
.. versionadded:: 3.9
.. method:: bytes.removesuffix(suffix, /)
bytearray.removesuffix(suffix, /)
If the binary data ends with the *suffix* string and that *suffix* is
not empty, return ``bytes[:-len(suffix)]``. Otherwise, return a copy of
the original binary data::
>>> b'MiscTests'.removesuffix(b'Tests')
b'Misc'
>>> b'TmpDirMixin'.removesuffix(b'Tests')
b'TmpDirMixin'
The *suffix* may be any :term:`bytes-like object`.
.. note::
The bytearray version of this method does *not* operate in place -
it always produces a new object, even if no changes were made.
.. versionadded:: 3.9
.. method:: bytes.decode(encoding="utf-8", errors="strict") .. method:: bytes.decode(encoding="utf-8", errors="strict")
bytearray.decode(encoding="utf-8", errors="strict") bytearray.decode(encoding="utf-8", errors="strict")
@ -2841,7 +2927,14 @@ produce new objects.
b'example.com' b'example.com'
The binary sequence of byte values to remove may be any The binary sequence of byte values to remove may be any
:term:`bytes-like object`. :term:`bytes-like object`. See :meth:`~bytes.removeprefix` for a method
that will remove a single prefix string rather than all of a set of
characters. For example::
>>> b'Arthur: three!'.lstrip(b'Arthur: ')
b'ee!'
>>> b'Arthur: three!'.removeprefix(b'Arthur: ')
b'three!'
.. note:: .. note::
@ -2890,7 +2983,14 @@ produce new objects.
b'mississ' b'mississ'
The binary sequence of byte values to remove may be any The binary sequence of byte values to remove may be any
:term:`bytes-like object`. :term:`bytes-like object`. See :meth:`~bytes.removesuffix` for a method
that will remove a single suffix string rather than all of a set of
characters. For example::
>>> b'Monty Python'.rstrip(b' Python')
b'M'
>>> b'Monty Python'.removesuffix(b' Python')
b'Monty'
.. note:: .. note::

View File

@ -105,6 +105,16 @@ Merge (``|``) and update (``|=``) operators have been added to the built-in
:class:`dict` class. See :pep:`584` for a full description. :class:`dict` class. See :pep:`584` for a full description.
(Contributed by Brandt Bucher in :issue:`36144`.) (Contributed by Brandt Bucher in :issue:`36144`.)
PEP 616: New removeprefix() and removesuffix() string methods
-------------------------------------------------------------
:meth:`str.removeprefix(prefix)<str.removeprefix>` and
:meth:`str.removesuffix(suffix)<str.removesuffix>` have been added
to easily remove an unneeded prefix or a suffix from a string. Corresponding
``bytes``, ``bytearray``, and ``collections.UserString`` methods have also been
added. See :pep:`616` for a full description. (Contributed by Dennis Sweeney in
:issue:`18939`.)
Other Language Changes Other Language Changes
====================== ======================

View File

@ -1239,6 +1239,14 @@ class UserString(_collections_abc.Sequence):
if isinstance(sub, UserString): if isinstance(sub, UserString):
sub = sub.data sub = sub.data
return self.data.count(sub, start, end) return self.data.count(sub, start, end)
def removeprefix(self, prefix, /):
if isinstance(prefix, UserString):
prefix = prefix.data
return self.__class__(self.data.removeprefix(prefix))
def removesuffix(self, suffix, /):
if isinstance(suffix, UserString):
suffix = suffix.data
return self.__class__(self.data.removesuffix(suffix))
def encode(self, encoding='utf-8', errors='strict'): def encode(self, encoding='utf-8', errors='strict'):
encoding = 'utf-8' if encoding is None else encoding encoding = 'utf-8' if encoding is None else encoding
errors = 'strict' if errors is None else errors errors = 'strict' if errors is None else errors

View File

@ -682,6 +682,42 @@ class BaseTest:
self.checkraises(OverflowError, A2_16, "replace", "A", A2_16) self.checkraises(OverflowError, A2_16, "replace", "A", A2_16)
self.checkraises(OverflowError, A2_16, "replace", "AA", A2_16+A2_16) self.checkraises(OverflowError, A2_16, "replace", "AA", A2_16+A2_16)
def test_removeprefix(self):
self.checkequal('am', 'spam', 'removeprefix', 'sp')
self.checkequal('spamspam', 'spamspamspam', 'removeprefix', 'spam')
self.checkequal('spam', 'spam', 'removeprefix', 'python')
self.checkequal('spam', 'spam', 'removeprefix', 'spider')
self.checkequal('spam', 'spam', 'removeprefix', 'spam and eggs')
self.checkequal('', '', 'removeprefix', '')
self.checkequal('', '', 'removeprefix', 'abcde')
self.checkequal('abcde', 'abcde', 'removeprefix', '')
self.checkequal('', 'abcde', 'removeprefix', 'abcde')
self.checkraises(TypeError, 'hello', 'removeprefix')
self.checkraises(TypeError, 'hello', 'removeprefix', 42)
self.checkraises(TypeError, 'hello', 'removeprefix', 42, 'h')
self.checkraises(TypeError, 'hello', 'removeprefix', 'h', 42)
self.checkraises(TypeError, 'hello', 'removeprefix', ("he", "l"))
def test_removesuffix(self):
self.checkequal('sp', 'spam', 'removesuffix', 'am')
self.checkequal('spamspam', 'spamspamspam', 'removesuffix', 'spam')
self.checkequal('spam', 'spam', 'removesuffix', 'python')
self.checkequal('spam', 'spam', 'removesuffix', 'blam')
self.checkequal('spam', 'spam', 'removesuffix', 'eggs and spam')
self.checkequal('', '', 'removesuffix', '')
self.checkequal('', '', 'removesuffix', 'abcde')
self.checkequal('abcde', 'abcde', 'removesuffix', '')
self.checkequal('', 'abcde', 'removesuffix', 'abcde')
self.checkraises(TypeError, 'hello', 'removesuffix')
self.checkraises(TypeError, 'hello', 'removesuffix', 42)
self.checkraises(TypeError, 'hello', 'removesuffix', 42, 'h')
self.checkraises(TypeError, 'hello', 'removesuffix', 'h', 42)
self.checkraises(TypeError, 'hello', 'removesuffix', ("lo", "l"))
def test_capitalize(self): def test_capitalize(self):
self.checkequal(' hello ', ' hello ', 'capitalize') self.checkequal(' hello ', ' hello ', 'capitalize')
self.checkequal('Hello ', 'Hello ','capitalize') self.checkequal('Hello ', 'Hello ','capitalize')

View File

@ -665,7 +665,7 @@ plain ol' Python and is guaranteed to be available.
>>> import builtins >>> import builtins
>>> tests = doctest.DocTestFinder().find(builtins) >>> tests = doctest.DocTestFinder().find(builtins)
>>> 810 < len(tests) < 830 # approximate number of objects with docstrings >>> 816 < len(tests) < 836 # approximate number of objects with docstrings
True True
>>> real_tests = [t for t in tests if len(t.examples) > 0] >>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests >>> len(real_tests) # objects that actually have doctests

View File

@ -1660,6 +1660,7 @@ Hisao Suzuki
Kalle Svensson Kalle Svensson
Andrew Svetlov Andrew Svetlov
Paul Swartz Paul Swartz
Dennis Sweeney
Al Sweigart Al Sweigart
Sviatoslav Sydorenko Sviatoslav Sydorenko
Thenault Sylvain Thenault Sylvain

View File

@ -0,0 +1,5 @@
Added str.removeprefix and str.removesuffix methods and corresponding
bytes, bytearray, and collections.UserString methods to remove affixes
from a string if present.
See :pep:`616` for a full description.
Patch by Dennis Sweeney.

View File

@ -1181,6 +1181,71 @@ bytearray_endswith(PyByteArrayObject *self, PyObject *args)
return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args); return _Py_bytes_endswith(PyByteArray_AS_STRING(self), PyByteArray_GET_SIZE(self), args);
} }
/*[clinic input]
bytearray.removeprefix as bytearray_removeprefix
prefix: Py_buffer
/
Return a bytearray with the given prefix string removed if present.
If the bytearray starts with the prefix string, return
bytearray[len(prefix):]. Otherwise, return a copy of the original
bytearray.
[clinic start generated code]*/
static PyObject *
bytearray_removeprefix_impl(PyByteArrayObject *self, Py_buffer *prefix)
/*[clinic end generated code: output=6cabc585e7f502e0 input=968aada38aedd262]*/
{
const char *self_start = PyByteArray_AS_STRING(self);
Py_ssize_t self_len = PyByteArray_GET_SIZE(self);
const char *prefix_start = prefix->buf;
Py_ssize_t prefix_len = prefix->len;
if (self_len >= prefix_len
&& memcmp(self_start, prefix_start, prefix_len) == 0)
{
return PyByteArray_FromStringAndSize(self_start + prefix_len,
self_len - prefix_len);
}
return PyByteArray_FromStringAndSize(self_start, self_len);
}
/*[clinic input]
bytearray.removesuffix as bytearray_removesuffix
suffix: Py_buffer
/
Return a bytearray with the given suffix string removed if present.
If the bytearray ends with the suffix string and that suffix is not
empty, return bytearray[:-len(suffix)]. Otherwise, return a copy of
the original bytearray.
[clinic start generated code]*/
static PyObject *
bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix)
/*[clinic end generated code: output=2bc8cfb79de793d3 input=c1827e810b2f6b99]*/
{
const char *self_start = PyByteArray_AS_STRING(self);
Py_ssize_t self_len = PyByteArray_GET_SIZE(self);
const char *suffix_start = suffix->buf;
Py_ssize_t suffix_len = suffix->len;
if (self_len >= suffix_len
&& memcmp(self_start + self_len - suffix_len,
suffix_start, suffix_len) == 0)
{
return PyByteArray_FromStringAndSize(self_start,
self_len - suffix_len);
}
return PyByteArray_FromStringAndSize(self_start, self_len);
}
/*[clinic input] /*[clinic input]
bytearray.translate bytearray.translate
@ -2203,6 +2268,8 @@ bytearray_methods[] = {
BYTEARRAY_POP_METHODDEF BYTEARRAY_POP_METHODDEF
BYTEARRAY_REMOVE_METHODDEF BYTEARRAY_REMOVE_METHODDEF
BYTEARRAY_REPLACE_METHODDEF BYTEARRAY_REPLACE_METHODDEF
BYTEARRAY_REMOVEPREFIX_METHODDEF
BYTEARRAY_REMOVESUFFIX_METHODDEF
BYTEARRAY_REVERSE_METHODDEF BYTEARRAY_REVERSE_METHODDEF
{"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, _Py_rfind__doc__}, {"rfind", (PyCFunction)bytearray_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, _Py_rindex__doc__}, {"rindex", (PyCFunction)bytearray_rindex, METH_VARARGS, _Py_rindex__doc__},

View File

@ -2182,6 +2182,81 @@ bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new,
/** End DALKE **/ /** End DALKE **/
/*[clinic input]
bytes.removeprefix as bytes_removeprefix
prefix: Py_buffer
/
Return a bytes object with the given prefix string removed if present.
If the bytes starts with the prefix string, return bytes[len(prefix):].
Otherwise, return a copy of the original bytes.
[clinic start generated code]*/
static PyObject *
bytes_removeprefix_impl(PyBytesObject *self, Py_buffer *prefix)
/*[clinic end generated code: output=f006865331a06ab6 input=0c93bac817a8502c]*/
{
const char *self_start = PyBytes_AS_STRING(self);
Py_ssize_t self_len = PyBytes_GET_SIZE(self);
const char *prefix_start = prefix->buf;
Py_ssize_t prefix_len = prefix->len;
if (self_len >= prefix_len
&& prefix_len > 0
&& memcmp(self_start, prefix_start, prefix_len) == 0)
{
return PyBytes_FromStringAndSize(self_start + prefix_len,
self_len - prefix_len);
}
if (PyBytes_CheckExact(self)) {
Py_INCREF(self);
return (PyObject *)self;
}
return PyBytes_FromStringAndSize(self_start, self_len);
}
/*[clinic input]
bytes.removesuffix as bytes_removesuffix
suffix: Py_buffer
/
Return a bytes object with the given suffix string removed if present.
If the bytes ends with the suffix string and that suffix is not empty,
return bytes[:-len(prefix)]. Otherwise, return a copy of the original
bytes.
[clinic start generated code]*/
static PyObject *
bytes_removesuffix_impl(PyBytesObject *self, Py_buffer *suffix)
/*[clinic end generated code: output=d887d308e3242eeb input=9f4e1da8c637bbf1]*/
{
const char *self_start = PyBytes_AS_STRING(self);
Py_ssize_t self_len = PyBytes_GET_SIZE(self);
const char *suffix_start = suffix->buf;
Py_ssize_t suffix_len = suffix->len;
if (self_len >= suffix_len
&& suffix_len > 0
&& memcmp(self_start + self_len - suffix_len,
suffix_start, suffix_len) == 0)
{
return PyBytes_FromStringAndSize(self_start,
self_len - suffix_len);
}
if (PyBytes_CheckExact(self)) {
Py_INCREF(self);
return (PyObject *)self;
}
return PyBytes_FromStringAndSize(self_start, self_len);
}
static PyObject * static PyObject *
bytes_startswith(PyBytesObject *self, PyObject *args) bytes_startswith(PyBytesObject *self, PyObject *args)
@ -2421,6 +2496,8 @@ bytes_methods[] = {
BYTES_MAKETRANS_METHODDEF BYTES_MAKETRANS_METHODDEF
BYTES_PARTITION_METHODDEF BYTES_PARTITION_METHODDEF
BYTES_REPLACE_METHODDEF BYTES_REPLACE_METHODDEF
BYTES_REMOVEPREFIX_METHODDEF
BYTES_REMOVESUFFIX_METHODDEF
{"rfind", (PyCFunction)bytes_rfind, METH_VARARGS, _Py_rfind__doc__}, {"rfind", (PyCFunction)bytes_rfind, METH_VARARGS, _Py_rfind__doc__},
{"rindex", (PyCFunction)bytes_rindex, METH_VARARGS, _Py_rindex__doc__}, {"rindex", (PyCFunction)bytes_rindex, METH_VARARGS, _Py_rindex__doc__},
STRINGLIB_RJUST_METHODDEF STRINGLIB_RJUST_METHODDEF

View File

@ -38,6 +38,86 @@ bytearray_copy(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
return bytearray_copy_impl(self); return bytearray_copy_impl(self);
} }
PyDoc_STRVAR(bytearray_removeprefix__doc__,
"removeprefix($self, prefix, /)\n"
"--\n"
"\n"
"Return a bytearray with the given prefix string removed if present.\n"
"\n"
"If the bytearray starts with the prefix string, return\n"
"bytearray[len(prefix):]. Otherwise, return a copy of the original\n"
"bytearray.");
#define BYTEARRAY_REMOVEPREFIX_METHODDEF \
{"removeprefix", (PyCFunction)bytearray_removeprefix, METH_O, bytearray_removeprefix__doc__},
static PyObject *
bytearray_removeprefix_impl(PyByteArrayObject *self, Py_buffer *prefix);
static PyObject *
bytearray_removeprefix(PyByteArrayObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
Py_buffer prefix = {NULL, NULL};
if (PyObject_GetBuffer(arg, &prefix, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!PyBuffer_IsContiguous(&prefix, 'C')) {
_PyArg_BadArgument("removeprefix", "argument", "contiguous buffer", arg);
goto exit;
}
return_value = bytearray_removeprefix_impl(self, &prefix);
exit:
/* Cleanup for prefix */
if (prefix.obj) {
PyBuffer_Release(&prefix);
}
return return_value;
}
PyDoc_STRVAR(bytearray_removesuffix__doc__,
"removesuffix($self, suffix, /)\n"
"--\n"
"\n"
"Return a bytearray with the given suffix string removed if present.\n"
"\n"
"If the bytearray ends with the suffix string and that suffix is not\n"
"empty, return bytearray[:-len(suffix)]. Otherwise, return a copy of\n"
"the original bytearray.");
#define BYTEARRAY_REMOVESUFFIX_METHODDEF \
{"removesuffix", (PyCFunction)bytearray_removesuffix, METH_O, bytearray_removesuffix__doc__},
static PyObject *
bytearray_removesuffix_impl(PyByteArrayObject *self, Py_buffer *suffix);
static PyObject *
bytearray_removesuffix(PyByteArrayObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
Py_buffer suffix = {NULL, NULL};
if (PyObject_GetBuffer(arg, &suffix, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!PyBuffer_IsContiguous(&suffix, 'C')) {
_PyArg_BadArgument("removesuffix", "argument", "contiguous buffer", arg);
goto exit;
}
return_value = bytearray_removesuffix_impl(self, &suffix);
exit:
/* Cleanup for suffix */
if (suffix.obj) {
PyBuffer_Release(&suffix);
}
return return_value;
}
PyDoc_STRVAR(bytearray_translate__doc__, PyDoc_STRVAR(bytearray_translate__doc__,
"translate($self, table, /, delete=b\'\')\n" "translate($self, table, /, delete=b\'\')\n"
"--\n" "--\n"
@ -1011,4 +1091,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored))
{ {
return bytearray_sizeof_impl(self); return bytearray_sizeof_impl(self);
} }
/*[clinic end generated code: output=508dce79cf2dffcc input=a9049054013a1b77]*/ /*[clinic end generated code: output=b2919f76709e48dc input=a9049054013a1b77]*/

View File

@ -526,6 +526,85 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(bytes_removeprefix__doc__,
"removeprefix($self, prefix, /)\n"
"--\n"
"\n"
"Return a bytes object with the given prefix string removed if present.\n"
"\n"
"If the bytes starts with the prefix string, return bytes[len(prefix):].\n"
"Otherwise, return a copy of the original bytes.");
#define BYTES_REMOVEPREFIX_METHODDEF \
{"removeprefix", (PyCFunction)bytes_removeprefix, METH_O, bytes_removeprefix__doc__},
static PyObject *
bytes_removeprefix_impl(PyBytesObject *self, Py_buffer *prefix);
static PyObject *
bytes_removeprefix(PyBytesObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
Py_buffer prefix = {NULL, NULL};
if (PyObject_GetBuffer(arg, &prefix, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!PyBuffer_IsContiguous(&prefix, 'C')) {
_PyArg_BadArgument("removeprefix", "argument", "contiguous buffer", arg);
goto exit;
}
return_value = bytes_removeprefix_impl(self, &prefix);
exit:
/* Cleanup for prefix */
if (prefix.obj) {
PyBuffer_Release(&prefix);
}
return return_value;
}
PyDoc_STRVAR(bytes_removesuffix__doc__,
"removesuffix($self, suffix, /)\n"
"--\n"
"\n"
"Return a bytes object with the given suffix string removed if present.\n"
"\n"
"If the bytes ends with the suffix string and that suffix is not empty,\n"
"return bytes[:-len(prefix)]. Otherwise, return a copy of the original\n"
"bytes.");
#define BYTES_REMOVESUFFIX_METHODDEF \
{"removesuffix", (PyCFunction)bytes_removesuffix, METH_O, bytes_removesuffix__doc__},
static PyObject *
bytes_removesuffix_impl(PyBytesObject *self, Py_buffer *suffix);
static PyObject *
bytes_removesuffix(PyBytesObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
Py_buffer suffix = {NULL, NULL};
if (PyObject_GetBuffer(arg, &suffix, PyBUF_SIMPLE) != 0) {
goto exit;
}
if (!PyBuffer_IsContiguous(&suffix, 'C')) {
_PyArg_BadArgument("removesuffix", "argument", "contiguous buffer", arg);
goto exit;
}
return_value = bytes_removesuffix_impl(self, &suffix);
exit:
/* Cleanup for suffix */
if (suffix.obj) {
PyBuffer_Release(&suffix);
}
return return_value;
}
PyDoc_STRVAR(bytes_decode__doc__, PyDoc_STRVAR(bytes_decode__doc__,
"decode($self, /, encoding=\'utf-8\', errors=\'strict\')\n" "decode($self, /, encoding=\'utf-8\', errors=\'strict\')\n"
"--\n" "--\n"
@ -755,4 +834,4 @@ skip_optional_pos:
exit: exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=ca60dfccf8d51e88 input=a9049054013a1b77]*/ /*[clinic end generated code: output=220388917d7bf751 input=a9049054013a1b77]*/

View File

@ -754,6 +754,77 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(unicode_removeprefix__doc__,
"removeprefix($self, prefix, /)\n"
"--\n"
"\n"
"Return a str with the given prefix string removed if present.\n"
"\n"
"If the string starts with the prefix string, return string[len(prefix):].\n"
"Otherwise, return a copy of the original string.");
#define UNICODE_REMOVEPREFIX_METHODDEF \
{"removeprefix", (PyCFunction)unicode_removeprefix, METH_O, unicode_removeprefix__doc__},
static PyObject *
unicode_removeprefix_impl(PyObject *self, PyObject *prefix);
static PyObject *
unicode_removeprefix(PyObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
PyObject *prefix;
if (!PyUnicode_Check(arg)) {
_PyArg_BadArgument("removeprefix", "argument", "str", arg);
goto exit;
}
if (PyUnicode_READY(arg) == -1) {
goto exit;
}
prefix = arg;
return_value = unicode_removeprefix_impl(self, prefix);
exit:
return return_value;
}
PyDoc_STRVAR(unicode_removesuffix__doc__,
"removesuffix($self, suffix, /)\n"
"--\n"
"\n"
"Return a str with the given suffix string removed if present.\n"
"\n"
"If the string ends with the suffix string and that suffix is not empty,\n"
"return string[:-len(suffix)]. Otherwise, return a copy of the original\n"
"string.");
#define UNICODE_REMOVESUFFIX_METHODDEF \
{"removesuffix", (PyCFunction)unicode_removesuffix, METH_O, unicode_removesuffix__doc__},
static PyObject *
unicode_removesuffix_impl(PyObject *self, PyObject *suffix);
static PyObject *
unicode_removesuffix(PyObject *self, PyObject *arg)
{
PyObject *return_value = NULL;
PyObject *suffix;
if (!PyUnicode_Check(arg)) {
_PyArg_BadArgument("removesuffix", "argument", "str", arg);
goto exit;
}
if (PyUnicode_READY(arg) == -1) {
goto exit;
}
suffix = arg;
return_value = unicode_removesuffix_impl(self, suffix);
exit:
return return_value;
}
PyDoc_STRVAR(unicode_rjust__doc__, PyDoc_STRVAR(unicode_rjust__doc__,
"rjust($self, width, fillchar=\' \', /)\n" "rjust($self, width, fillchar=\' \', /)\n"
"--\n" "--\n"
@ -1232,4 +1303,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored))
{ {
return unicode_sizeof_impl(self); return unicode_sizeof_impl(self);
} }
/*[clinic end generated code: output=e4ed33400979c7e8 input=a9049054013a1b77]*/ /*[clinic end generated code: output=b91233f3722643be input=a9049054013a1b77]*/

View File

@ -12789,6 +12789,61 @@ unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new,
return replace(self, old, new, count); return replace(self, old, new, count);
} }
/*[clinic input]
str.removeprefix as unicode_removeprefix
prefix: unicode
/
Return a str with the given prefix string removed if present.
If the string starts with the prefix string, return string[len(prefix):].
Otherwise, return a copy of the original string.
[clinic start generated code]*/
static PyObject *
unicode_removeprefix_impl(PyObject *self, PyObject *prefix)
/*[clinic end generated code: output=f1e5945e9763bcb9 input=27ec40b99a37eb88]*/
{
int match = tailmatch(self, prefix, 0, PY_SSIZE_T_MAX, -1);
if (match == -1) {
return NULL;
}
if (match) {
return PyUnicode_Substring(self, PyUnicode_GET_LENGTH(prefix),
PyUnicode_GET_LENGTH(self));
}
return unicode_result_unchanged(self);
}
/*[clinic input]
str.removesuffix as unicode_removesuffix
suffix: unicode
/
Return a str with the given suffix string removed if present.
If the string ends with the suffix string and that suffix is not empty,
return string[:-len(suffix)]. Otherwise, return a copy of the original
string.
[clinic start generated code]*/
static PyObject *
unicode_removesuffix_impl(PyObject *self, PyObject *suffix)
/*[clinic end generated code: output=d36629e227636822 input=12cc32561e769be4]*/
{
int match = tailmatch(self, suffix, 0, PY_SSIZE_T_MAX, +1);
if (match == -1) {
return NULL;
}
if (match) {
return PyUnicode_Substring(self, 0, PyUnicode_GET_LENGTH(self)
- PyUnicode_GET_LENGTH(suffix));
}
return unicode_result_unchanged(self);
}
static PyObject * static PyObject *
unicode_repr(PyObject *unicode) unicode_repr(PyObject *unicode)
{ {
@ -14105,6 +14160,8 @@ static PyMethodDef unicode_methods[] = {
UNICODE_UPPER_METHODDEF UNICODE_UPPER_METHODDEF
{"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__}, {"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__},
{"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__}, {"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__},
UNICODE_REMOVEPREFIX_METHODDEF
UNICODE_REMOVESUFFIX_METHODDEF
UNICODE_ISASCII_METHODDEF UNICODE_ISASCII_METHODDEF
UNICODE_ISLOWER_METHODDEF UNICODE_ISLOWER_METHODDEF
UNICODE_ISUPPER_METHODDEF UNICODE_ISUPPER_METHODDEF