Issue #20998: Fixed re.fullmatch() of repeated single character pattern

with ignore case.  Original patch by Matthew Barnett.
This commit is contained in:
Serhiy Storchaka 2014-05-14 21:48:17 +03:00
parent 946cfc3e23
commit 429b59ec69
5 changed files with 25 additions and 19 deletions

View File

@ -1223,6 +1223,11 @@ class ReTests(unittest.TestCase):
pat.scanner(string='abracadabra', pos=3, endpos=10).search().span(), pat.scanner(string='abracadabra', pos=3, endpos=10).search().span(),
(7, 9)) (7, 9))
def test_bug_20998(self):
# Issue #20998: Fullmatch of repeated single character pattern
# with ignore case.
self.assertEqual(re.fullmatch('[a-c]+', 'ABC', re.I).span(), (0, 3))
class PatternReprTests(unittest.TestCase): class PatternReprTests(unittest.TestCase):
def check(self, pattern, expected): def check(self, pattern, expected):

View File

@ -23,6 +23,9 @@ Core and Builtins
Library Library
------- -------
- Issue #20998: Fixed re.fullmatch() of repeated single character pattern
with ignore case. Original patch by Matthew Barnett.
- Issue #21075: fileinput.FileInput now reads bytes from standard stream if - Issue #21075: fileinput.FileInput now reads bytes from standard stream if
binary mode is specified. Patch by Sam Kimbrel. binary mode is specified. Patch by Sam Kimbrel.

View File

@ -505,14 +505,14 @@ pattern_dealloc(PatternObject* self)
} }
LOCAL(Py_ssize_t) LOCAL(Py_ssize_t)
sre_match(SRE_STATE* state, SRE_CODE* pattern) sre_match(SRE_STATE* state, SRE_CODE* pattern, int match_all)
{ {
if (state->charsize == 1) if (state->charsize == 1)
return sre_ucs1_match(state, pattern); return sre_ucs1_match(state, pattern, match_all);
if (state->charsize == 2) if (state->charsize == 2)
return sre_ucs2_match(state, pattern); return sre_ucs2_match(state, pattern, match_all);
assert(state->charsize == 4); assert(state->charsize == 4);
return sre_ucs4_match(state, pattern); return sre_ucs4_match(state, pattern, match_all);
} }
LOCAL(Py_ssize_t) LOCAL(Py_ssize_t)
@ -576,7 +576,7 @@ pattern_match(PatternObject *self, PyObject *args, PyObject *kwargs)
TRACE(("|%p|%p|MATCH\n", PatternObject_GetCode(self), state.ptr)); TRACE(("|%p|%p|MATCH\n", PatternObject_GetCode(self), state.ptr));
status = sre_match(&state, PatternObject_GetCode(self)); status = sre_match(&state, PatternObject_GetCode(self), 0);
TRACE(("|%p|%p|END\n", PatternObject_GetCode(self), state.ptr)); TRACE(("|%p|%p|END\n", PatternObject_GetCode(self), state.ptr));
if (PyErr_Occurred()) if (PyErr_Occurred())
@ -609,12 +609,11 @@ pattern_fullmatch(PatternObject* self, PyObject* args, PyObject* kw)
if (!string) if (!string)
return NULL; return NULL;
state.match_all = 1;
state.ptr = state.start; state.ptr = state.start;
TRACE(("|%p|%p|FULLMATCH\n", PatternObject_GetCode(self), state.ptr)); TRACE(("|%p|%p|FULLMATCH\n", PatternObject_GetCode(self), state.ptr));
status = sre_match(&state, PatternObject_GetCode(self)); status = sre_match(&state, PatternObject_GetCode(self), 1);
TRACE(("|%p|%p|END\n", PatternObject_GetCode(self), state.ptr)); TRACE(("|%p|%p|END\n", PatternObject_GetCode(self), state.ptr));
if (PyErr_Occurred()) if (PyErr_Occurred())
@ -2572,7 +2571,7 @@ scanner_match(ScannerObject* self, PyObject *unused)
state->ptr = state->start; state->ptr = state->start;
status = sre_match(state, PatternObject_GetCode(self->pattern)); status = sre_match(state, PatternObject_GetCode(self->pattern), 0);
if (PyErr_Occurred()) if (PyErr_Occurred())
return NULL; return NULL;

View File

