mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
Bug #1515471: string.replace() accepts character buffers again.
Pass the char* and size around rather than PyObject's.
This commit is contained in:
parent
07aadb14f3
commit
f71ec5a0ac
3 changed files with 60 additions and 73 deletions
|
@ -147,8 +147,8 @@ class CommonTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
r2, rem = len(i)+1, 0
|
r2, rem = len(i)+1, 0
|
||||||
if rem or r1 != r2:
|
if rem or r1 != r2:
|
||||||
self.assertEqual(rem, 0)
|
self.assertEqual(rem, 0, '%s != 0 for %s' % (rem, i))
|
||||||
self.assertEqual(r1, r2)
|
self.assertEqual(r1, r2, '%s != %s for %s' % (r1, r2, i))
|
||||||
|
|
||||||
def test_find(self):
|
def test_find(self):
|
||||||
self.checkequal(0, 'abcdefghiabc', 'find', 'abc')
|
self.checkequal(0, 'abcdefghiabc', 'find', 'abc')
|
||||||
|
@ -636,6 +636,11 @@ class CommonTest(unittest.TestCase):
|
||||||
EQ("bobobXbobob", "bobobobXbobobob", "replace", "bobob", "bob")
|
EQ("bobobXbobob", "bobobobXbobobob", "replace", "bobob", "bob")
|
||||||
EQ("BOBOBOB", "BOBOBOB", "replace", "bob", "bobby")
|
EQ("BOBOBOB", "BOBOBOB", "replace", "bob", "bobby")
|
||||||
|
|
||||||
|
ba = buffer('a')
|
||||||
|
bb = buffer('b')
|
||||||
|
EQ("bbc", "abc", "replace", ba, bb)
|
||||||
|
EQ("aac", "abc", "replace", bb, ba)
|
||||||
|
|
||||||
#
|
#
|
||||||
self.checkequal('one@two!three!', 'one!two!three!', 'replace', '!', '@', 1)
|
self.checkequal('one@two!three!', 'one!two!three!', 'replace', '!', '@', 1)
|
||||||
self.checkequal('onetwothree', 'one!two!three!', 'replace', '!', '')
|
self.checkequal('onetwothree', 'one!two!three!', 'replace', '!', '')
|
||||||
|
|
|
@ -12,6 +12,8 @@ What's New in Python 2.5 beta 3?
|
||||||
Core and builtins
|
Core and builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Bug #1515471: string.replace() accepts character buffers again.
|
||||||
|
|
||||||
- Add PyErr_WarnEx() so C code can pass the stacklevel to warnings.warn().
|
- Add PyErr_WarnEx() so C code can pass the stacklevel to warnings.warn().
|
||||||
This provides the proper warning for struct.pack().
|
This provides the proper warning for struct.pack().
|
||||||
PyErr_Warn() is now deprecated in favor of PyErr_WarnEx().
|
PyErr_Warn() is now deprecated in favor of PyErr_WarnEx().
|
||||||
|
|
|
@ -2464,11 +2464,11 @@ return_self(PyStringObject *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_LOCAL_INLINE(Py_ssize_t)
|
Py_LOCAL_INLINE(Py_ssize_t)
|
||||||
countchar(char *target, int target_len, char c, Py_ssize_t maxcount)
|
countchar(const char *target, int target_len, char c, Py_ssize_t maxcount)
|
||||||
{
|
{
|
||||||
Py_ssize_t count=0;
|
Py_ssize_t count=0;
|
||||||
char *start=target;
|
const char *start=target;
|
||||||
char *end=target+target_len;
|
const char *end=target+target_len;
|
||||||
|
|
||||||
while ( (start=findchar(start, end-start, c)) != NULL ) {
|
while ( (start=findchar(start, end-start, c)) != NULL ) {
|
||||||
count++;
|
count++;
|
||||||
|
@ -2480,8 +2480,8 @@ countchar(char *target, int target_len, char c, Py_ssize_t maxcount)
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_LOCAL(Py_ssize_t)
|
Py_LOCAL(Py_ssize_t)
|
||||||
findstring(char *target, Py_ssize_t target_len,
|
findstring(const char *target, Py_ssize_t target_len,
|
||||||
char *pattern, Py_ssize_t pattern_len,
|
const char *pattern, Py_ssize_t pattern_len,
|
||||||
Py_ssize_t start,
|
Py_ssize_t start,
|
||||||
Py_ssize_t end,
|
Py_ssize_t end,
|
||||||
int direction)
|
int direction)
|
||||||
|
@ -2518,8 +2518,8 @@ findstring(char *target, Py_ssize_t target_len,
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_LOCAL_INLINE(Py_ssize_t)
|
Py_LOCAL_INLINE(Py_ssize_t)
|
||||||
countstring(char *target, Py_ssize_t target_len,
|
countstring(const char *target, Py_ssize_t target_len,
|
||||||
char *pattern, Py_ssize_t pattern_len,
|
const char *pattern, Py_ssize_t pattern_len,
|
||||||
Py_ssize_t start,
|
Py_ssize_t start,
|
||||||
Py_ssize_t end,
|
Py_ssize_t end,
|
||||||
int direction, Py_ssize_t maxcount)
|
int direction, Py_ssize_t maxcount)
|
||||||
|
@ -2572,16 +2572,15 @@ countstring(char *target, Py_ssize_t target_len,
|
||||||
/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
|
/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
|
||||||
Py_LOCAL(PyStringObject *)
|
Py_LOCAL(PyStringObject *)
|
||||||
replace_interleave(PyStringObject *self,
|
replace_interleave(PyStringObject *self,
|
||||||
PyStringObject *to,
|
const char *to_s, Py_ssize_t to_len,
|
||||||
Py_ssize_t maxcount)
|
Py_ssize_t maxcount)
|
||||||
{
|
{
|
||||||
char *self_s, *to_s, *result_s;
|
char *self_s, *result_s;
|
||||||
Py_ssize_t self_len, to_len, result_len;
|
Py_ssize_t self_len, result_len;
|
||||||
Py_ssize_t count, i, product;
|
Py_ssize_t count, i, product;
|
||||||
PyStringObject *result;
|
PyStringObject *result;
|
||||||
|
|
||||||
self_len = PyString_GET_SIZE(self);
|
self_len = PyString_GET_SIZE(self);
|
||||||
to_len = PyString_GET_SIZE(to);
|
|
||||||
|
|
||||||
/* 1 at the end plus 1 after every character */
|
/* 1 at the end plus 1 after every character */
|
||||||
count = self_len+1;
|
count = self_len+1;
|
||||||
|
@ -2608,8 +2607,6 @@ replace_interleave(PyStringObject *self,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
self_s = PyString_AS_STRING(self);
|
self_s = PyString_AS_STRING(self);
|
||||||
to_s = PyString_AS_STRING(to);
|
|
||||||
to_len = PyString_GET_SIZE(to);
|
|
||||||
result_s = PyString_AS_STRING(result);
|
result_s = PyString_AS_STRING(result);
|
||||||
|
|
||||||
/* TODO: special case single character, which doesn't need memcpy */
|
/* TODO: special case single character, which doesn't need memcpy */
|
||||||
|
@ -2677,18 +2674,17 @@ replace_delete_single_character(PyStringObject *self,
|
||||||
/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
|
/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
|
||||||
|
|
||||||
Py_LOCAL(PyStringObject *)
|
Py_LOCAL(PyStringObject *)
|
||||||
replace_delete_substring(PyStringObject *self, PyStringObject *from,
|
replace_delete_substring(PyStringObject *self,
|
||||||
|
const char *from_s, Py_ssize_t from_len,
|
||||||
Py_ssize_t maxcount) {
|
Py_ssize_t maxcount) {
|
||||||
char *self_s, *from_s, *result_s;
|
char *self_s, *result_s;
|
||||||
char *start, *next, *end;
|
char *start, *next, *end;
|
||||||
Py_ssize_t self_len, from_len, result_len;
|
Py_ssize_t self_len, result_len;
|
||||||
Py_ssize_t count, offset;
|
Py_ssize_t count, offset;
|
||||||
PyStringObject *result;
|
PyStringObject *result;
|
||||||
|
|
||||||
self_len = PyString_GET_SIZE(self);
|
self_len = PyString_GET_SIZE(self);
|
||||||
self_s = PyString_AS_STRING(self);
|
self_s = PyString_AS_STRING(self);
|
||||||
from_len = PyString_GET_SIZE(from);
|
|
||||||
from_s = PyString_AS_STRING(from);
|
|
||||||
|
|
||||||
count = countstring(self_s, self_len,
|
count = countstring(self_s, self_len,
|
||||||
from_s, from_len,
|
from_s, from_len,
|
||||||
|
@ -2776,24 +2772,20 @@ replace_single_character_in_place(PyStringObject *self,
|
||||||
/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
|
/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
|
||||||
Py_LOCAL(PyStringObject *)
|
Py_LOCAL(PyStringObject *)
|
||||||
replace_substring_in_place(PyStringObject *self,
|
replace_substring_in_place(PyStringObject *self,
|
||||||
PyStringObject *from,
|
const char *from_s, Py_ssize_t from_len,
|
||||||
PyStringObject *to,
|
const char *to_s, Py_ssize_t to_len,
|
||||||
Py_ssize_t maxcount)
|
Py_ssize_t maxcount)
|
||||||
{
|
{
|
||||||
char *result_s, *start, *end;
|
char *result_s, *start, *end;
|
||||||
char *self_s, *from_s, *to_s;
|
char *self_s;
|
||||||
Py_ssize_t self_len, from_len, offset;
|
Py_ssize_t self_len, offset;
|
||||||
PyStringObject *result;
|
PyStringObject *result;
|
||||||
|
|
||||||
/* The result string will be the same size */
|
/* The result string will be the same size */
|
||||||
|
|
||||||
self_s = PyString_AS_STRING(self);
|
self_s = PyString_AS_STRING(self);
|
||||||
self_len = PyString_GET_SIZE(self);
|
self_len = PyString_GET_SIZE(self);
|
||||||
|
|
||||||
from_s = PyString_AS_STRING(from);
|
|
||||||
from_len = PyString_GET_SIZE(from);
|
|
||||||
to_s = PyString_AS_STRING(to);
|
|
||||||
|
|
||||||
offset = findstring(self_s, self_len,
|
offset = findstring(self_s, self_len,
|
||||||
from_s, from_len,
|
from_s, from_len,
|
||||||
0, self_len, FORWARD);
|
0, self_len, FORWARD);
|
||||||
|
@ -2810,7 +2802,6 @@ replace_substring_in_place(PyStringObject *self,
|
||||||
result_s = PyString_AS_STRING(result);
|
result_s = PyString_AS_STRING(result);
|
||||||
Py_MEMCPY(result_s, self_s, self_len);
|
Py_MEMCPY(result_s, self_s, self_len);
|
||||||
|
|
||||||
|
|
||||||
/* change everything in-place, starting with this one */
|
/* change everything in-place, starting with this one */
|
||||||
start = result_s + offset;
|
start = result_s + offset;
|
||||||
Py_MEMCPY(start, to_s, from_len);
|
Py_MEMCPY(start, to_s, from_len);
|
||||||
|
@ -2834,12 +2825,12 @@ replace_substring_in_place(PyStringObject *self,
|
||||||
Py_LOCAL(PyStringObject *)
|
Py_LOCAL(PyStringObject *)
|
||||||
replace_single_character(PyStringObject *self,
|
replace_single_character(PyStringObject *self,
|
||||||
char from_c,
|
char from_c,
|
||||||
PyStringObject *to,
|
const char *to_s, Py_ssize_t to_len,
|
||||||
Py_ssize_t maxcount)
|
Py_ssize_t maxcount)
|
||||||
{
|
{
|
||||||
char *self_s, *to_s, *result_s;
|
char *self_s, *result_s;
|
||||||
char *start, *next, *end;
|
char *start, *next, *end;
|
||||||
Py_ssize_t self_len, to_len, result_len;
|
Py_ssize_t self_len, result_len;
|
||||||
Py_ssize_t count, product;
|
Py_ssize_t count, product;
|
||||||
PyStringObject *result;
|
PyStringObject *result;
|
||||||
|
|
||||||
|
@ -2852,10 +2843,7 @@ replace_single_character(PyStringObject *self,
|
||||||
/* no matches, return unchanged */
|
/* no matches, return unchanged */
|
||||||
return return_self(self);
|
return return_self(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
to_s = PyString_AS_STRING(to);
|
|
||||||
to_len = PyString_GET_SIZE(to);
|
|
||||||
|
|
||||||
/* use the difference between current and new, hence the "-1" */
|
/* use the difference between current and new, hence the "-1" */
|
||||||
/* result_len = self_len + count * (to_len-1) */
|
/* result_len = self_len + count * (to_len-1) */
|
||||||
product = count * (to_len-1);
|
product = count * (to_len-1);
|
||||||
|
@ -2904,20 +2892,18 @@ replace_single_character(PyStringObject *self,
|
||||||
/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
|
/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
|
||||||
Py_LOCAL(PyStringObject *)
|
Py_LOCAL(PyStringObject *)
|
||||||
replace_substring(PyStringObject *self,
|
replace_substring(PyStringObject *self,
|
||||||
PyStringObject *from,
|
const char *from_s, Py_ssize_t from_len,
|
||||||
PyStringObject *to,
|
const char *to_s, Py_ssize_t to_len,
|
||||||
Py_ssize_t maxcount) {
|
Py_ssize_t maxcount) {
|
||||||
char *self_s, *from_s, *to_s, *result_s;
|
char *self_s, *result_s;
|
||||||
char *start, *next, *end;
|
char *start, *next, *end;
|
||||||
Py_ssize_t self_len, from_len, to_len, result_len;
|
Py_ssize_t self_len, result_len;
|
||||||
Py_ssize_t count, offset, product;
|
Py_ssize_t count, offset, product;
|
||||||
PyStringObject *result;
|
PyStringObject *result;
|
||||||
|
|
||||||
self_s = PyString_AS_STRING(self);
|
self_s = PyString_AS_STRING(self);
|
||||||
self_len = PyString_GET_SIZE(self);
|
self_len = PyString_GET_SIZE(self);
|
||||||
from_s = PyString_AS_STRING(from);
|
|
||||||
from_len = PyString_GET_SIZE(from);
|
|
||||||
|
|
||||||
count = countstring(self_s, self_len,
|
count = countstring(self_s, self_len,
|
||||||
from_s, from_len,
|
from_s, from_len,
|
||||||
0, self_len, FORWARD, maxcount);
|
0, self_len, FORWARD, maxcount);
|
||||||
|
@ -2925,10 +2911,7 @@ replace_substring(PyStringObject *self,
|
||||||
/* no matches, return unchanged */
|
/* no matches, return unchanged */
|
||||||
return return_self(self);
|
return return_self(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
to_s = PyString_AS_STRING(to);
|
|
||||||
to_len = PyString_GET_SIZE(to);
|
|
||||||
|
|
||||||
/* Check for overflow */
|
/* Check for overflow */
|
||||||
/* result_len = self_len + count * (to_len-from_len) */
|
/* result_len = self_len + count * (to_len-from_len) */
|
||||||
product = count * (to_len-from_len);
|
product = count * (to_len-from_len);
|
||||||
|
@ -2979,22 +2962,17 @@ replace_substring(PyStringObject *self,
|
||||||
|
|
||||||
Py_LOCAL(PyStringObject *)
|
Py_LOCAL(PyStringObject *)
|
||||||
replace(PyStringObject *self,
|
replace(PyStringObject *self,
|
||||||
PyStringObject *from,
|
const char *from_s, Py_ssize_t from_len,
|
||||||
PyStringObject *to,
|
const char *to_s, Py_ssize_t to_len,
|
||||||
Py_ssize_t maxcount)
|
Py_ssize_t maxcount)
|
||||||
{
|
{
|
||||||
Py_ssize_t from_len, to_len;
|
|
||||||
|
|
||||||
if (maxcount < 0) {
|
if (maxcount < 0) {
|
||||||
maxcount = PY_SSIZE_T_MAX;
|
maxcount = PY_SSIZE_T_MAX;
|
||||||
} else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) {
|
} else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) {
|
||||||
/* nothing to do; return the original string */
|
/* nothing to do; return the original string */
|
||||||
return return_self(self);
|
return return_self(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
from_len = PyString_GET_SIZE(from);
|
|
||||||
to_len = PyString_GET_SIZE(to);
|
|
||||||
|
|
||||||
if (maxcount == 0 ||
|
if (maxcount == 0 ||
|
||||||
(from_len == 0 && to_len == 0)) {
|
(from_len == 0 && to_len == 0)) {
|
||||||
/* nothing to do; return the original string */
|
/* nothing to do; return the original string */
|
||||||
|
@ -3007,7 +2985,7 @@ replace(PyStringObject *self,
|
||||||
/* insert the 'to' string everywhere. */
|
/* insert the 'to' string everywhere. */
|
||||||
/* >>> "Python".replace("", ".") */
|
/* >>> "Python".replace("", ".") */
|
||||||
/* '.P.y.t.h.o.n.' */
|
/* '.P.y.t.h.o.n.' */
|
||||||
return replace_interleave(self, to, maxcount);
|
return replace_interleave(self, to_s, to_len, maxcount);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Except for "".replace("", "A") == "A" there is no way beyond this */
|
/* Except for "".replace("", "A") == "A" there is no way beyond this */
|
||||||
|
@ -3021,9 +2999,9 @@ replace(PyStringObject *self,
|
||||||
/* delete all occurances of 'from' string */
|
/* delete all occurances of 'from' string */
|
||||||
if (from_len == 1) {
|
if (from_len == 1) {
|
||||||
return replace_delete_single_character(
|
return replace_delete_single_character(
|
||||||
self, PyString_AS_STRING(from)[0], maxcount);
|
self, from_s[0], maxcount);
|
||||||
} else {
|
} else {
|
||||||
return replace_delete_substring(self, from, maxcount);
|
return replace_delete_substring(self, from_s, from_len, maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3033,22 +3011,22 @@ replace(PyStringObject *self,
|
||||||
if (from_len == 1) {
|
if (from_len == 1) {
|
||||||
return replace_single_character_in_place(
|
return replace_single_character_in_place(
|
||||||
self,
|
self,
|
||||||
PyString_AS_STRING(from)[0],
|
from_s[0],
|
||||||
PyString_AS_STRING(to)[0],
|
to_s[0],
|
||||||
maxcount);
|
maxcount);
|
||||||
} else {
|
} else {
|
||||||
return replace_substring_in_place(
|
return replace_substring_in_place(
|
||||||
self, from, to, maxcount);
|
self, from_s, from_len, to_s, to_len, maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise use the more generic algorithms */
|
/* Otherwise use the more generic algorithms */
|
||||||
if (from_len == 1) {
|
if (from_len == 1) {
|
||||||
return replace_single_character(self, PyString_AS_STRING(from)[0],
|
return replace_single_character(self, from_s[0],
|
||||||
to, maxcount);
|
to_s, to_len, maxcount);
|
||||||
} else {
|
} else {
|
||||||
/* len('from')>=2, len('to')>=1 */
|
/* len('from')>=2, len('to')>=1 */
|
||||||
return replace_substring(self, from, to, maxcount);
|
return replace_substring(self, from_s, from_len, to_s, to_len, maxcount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3064,37 +3042,39 @@ string_replace(PyStringObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
Py_ssize_t count = -1;
|
Py_ssize_t count = -1;
|
||||||
PyObject *from, *to;
|
PyObject *from, *to;
|
||||||
const char *tmp_s;
|
const char *from_s, *to_s;
|
||||||
Py_ssize_t tmp_len;
|
Py_ssize_t from_len, to_len;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
|
if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (PyString_Check(from)) {
|
if (PyString_Check(from)) {
|
||||||
/* Can this be made a '!check' after the Unicode check? */
|
from_s = PyString_AS_STRING(from);
|
||||||
|
from_len = PyString_GET_SIZE(from);
|
||||||
}
|
}
|
||||||
#ifdef Py_USING_UNICODE
|
#ifdef Py_USING_UNICODE
|
||||||
if (PyUnicode_Check(from))
|
if (PyUnicode_Check(from))
|
||||||
return PyUnicode_Replace((PyObject *)self,
|
return PyUnicode_Replace((PyObject *)self,
|
||||||
from, to, count);
|
from, to, count);
|
||||||
#endif
|
#endif
|
||||||
else if (PyObject_AsCharBuffer(from, &tmp_s, &tmp_len))
|
else if (PyObject_AsCharBuffer(from, &from_s, &from_len))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (PyString_Check(to)) {
|
if (PyString_Check(to)) {
|
||||||
/* Can this be made a '!check' after the Unicode check? */
|
to_s = PyString_AS_STRING(to);
|
||||||
|
to_len = PyString_GET_SIZE(to);
|
||||||
}
|
}
|
||||||
#ifdef Py_USING_UNICODE
|
#ifdef Py_USING_UNICODE
|
||||||
else if (PyUnicode_Check(to))
|
else if (PyUnicode_Check(to))
|
||||||
return PyUnicode_Replace((PyObject *)self,
|
return PyUnicode_Replace((PyObject *)self,
|
||||||
from, to, count);
|
from, to, count);
|
||||||
#endif
|
#endif
|
||||||
else if (PyObject_AsCharBuffer(to, &tmp_s, &tmp_len))
|
else if (PyObject_AsCharBuffer(to, &to_s, &to_len))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return (PyObject *)replace((PyStringObject *) self,
|
return (PyObject *)replace((PyStringObject *) self,
|
||||||
(PyStringObject *) from,
|
from_s, from_len,
|
||||||
(PyStringObject *) to, count);
|
to_s, to_len, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** End DALKE **/
|
/** End DALKE **/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue