fixed character set description in docstring (SRE uses Python

strings, not C strings)

removed USE_PYTHON defines, and related sre.py helpers

skip calling the subx helper if the template is callable.
interestingly enough, this means that

	def callback(m):
	    return literal
	result = pattern.sub(callback, string)

is much faster than

	result = pattern.sub(literal, string)
This commit is contained in:
Fredrik Lundh 2001-10-21 21:48:30 +00:00
parent 0402dd18cb
commit dac58492aa
2 changed files with 55 additions and 175 deletions

View File

@ -17,15 +17,13 @@
r"""Support for regular expressions (RE). r"""Support for regular expressions (RE).
This module provides regular expression matching operations similar to This module provides regular expression matching operations similar to
those found in Perl. It's 8-bit clean: the strings being processed may those found in Perl. It supports both 8-bit and Unicode strings; both
contain both null bytes and characters whose high bit is set. Regular the pattern and the strings being processed can contain null bytes and
expression pattern strings may not contain null bytes, but can specify characters outside the US ASCII range.
the null byte using the \\number notation. Characters with the high
bit set may be included.
Regular expressions can contain both special and ordinary Regular expressions can contain both special and ordinary characters.
characters. Most ordinary characters, like "A", "a", or "0", are the Most ordinary characters, like "A", "a", or "0", are the simplest
simplest regular expressions; they simply match themselves. You can regular expressions; they simply match themselves. You can
concatenate ordinary characters, so last matches the string 'last'. concatenate ordinary characters, so last matches the string 'last'.
The special characters are: The special characters are:
@ -45,7 +43,7 @@ The special characters are:
"|" A|B, creates an RE that will match either A or B. "|" A|B, creates an RE that will match either A or B.
(...) Matches the RE inside the parentheses. (...) Matches the RE inside the parentheses.
The contents can be retrieved or matched later in the string. The contents can be retrieved or matched later in the string.
(?iLmsx) Set the I, L, M, S, or X flag for the RE (see below). (?iLmsux) Set the I, L, M, S, U, or X flag for the RE (see below).
(?:...) Non-grouping version of regular parentheses. (?:...) Non-grouping version of regular parentheses.
(?P<name>...) The substring matched by the group is accessible by name. (?P<name>...) The substring matched by the group is accessible by name.
(?P=name) Matches the text matched earlier by the group named name. (?P=name) Matches the text matched earlier by the group named name.
@ -54,7 +52,7 @@ The special characters are:
(?!...) Matches if ... doesn't match next. (?!...) Matches if ... doesn't match next.
The special sequences consist of "\\" and a character from the list The special sequences consist of "\\" and a character from the list
below. If the ordinary character is not on the list, then the below. If the ordinary character is not on the list, then the
resulting RE will match the second character. resulting RE will match the second character.
\number Matches the contents of the group of the same number. \number Matches the contents of the group of the same number.
\A Matches only at the start of the string. \A Matches only at the start of the string.
@ -246,76 +244,13 @@ def _expand(pattern, match, template):
def _subx(pattern, template): def _subx(pattern, template):
# internal: pattern.sub/subn implementation helper # internal: pattern.sub/subn implementation helper
if callable(template): template = _compile_repl(template, pattern)
filter = template if not template[0] and len(template[1]) == 1:
else:
template = _compile_repl(template, pattern)
if not template[0] and len(template[1]) == 1:
# literal replacement
filter = template[1][0]
else:
def filter(match, template=template):
return sre_parse.expand_template(template, match)
return filter
def _sub(pattern, template, text, count=0):
# internal: pattern.sub implementation hook
# FIXME: not used in SRE 2.2.1 and later; will be removed soon
return _subn(pattern, template, text, count)[0]
def _subn(pattern, template, text, count=0):
# internal: pattern.subn implementation hook
# FIXME: not used in SRE 2.2.1 and later; will be removed soon
filter = _subx(pattern, template)
if not callable(filter):
# literal replacement # literal replacement
def filter(match, literal=filter): return template[1][0]
return literal def filter(match, template=template):
n = i = 0 return sre_parse.expand_template(template, match)
s = [] return filter
append = s.append
c = pattern.scanner(text)
while not count or n < count:
m = c.search()
if not m:
break
b, e = m.span()
if i < b:
append(text[i:b])
elif i == b == e and n:
append(text[i:b])
continue # ignore empty match at previous position
append(filter(m))
i = e
n = n + 1
append(text[i:])
return _join(s, text[:0]), n
def _split(pattern, text, maxsplit=0):
# internal: pattern.split implementation hook
# FIXME: not used in SRE 2.2.1 and later; will be removed soon
n = i = 0
s = []
append = s.append
extend = s.extend
c = pattern.scanner(text)
g = pattern.groups
while not maxsplit or n < maxsplit:
m = c.search()
if not m:
break
b, e = m.span()
if b == e:
if i >= len(text):
break
continue
append(text[i:b])
if g and b != e:
extend(list(m.groups()))
i = e
n = n + 1
append(text[i:])
return s
# register myself for pickling # register myself for pickling

View File

@ -76,10 +76,6 @@ static char copyright[] =
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* optional features */ /* optional features */
/* test: define to use sre.py helpers instead of C code */
#undef USE_PYTHON_SPLIT
#undef USE_PYTHON_SUB
/* prevent run-away recursion (bad patterns on long strings) */ /* prevent run-away recursion (bad patterns on long strings) */
#if !defined(USE_STACKCHECK) #if !defined(USE_STACKCHECK)
@ -1251,6 +1247,8 @@ SRE_SEARCH(SRE_STATE* state, SRE_CODE* pattern)
TRACE(("|%p|%p|SEARCH LITERAL\n", pattern, ptr)); TRACE(("|%p|%p|SEARCH LITERAL\n", pattern, ptr));
state->start = ptr; state->start = ptr;
state->ptr = ++ptr; state->ptr = ++ptr;
if (flags & SRE_INFO_LITERAL)
return 1; /* we got all of it */
status = SRE_MATCH(state, pattern + 2, 1); status = SRE_MATCH(state, pattern + 2, 1);
if (status != 0) if (status != 0)
break; break;
@ -1820,66 +1818,6 @@ join(PyObject* list, PyObject* pattern)
return result; return result;
} }
#ifdef USE_PYTHON_SUB
static PyObject*
pattern_sub(PatternObject* self, PyObject* args, PyObject* kw)
{
PyObject* template;
PyObject* string;
PyObject* count = Py_False; /* zero */
static char* kwlist[] = { "repl", "string", "count", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|O:sub", kwlist,
&template, &string, &count))
return NULL;
/* delegate to Python code */
return call(
SRE_MODULE, "_sub",
Py_BuildValue("OOOO", self, template, string, count)
);
}
#endif
#ifdef USE_PYTHON_SUB
static PyObject*
pattern_subn(PatternObject* self, PyObject* args, PyObject* kw)
{
PyObject* template;
PyObject* string;
PyObject* count = Py_False; /* zero */
static char* kwlist[] = { "repl", "string", "count", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|O:subn", kwlist,
&template, &string, &count))
return NULL;
/* delegate to Python code */
return call(
SRE_MODULE, "_subn",
Py_BuildValue("OOOO", self, template, string, count)
);
}
#endif
#if defined(USE_PYTHON_SPLIT)
static PyObject*
pattern_split(PatternObject* self, PyObject* args, PyObject* kw)
{
PyObject* string;
PyObject* maxsplit = Py_False; /* zero */
static char* kwlist[] = { "source", "maxsplit", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kw, "O|O:split", kwlist,
&string, &maxsplit))
return NULL;
/* delegate to Python code */
return call(
SRE_MODULE, "_split",
Py_BuildValue("OOO", self, string, maxsplit)
);
}
#endif
static PyObject* static PyObject*
pattern_findall(PatternObject* self, PyObject* args, PyObject* kw) pattern_findall(PatternObject* self, PyObject* args, PyObject* kw)
{ {
@ -1980,7 +1918,6 @@ error:
} }
#if !defined(USE_PYTHON_SPLIT)
static PyObject* static PyObject*
pattern_split(PatternObject* self, PyObject* args, PyObject* kw) pattern_split(PatternObject* self, PyObject* args, PyObject* kw)
{ {
@ -2071,15 +2008,16 @@ pattern_split(PatternObject* self, PyObject* args, PyObject* kw)
} }
/* get segment following last match */ /* get segment following last match */
item = PySequence_GetSlice( i = STATE_OFFSET(&state, last);
string, STATE_OFFSET(&state, last), state.endpos if (i < state.endpos) {
); item = PySequence_GetSlice(string, i, state.endpos);
if (!item) if (!item)
goto error; goto error;
status = PyList_Append(list, item); status = PyList_Append(list, item);
Py_DECREF(item); Py_DECREF(item);
if (status < 0) if (status < 0)
goto error; goto error;
}
state_fini(&state); state_fini(&state);
return list; return list;
@ -2090,9 +2028,7 @@ error:
return NULL; return NULL;
} }
#endif
#if !defined(USE_PYTHON_SUB)
static PyObject* static PyObject*
pattern_subx(PatternObject* self, PyObject* template, PyObject* string, pattern_subx(PatternObject* self, PyObject* template, PyObject* string,
int count, int subn) int count, int subn)
@ -2108,15 +2044,22 @@ pattern_subx(PatternObject* self, PyObject* template, PyObject* string,
int i, b, e; int i, b, e;
int filter_is_callable; int filter_is_callable;
/* call subx helper to get the filter */ if (PyCallable_Check(template)) {
filter = call( /* sub/subn takes either a function or a template */
SRE_MODULE, "_subx", filter = template;
Py_BuildValue("OO", self, template) Py_INCREF(filter);
); filter_is_callable = 1;
if (!filter) } else {
return NULL; /* if not callable, call the template compiler. it may return
either a filter function or a literal string */
filter_is_callable = PyCallable_Check(filter); filter = call(
SRE_MODULE, "_subx",
Py_BuildValue("OO", self, template)
);
if (!filter)
return NULL;
filter_is_callable = PyCallable_Check(filter);
}
string = state_init(&state, self, string, 0, INT_MAX); string = state_init(&state, self, string, 0, INT_MAX);
if (!string) if (!string)
@ -2169,7 +2112,7 @@ pattern_subx(PatternObject* self, PyObject* template, PyObject* string,
goto next; goto next;
if (filter_is_callable) { if (filter_is_callable) {
/* filter match */ /* pass match object through filter */
match = pattern_new_match(self, &state, 1); match = pattern_new_match(self, &state, 1);
if (!match) if (!match)
goto error; goto error;
@ -2186,7 +2129,7 @@ pattern_subx(PatternObject* self, PyObject* template, PyObject* string,
} else { } else {
/* filter is literal string */ /* filter is literal string */
item = filter; item = filter;
Py_INCREF(filter); Py_INCREF(item);
} }
/* add to list */ /* add to list */
@ -2208,18 +2151,21 @@ next:
} }
/* get segment following last match */ /* get segment following last match */
item = PySequence_GetSlice(string, i, state.endpos); if (i < state.endpos) {
if (!item) item = PySequence_GetSlice(string, i, state.endpos);
goto error; if (!item)
status = PyList_Append(list, item); goto error;
Py_DECREF(item); status = PyList_Append(list, item);
if (status < 0) Py_DECREF(item);
goto error; if (status < 0)
goto error;
}
state_fini(&state); state_fini(&state);
/* convert list to single string */ /* convert list to single string (also removes list) */
item = join(list, self->pattern); item = join(list, self->pattern);
if (!item) if (!item)
return NULL; return NULL;
@ -2262,7 +2208,6 @@ pattern_subn(PatternObject* self, PyObject* args, PyObject* kw)
return pattern_subx(self, template, string, count, 1); return pattern_subx(self, template, string, count, 1);
} }
#endif
static PyObject* static PyObject*
pattern_copy(PatternObject* self, PyObject* args) pattern_copy(PatternObject* self, PyObject* args)