@ -86,7 +86,6 @@ typedef struct {
SRE_REPEAT *repeat; SRE_REPEAT *repeat;
/* hooks */ /* hooks */
SRE_TOLOWER_HOOK lower; SRE_TOLOWER_HOOK lower;
int match_all;
} SRE_STATE; } SRE_STATE;
typedef struct { typedef struct {

View File

@ -173,7 +173,7 @@ SRE(charset)(SRE_CODE* set, SRE_CODE ch)
} }
} }
LOCAL(Py_ssize_t) SRE(match)(SRE_STATE* state, SRE_CODE* pattern); LOCAL(Py_ssize_t) SRE(match)(SRE_STATE* state, SRE_CODE* pattern, int match_all);
LOCAL(Py_ssize_t) LOCAL(Py_ssize_t)
SRE(count)(SRE_STATE* state, SRE_CODE* pattern, Py_ssize_t maxcount) SRE(count)(SRE_STATE* state, SRE_CODE* pattern, Py_ssize_t maxcount)
@ -259,7 +259,7 @@ SRE(count)(SRE_STATE* state, SRE_CODE* pattern, Py_ssize_t maxcount)
/* repeated single character pattern */ /* repeated single character pattern */
TRACE(("|%p|%p|COUNT SUBPATTERN\n", pattern, ptr)); TRACE(("|%p|%p|COUNT SUBPATTERN\n", pattern, ptr));
while ((SRE_CHAR*) state->ptr < end) { while ((SRE_CHAR*) state->ptr < end) {
i = SRE(match)(state, pattern); i = SRE(match)(state, pattern, 0);
if (i < 0) if (i < 0)
return i; return i;
if (!i) if (!i)
@ -490,7 +490,7 @@ typedef struct {
/* check if string matches the given pattern. returns <0 for /* check if string matches the given pattern. returns <0 for
error, 0 for failure, and 1 for success */ error, 0 for failure, and 1 for success */
LOCAL(Py_ssize_t) LOCAL(Py_ssize_t)
SRE(match)(SRE_STATE* state, SRE_CODE* pattern) SRE(match)(SRE_STATE* state, SRE_CODE* pattern, int match_all)
{ {
SRE_CHAR* end = (SRE_CHAR *)state->end; SRE_CHAR* end = (SRE_CHAR *)state->end;
Py_ssize_t alloc_pos, ctx_pos = -1; Py_ssize_t alloc_pos, ctx_pos = -1;
@ -507,7 +507,7 @@ SRE(match)(SRE_STATE* state, SRE_CODE* pattern)
ctx->last_ctx_pos = -1; ctx->last_ctx_pos = -1;
ctx->jump = JUMP_NONE; ctx->jump = JUMP_NONE;
ctx->pattern = pattern; ctx->pattern = pattern;
ctx->match_all = state->match_all; ctx->match_all = match_all;
ctx_pos = alloc_pos; ctx_pos = alloc_pos;
entrance: entrance:
@ -739,7 +739,7 @@ entrance:
RETURN_FAILURE; RETURN_FAILURE;
if (ctx->pattern[ctx->pattern[0]] == SRE_OP_SUCCESS && if (ctx->pattern[ctx->pattern[0]] == SRE_OP_SUCCESS &&
(!ctx->match_all || ctx->ptr == state->end)) { ctx->ptr == state->end) {
/* tail is empty. we're finished */ /* tail is empty. we're finished */
state->ptr = ctx->ptr; state->ptr = ctx->ptr;
RETURN_SUCCESS; RETURN_SUCCESS;
@ -824,7 +824,7 @@ entrance:
} }
if (ctx->pattern[ctx->pattern[0]] == SRE_OP_SUCCESS && if (ctx->pattern[ctx->pattern[0]] == SRE_OP_SUCCESS &&
(!ctx->match_all || ctx->ptr == state->end)) { (!match_all || ctx->ptr == state->end)) {
/* tail is empty. we're finished */ /* tail is empty. we're finished */
state->ptr = ctx->ptr; state->ptr = ctx->ptr;
RETURN_SUCCESS; RETURN_SUCCESS;
@ -1269,7 +1269,7 @@ SRE(search)(SRE_STATE* state, SRE_CODE* pattern)
state->ptr = ptr - (prefix_len - prefix_skip - 1); state->ptr = ptr - (prefix_len - prefix_skip - 1);
if (flags & SRE_INFO_LITERAL) if (flags & SRE_INFO_LITERAL)
return 1; /* we got all of it */ return 1; /* we got all of it */
status = SRE(match)(state, pattern + 2*prefix_skip); status = SRE(match)(state, pattern + 2*prefix_skip, 0);
if (status != 0) if (status != 0)
return status; return status;
/* close but no cigar -- try again */ /* close but no cigar -- try again */
@ -1302,7 +1302,7 @@ SRE(search)(SRE_STATE* state, SRE_CODE* pattern)
state->ptr = ++ptr; state->ptr = ++ptr;
if (flags & SRE_INFO_LITERAL) if (flags & SRE_INFO_LITERAL)
return 1; /* we got all of it */ return 1; /* we got all of it */
status = SRE(match)(state, pattern + 2); status = SRE(match)(state, pattern + 2, 0);
if (status != 0) if (status != 0)
break; break;
} }
@ -1317,7 +1317,7 @@ SRE(search)(SRE_STATE* state, SRE_CODE* pattern)
TRACE(("|%p|%p|SEARCH CHARSET\n", pattern, ptr)); TRACE(("|%p|%p|SEARCH CHARSET\n", pattern, ptr));
state->start = ptr; state->start = ptr;
state->ptr = ptr; state->ptr = ptr;
status = SRE(match)(state, pattern); status = SRE(match)(state, pattern, 0);
if (status != 0) if (status != 0)
break; break;
ptr++; ptr++;
@ -1327,7 +1327,7 @@ SRE(search)(SRE_STATE* state, SRE_CODE* pattern)
while (ptr <= end) { while (ptr <= end) {
TRACE(("|%p|%p|SEARCH\n", pattern, ptr)); TRACE(("|%p|%p|SEARCH\n", pattern, ptr));
state->start = state->ptr = ptr++; state->start = state->ptr = ptr++;
status = SRE(match)(state, pattern); status = SRE(match)(state, pattern, 0);
if (status != 0) if (status != 0)
break; break;
} }