Skip to content

Commit e330862

Browse files
author
facundo.batista
committed
Now in find, rfind, index, and rindex, you can use None as defaults, as usual with slicing (both with str and unicode strings). This fixes issue 1259. For str only the stringobject.c file was modified. But for unicode, I needed to repeat in the four functions a lot of code, so created a new function that does part of the job for them (and placed it in find.h, following a suggestion of Barry). Also added tests for this behaviour. git-svn-id: http://svn.python.org/projects/python/trunk@59020 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 0533486 commit e330862

4 files changed

Lines changed: 102 additions & 32 deletions

File tree

Lib/test/string_tests.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,13 @@ def test_find(self):
159159
self.checkequal(3, 'abc', 'find', '', 3)
160160
self.checkequal(-1, 'abc', 'find', '', 4)
161161

162+
# to check the ability to pass None as defaults
163+
self.checkequal( 2, 'rrarrrrrrrrra', 'find', 'a')
164+
self.checkequal(12, 'rrarrrrrrrrra', 'find', 'a', 4)
165+
self.checkequal(-1, 'rrarrrrrrrrra', 'find', 'a', 4, 6)
166+
self.checkequal(12, 'rrarrrrrrrrra', 'find', 'a', 4, None)
167+
self.checkequal( 2, 'rrarrrrrrrrra', 'find', 'a', None, 6)
168+
162169
self.checkraises(TypeError, 'hello', 'find')
163170
self.checkraises(TypeError, 'hello', 'find', 42)
164171

@@ -197,6 +204,13 @@ def test_rfind(self):
197204
self.checkequal(3, 'abc', 'rfind', '', 3)
198205
self.checkequal(-1, 'abc', 'rfind', '', 4)
199206

207+
# to check the ability to pass None as defaults
208+
self.checkequal(12, 'rrarrrrrrrrra', 'rfind', 'a')
209+
self.checkequal(12, 'rrarrrrrrrrra', 'rfind', 'a', 4)
210+
self.checkequal(-1, 'rrarrrrrrrrra', 'rfind', 'a', 4, 6)
211+
self.checkequal(12, 'rrarrrrrrrrra', 'rfind', 'a', 4, None)
212+
self.checkequal( 2, 'rrarrrrrrrrra', 'rfind', 'a', None, 6)
213+
200214
self.checkraises(TypeError, 'hello', 'rfind')
201215
self.checkraises(TypeError, 'hello', 'rfind', 42)
202216

@@ -211,6 +225,13 @@ def test_index(self):
211225
self.checkraises(ValueError, 'abcdefghi', 'index', 'ghi', 8)
212226
self.checkraises(ValueError, 'abcdefghi', 'index', 'ghi', -1)
213227

228+
# to check the ability to pass None as defaults
229+
self.checkequal( 2, 'rrarrrrrrrrra', 'index', 'a')
230+
self.checkequal(12, 'rrarrrrrrrrra', 'index', 'a', 4)
231+
self.checkraises(ValueError, 'rrarrrrrrrrra', 'index', 'a', 4, 6)
232+
self.checkequal(12, 'rrarrrrrrrrra', 'index', 'a', 4, None)
233+
self.checkequal( 2, 'rrarrrrrrrrra', 'index', 'a', None, 6)
234+
214235
self.checkraises(TypeError, 'hello', 'index')
215236
self.checkraises(TypeError, 'hello', 'index', 42)
216237

@@ -226,6 +247,13 @@ def test_rindex(self):
226247
self.checkraises(ValueError, 'abcdefghi', 'rindex', 'ghi', 0, 8)
227248
self.checkraises(ValueError, 'abcdefghi', 'rindex', 'ghi', 0, -1)
228249

250+
# to check the ability to pass None as defaults
251+
self.checkequal(12, 'rrarrrrrrrrra', 'rindex', 'a')
252+
self.checkequal(12, 'rrarrrrrrrrra', 'rindex', 'a', 4)
253+
self.checkraises(ValueError, 'rrarrrrrrrrra', 'rindex', 'a', 4, 6)
254+
self.checkequal(12, 'rrarrrrrrrrra', 'rindex', 'a', 4, None)
255+
self.checkequal( 2, 'rrarrrrrrrrra', 'rindex', 'a', None, 6)
256+
229257
self.checkraises(TypeError, 'hello', 'rindex')
230258
self.checkraises(TypeError, 'hello', 'rindex', 42)
231259

Objects/stringlib/find.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,53 @@ stringlib_contains_obj(PyObject* str, PyObject* sub)
103103

104104
#endif /* STRINGLIB_STR */
105105

106+
/*
107+
This function is a helper for the "find" family (find, rfind, index,
108+
rindex) of unicodeobject.c file, because they all have the same
109+
behaviour for the arguments.
110+
111+
It does not touch the variables received until it knows everything
112+
is ok.
113+
114+
Note that we receive a pointer to the pointer of the substring object,
115+
so when we create that object in this function we don't DECREF it,
116+
because it continues living in the caller functions (those functions,
117+
after finishing using the substring, must DECREF it).
118+
*/
119+
120+
int
121+
_ParseTupleFinds (PyObject *args, PyObject **substring,
122+
Py_ssize_t *start, Py_ssize_t *end) {
123+
PyObject *tmp_substring;
124+
Py_ssize_t tmp_start = 0;
125+
Py_ssize_t tmp_end = PY_SSIZE_T_MAX;
126+
PyObject *obj_start=Py_None, *obj_end=Py_None;
127+
128+
if (!PyArg_ParseTuple(args, "O|OO:find", &tmp_substring,
129+
&obj_start, &obj_end))
130+
return 0;
131+
132+
/* To support None in "start" and "end" arguments, meaning
133+
the same as if they were not passed.
134+
*/
135+
if (obj_start != Py_None)
136+
if (!_PyEval_SliceIndex(obj_start, &tmp_start))
137+
return 0;
138+
if (obj_end != Py_None)
139+
if (!_PyEval_SliceIndex(obj_end, &tmp_end))
140+
return 0;
141+
142+
tmp_substring = PyUnicode_FromObject(tmp_substring);
143+
if (!tmp_substring)
144+
return 0;
145+
146+
*start = tmp_start;
147+
*end = tmp_end;
148+
*substring = tmp_substring;
149+
return 1;
150+
}
151+
152+
106153
#endif /* STRINGLIB_FIND_H */
107154

108155
/*

Objects/stringobject.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,10 +1880,21 @@ string_find_internal(PyStringObject *self, PyObject *args, int dir)
18801880
const char *sub;
18811881
Py_ssize_t sub_len;
18821882
Py_ssize_t start=0, end=PY_SSIZE_T_MAX;
1883+
PyObject *obj_start=Py_None, *obj_end=Py_None;
18831884

1884-
if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj,
1885-
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
1885+
if (!PyArg_ParseTuple(args, "O|OO:find/rfind/index/rindex", &subobj,
1886+
&obj_start, &obj_end))
18861887
return -2;
1888+
/* To support None in "start" and "end" arguments, meaning
1889+
the same as if they were not passed.
1890+
*/
1891+
if (obj_start != Py_None)
1892+
if (!_PyEval_SliceIndex(obj_start, &start))
1893+
return -2;
1894+
if (obj_end != Py_None)
1895+
if (!_PyEval_SliceIndex(obj_end, &end))
1896+
return -2;
1897+
18871898
if (PyString_Check(subobj)) {
18881899
sub = PyString_AS_STRING(subobj);
18891900
sub_len = PyString_GET_SIZE(subobj);

Objects/unicodeobject.c

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6040,16 +6040,12 @@ static PyObject *
60406040
unicode_find(PyUnicodeObject *self, PyObject *args)
60416041
{
60426042
PyObject *substring;
6043-
Py_ssize_t start = 0;
6044-
Py_ssize_t end = PY_SSIZE_T_MAX;
6043+
Py_ssize_t start;
6044+
Py_ssize_t end;
60456045
Py_ssize_t result;
60466046

6047-
if (!PyArg_ParseTuple(args, "O|O&O&:find", &substring,
6048-
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
6047+
if (!_ParseTupleFinds(args, &substring, &start, &end))
60496048
return NULL;
6050-
substring = PyUnicode_FromObject(substring);
6051-
if (!substring)
6052-
return NULL;
60536049

60546050
result = stringlib_find_slice(
60556051
PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self),
@@ -6110,15 +6106,11 @@ unicode_index(PyUnicodeObject *self, PyObject *args)
61106106
{
61116107
Py_ssize_t result;
61126108
PyObject *substring;
6113-
Py_ssize_t start = 0;
6114-
Py_ssize_t end = PY_SSIZE_T_MAX;
6109+
Py_ssize_t start;
6110+
Py_ssize_t end;
61156111

6116-
if (!PyArg_ParseTuple(args, "O|O&O&:index", &substring,
6117-
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
6112+
if (!_ParseTupleFinds(args, &substring, &start, &end))
61186113
return NULL;
6119-
substring = PyUnicode_FromObject(substring);
6120-
if (!substring)
6121-
return NULL;
61226114

61236115
result = stringlib_find_slice(
61246116
PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self),
@@ -6781,16 +6773,12 @@ static PyObject *
67816773
unicode_rfind(PyUnicodeObject *self, PyObject *args)
67826774
{
67836775
PyObject *substring;
6784-
Py_ssize_t start = 0;
6785-
Py_ssize_t end = PY_SSIZE_T_MAX;
6776+
Py_ssize_t start;
6777+
Py_ssize_t end;
67866778
Py_ssize_t result;
67876779

6788-
if (!PyArg_ParseTuple(args, "O|O&O&:rfind", &substring,
6789-
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
6790-
return NULL;
6791-
substring = PyUnicode_FromObject(substring);
6792-
if (!substring)
6793-
return NULL;
6780+
if (!_ParseTupleFinds(args, &substring, &start, &end))
6781+
return NULL;
67946782

67956783
result = stringlib_rfind_slice(
67966784
PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self),
@@ -6812,16 +6800,12 @@ static PyObject *
68126800
unicode_rindex(PyUnicodeObject *self, PyObject *args)
68136801
{
68146802
PyObject *substring;
6815-
Py_ssize_t start = 0;
6816-
Py_ssize_t end = PY_SSIZE_T_MAX;
6803+
Py_ssize_t start;
6804+
Py_ssize_t end;
68176805
Py_ssize_t result;
68186806

6819-
if (!PyArg_ParseTuple(args, "O|O&O&:rindex", &substring,
6820-
_PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end))
6821-
return NULL;
6822-
substring = PyUnicode_FromObject(substring);
6823-
if (!substring)
6824-
return NULL;
6807+
if (!_ParseTupleFinds(args, &substring, &start, &end))
6808+
return NULL;
68256809

68266810
result = stringlib_rfind_slice(
68276811
PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self),

0 commit comments

Comments
 (0)