Index: Lib/sre_compile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sre_compile.py,v retrieving revision 1.47 diff -u -r1.47 sre_compile.py --- Lib/sre_compile.py 19 Apr 2003 12:56:07 -0000 1.47 +++ Lib/sre_compile.py 20 Jun 2003 01:34:00 -0000 @@ -48,38 +48,27 @@ emit(OPCODES[ANY_ALL]) else: emit(OPCODES[ANY]) - elif op in (REPEAT, MIN_REPEAT, MAX_REPEAT): + elif op in (MIN_REPEAT, MAX_REPEAT): if flags & SRE_FLAG_TEMPLATE: raise error, "internal: unsupported template operator" - emit(OPCODES[REPEAT]) + emit(OPCODES[MAX_REPEAT]) skip = len(code); emit(0) emit(av[0]) emit(av[1]) _compile(code, av[2], flags) emit(OPCODES[SUCCESS]) code[skip] = len(code) - skip - elif _simple(av) and op != REPEAT: - if op == MAX_REPEAT: - emit(OPCODES[REPEAT_ONE]) + else: + if op == MAX_REPEAT and _simple(av): + emit(OPCODES[MAX_REPEAT_ONE]) else: - emit(OPCODES[MIN_REPEAT_ONE]) + emit(OPCODES[op]) skip = len(code); emit(0) emit(av[0]) emit(av[1]) _compile(code, av[2], flags) emit(OPCODES[SUCCESS]) code[skip] = len(code) - skip - else: - emit(OPCODES[REPEAT]) - skip = len(code); emit(0) - emit(av[0]) - emit(av[1]) - _compile(code, av[2], flags) - code[skip] = len(code) - skip - if op == MAX_REPEAT: - emit(OPCODES[MAX_UNTIL]) - else: - emit(OPCODES[MIN_UNTIL]) elif op is SUBPATTERN: if av[0]: emit(OPCODES[MARK]) @@ -145,6 +134,19 @@ else: emit(OPCODES[op]) emit(av-1) + elif op is GROUPREF_EXISTS: + emit(OPCODES[op]) + emit((av[0]-1)*2) + skipyes = len(code); emit(0) + _compile(code, av[1], flags) + if av[2]: + emit(OPCODES[JUMP]) + skipno = len(code); emit(0) + code[skipyes] = len(code) - skipyes + 1 + _compile(code, av[2], flags) + code[skipno] = len(code) - skipno + else: + code[skipyes] = len(code) - skipyes + 1 else: raise ValueError, ("unsupported operand type", op) Index: Lib/sre_constants.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sre_constants.py,v retrieving revision 1.32 diff -u -r1.32 sre_constants.py --- Lib/sre_constants.py 19 Apr 2003 12:56:07 -0000 1.32 +++ Lib/sre_constants.py 20 Jun 2003 01:34:01 -0000 @@ -13,7 +13,7 @@ # update when constants are added or removed -MAGIC = 20030419 +MAGIC = 20030614 # max code word in this release @@ -42,6 +42,7 @@ CHARSET = "charset" GROUPREF = "groupref" GROUPREF_IGNORE = "groupref_ignore" +GROUPREF_EXISTS = "groupref_exists" IN = "in" IN_IGNORE = "in_ignore" INFO = "info" @@ -49,18 +50,14 @@ LITERAL = "literal" LITERAL_IGNORE = "literal_ignore" MARK = "mark" -MAX_REPEAT = "max_repeat" -MAX_UNTIL = "max_until" MIN_REPEAT = "min_repeat" -MIN_UNTIL = "min_until" +MAX_REPEAT = "max_repeat" +MAX_REPEAT_ONE = "max_repeat_one" NEGATE = "negate" NOT_LITERAL = "not_literal" NOT_LITERAL_IGNORE = "not_literal_ignore" RANGE = "range" -REPEAT = "repeat" -REPEAT_ONE = "repeat_one" SUBPATTERN = "subpattern" -MIN_REPEAT_ONE = "min_repeat_one" # positions AT_BEGINNING = "at_beginning" @@ -108,21 +105,19 @@ CALL, CATEGORY, CHARSET, BIGCHARSET, - GROUPREF, GROUPREF_IGNORE, + GROUPREF, GROUPREF_IGNORE, GROUPREF_EXISTS, IN, IN_IGNORE, INFO, JUMP, LITERAL, LITERAL_IGNORE, MARK, - MAX_UNTIL, - MIN_UNTIL, NOT_LITERAL, NOT_LITERAL_IGNORE, NEGATE, RANGE, - REPEAT, - REPEAT_ONE, + MIN_REPEAT, + MAX_REPEAT, + MAX_REPEAT_ONE, SUBPATTERN, - MIN_REPEAT_ONE ] Index: Lib/sre_parse.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sre_parse.py,v retrieving revision 1.57 diff -u -r1.57 sre_parse.py --- Lib/sre_parse.py 19 Apr 2003 08:37:23 -0000 1.57 +++ Lib/sre_parse.py 20 Jun 2003 01:34:03 -0000 @@ -364,6 +364,20 @@ subpattern.append((BRANCH, (None, items))) return subpattern +def _parse_sub_cond(source, state, condgroup): + item_yes = _parse(source, state) + if source.match("|"): + item_no = _parse(source, state) + if source.match("|"): + raise error, "conditional backref with more than two branches" + else: + item_no = None + if source.next and not source.match(")", 0): + raise error, "pattern not properly closed" + subpattern = SubPattern(state) + subpattern.append((GROUPREF_EXISTS, (condgroup, item_yes, item_no))) + return subpattern + def _parse(source, state): # parse a simple pattern @@ -499,6 +513,7 @@ elif this == "(": group = 1 name = None + condgroup = None if source.match("?"): group = 0 # options @@ -568,6 +583,26 @@ else: subpattern.append((ASSERT_NOT, (dir, p))) continue + elif source.match("("): + # conditional backreference group + condname = "" + while 1: + char = source.get() + if char is None: + raise error, "unterminated name" + if char == ")": + break + condname = condname + char + group = 2 + if isname(condname): + condgroup = state.groupdict.get(condname) + if condgroup is None: + raise error, "unknown group name" + else: + try: + condgroup = atoi(condname) + except ValueError: + raise error, "bad character in group name" else: # flags if not source.next in FLAGS: @@ -581,7 +616,10 @@ group = None else: group = state.opengroup(name) - p = _parse_sub(source, state) + if condgroup: + p = _parse_sub_cond(source, state, condgroup) + else: + p = _parse_sub(source, state) if not source.match(")"): raise error, "unbalanced parenthesis" if group is not None: Index: Modules/_sre.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_sre.c,v retrieving revision 2.98 diff -u -r2.98 _sre.c --- Modules/_sre.c 9 Jun 2003 08:22:11 -0000 2.98 +++ Modules/_sre.c 20 Jun 2003 01:34:18 -0000 @@ -52,6 +52,7 @@ /* defining this one enables tracing */ #undef VERBOSE +//#define VERBOSE 1 #if PY_VERSION_HEX >= 0x01060000 #if PY_VERSION_HEX < 0x02020000 || defined(Py_USING_UNICODE) @@ -275,67 +276,83 @@ /* helpers */ static void -mark_fini(SRE_STATE* state) +data_stack_dealloc(SRE_STATE* state) { - if (state->mark_stack) { - free(state->mark_stack); - state->mark_stack = NULL; + if (state->data_stack) { + free(state->data_stack); + state->data_stack = NULL; } - state->mark_stack_size = state->mark_stack_base = 0; + state->data_stack_size = state->data_stack_base = 0; } static int -mark_save(SRE_STATE* state, int lo, int hi, int *mark_stack_base) +data_stack_grow(SRE_STATE* state, int size) { + int minsize, cursize; void* stack; - int size; - int minsize, newsize; - if (hi <= lo) - return 0; - - size = (hi - lo) + 1; + minsize = state->data_stack_base + size; + cursize = state->data_stack_size; - newsize = state->mark_stack_size; - minsize = state->mark_stack_base + size; - - if (newsize < minsize) { + if (cursize < minsize) { /* create new stack */ - if (!newsize) { - newsize = 512; - if (newsize < minsize) - newsize = minsize; - TRACE(("allocate stack %d\n", newsize)); - stack = malloc(sizeof(void*) * newsize); + if (!cursize) { + cursize = 512; + if (cursize < minsize) + cursize = minsize; + TRACE(("allocate stack %d\n", cursize)); + stack = malloc(sizeof(void*) * cursize); } else { /* grow the stack */ - while (newsize < minsize) - newsize += newsize; - TRACE(("grow stack to %d\n", newsize)); - stack = realloc(state->mark_stack, sizeof(void*) * newsize); + cursize += 1024; + while (cursize < minsize) + cursize += cursize; + TRACE(("grow stack to %d\n", cursize)); + stack = realloc(state->data_stack, sizeof(void*) * cursize); } if (!stack) { - mark_fini(state); + data_stack_dealloc(state); return SRE_ERROR_MEMORY; } - state->mark_stack = stack; - state->mark_stack_size = newsize; + state->data_stack = stack; + state->data_stack_size = cursize; } - TRACE(("copy %d:%d to %d (%d)\n", lo, hi, state->mark_stack_base, size)); + return 0; +} + +static int +mark_save(SRE_STATE* state, int lo, int hi, int *data_stack_base) +{ + int size; + int i; + + if (hi <= lo) + return 0; + + size = (hi - lo) + 1; + + if (*data_stack_base != -1) + state->data_stack_base = *data_stack_base; + + i = data_stack_grow(state, size+1); + if (i) + return i; + + TRACE(("copy %d:%d to %d (%d)\n", lo, hi, state->data_stack_base, size)); - memcpy(state->mark_stack + state->mark_stack_base, state->mark + lo, + memcpy(state->data_stack + state->data_stack_base, state->mark + lo, size * sizeof(void*)); - state->mark_stack_base += size; + state->data_stack_base += size; - *mark_stack_base = state->mark_stack_base; + *data_stack_base = state->data_stack_base; return 0; } static int -mark_restore(SRE_STATE* state, int lo, int hi, int *mark_stack_base) +mark_restore(SRE_STATE* state, int lo, int hi, int *data_stack_base) { int size; @@ -344,16 +361,56 @@ size = (hi - lo) + 1; - state->mark_stack_base = *mark_stack_base - size; + *data_stack_base -= size; + state->data_stack_base = *data_stack_base; - TRACE(("copy %d:%d from %d\n", lo, hi, state->mark_stack_base)); + TRACE(("copy %d:%d from %d\n", lo, hi, state->data_stack_base)); - memcpy(state->mark + lo, state->mark_stack + state->mark_stack_base, + memcpy(state->mark + lo, state->data_stack + state->data_stack_base, size * sizeof(void*)); return 0; } +static int +data_save(SRE_STATE* state, void *data, int size, int *data_stack_base) +{ + int stacksize = (size+sizeof(void*)-1)/sizeof(void*); + int i; + + if (*data_stack_base != -1) + state->data_stack_base = *data_stack_base; + + i = data_stack_grow(state, stacksize); + if (i) + return i; + + TRACE(("copy data in %p to %d (%d)\n", data, state->data_stack_base, size)); + + memcpy(state->data_stack + state->data_stack_base, data, size); + + state->data_stack_base += stacksize; + + *data_stack_base = state->data_stack_base; + + return 0; +} + +static int +data_restore(SRE_STATE* state, void *data, int size, int *data_stack_base) +{ + int stacksize = (size+sizeof(void*)-1)/sizeof(void*); + + *data_stack_base -= stacksize; + state->data_stack_base = *data_stack_base; + + TRACE(("copy data to %p from %d\n", data, state->data_stack_base)); + + memcpy(data, state->data_stack + state->data_stack_base, size); + + return 0; +} + /* generate 8-bit version */ #define SRE_CHAR unsigned char @@ -737,6 +794,30 @@ } \ } while (0) +#define DATA_SAVE(s,x) data_save(state, (x), sizeof(x), &data_stack_base) +#define DATA_RESTORE(s,x) data_restore(state, (x), sizeof(x), &data_stack_base) + +#define STATE_SAVE() \ + do { \ + int i_ = 0; \ + LASTMARK_SAVE(); \ + i_ |= mark_save(state, 0, lastmark, &data_stack_base); \ + i_ |= DATA_SAVE(state, &lastmark); \ + i_ |= DATA_SAVE(state, &lastindex); \ + i_ |= DATA_SAVE(state, &state->ptr); \ + if (i_ < 0) return i; \ + } while (0) +#define STATE_RESTORE() \ + do { \ + int i_ = 0; \ + i_ |= DATA_RESTORE(state, &state->ptr); \ + i_ |= DATA_RESTORE(state, &lastindex); \ + i_ |= DATA_RESTORE(state, &lastmark); \ + i_ |= mark_restore(state, 0, lastmark, &data_stack_base); \ + LASTMARK_RESTORE(); \ + if (i_ < 0) return i; \ + } while (0) + LOCAL(int) SRE_MATCH(SRE_STATE* state, SRE_CODE* pattern, int level) { @@ -746,12 +827,10 @@ SRE_CHAR* end = state->end; SRE_CHAR* ptr = state->ptr; int i, count; - SRE_REPEAT* rp; - int lastmark, lastindex, mark_stack_base; + int lastmark, lastindex; + int data_stack_base = -1; SRE_CODE chr; - SRE_REPEAT rep; /* FIXME: allocate in STATE instead */ - TRACE(("|%p|%p|ENTER %d\n", pattern, ptr, level)); #if defined(USE_STACKCHECK) @@ -894,6 +973,21 @@ pattern++; break; + case SRE_OP_GROUPREF_EXISTS: + TRACE(("|%p|%p|GROUPREF_EXISTS %d\n", pattern, ptr, pattern[0])); + /* codeyes codeno ... */ + i = pattern[0]; + { + SRE_CHAR* p = (SRE_CHAR*) state->mark[i+i]; + SRE_CHAR* e = (SRE_CHAR*) state->mark[i+i+1]; + if (!p || !e || e < p) { + pattern += pattern[1]; + break; + } + } + pattern += 2; + break; + case SRE_OP_LITERAL_IGNORE: TRACE(("|%p|%p|LITERAL_IGNORE %d\n", pattern, ptr, pattern[0])); if (ptr >= end || @@ -975,8 +1069,8 @@ /* <0=skip> code ... */ TRACE(("|%p|%p|BRANCH\n", pattern, ptr)); LASTMARK_SAVE(); - if (state->repeat) { - i = mark_save(state, 0, lastmark, &mark_stack_base); + if (state->inside_repeat) { + i = mark_save(state, 0, lastmark, &data_stack_base); if (i < 0) return i; } @@ -991,8 +1085,8 @@ i = SRE_MATCH(state, pattern + 1, level + 1); if (i) return i; - if (state->repeat) { - i = mark_restore(state, 0, lastmark, &mark_stack_base); + if (state->inside_repeat) { + i = mark_restore(state, 0, lastmark, &data_stack_base); if (i < 0) return i; } @@ -1000,7 +1094,7 @@ } return 0; - case SRE_OP_REPEAT_ONE: + case SRE_OP_MAX_REPEAT_ONE: /* match repeated sequence (maximizing regexp) */ /* this operator only works if the repeated item is @@ -1008,9 +1102,9 @@ collecting backtracking points. for other cases, use the MAX_REPEAT operator */ - /* <1=min> <2=max> item tail */ + /* <1=min> <2=max> item tail */ - TRACE(("|%p|%p|REPEAT_ONE %d %d\n", pattern, ptr, + TRACE(("|%p|%p|MAX_REPEAT_ONE %d %d\n", pattern, ptr, pattern[1], pattern[2])); if (ptr + pattern[1] > end) @@ -1075,196 +1169,95 @@ } return 0; - case SRE_OP_MIN_REPEAT_ONE: - /* match repeated sequence (minimizing regexp) */ - - /* this operator only works if the repeated item is - exactly one character wide, and we're not already - collecting backtracking points. for other cases, - use the MIN_REPEAT operator */ - - /* <1=min> <2=max> item tail */ - - TRACE(("|%p|%p|MIN_REPEAT_ONE %d %d\n", pattern, ptr, + case SRE_OP_MIN_REPEAT: + /* Non-greedy repeat. */ + /* <1=min> <2=max> item tail */ + TRACE(("|%p|%p|MIN_REPEAT %d %d\n", pattern, ptr, pattern[1], pattern[2])); - if (ptr + pattern[1] > end) - return 0; /* cannot match */ - state->ptr = ptr; + state->inside_repeat = 1; + count = 0; - if (pattern[1] == 0) - count = 0; - else { - /* count using pattern min as the maximum */ - count = SRE_COUNT(state, pattern + 3, pattern[1], level + 1); - - if (count < 0) - return count; /* exception */ - if (count < (int) pattern[1]) - return 0; /* did not match minimum number of times */ - ptr += count; /* advance past minimum matches of repeat */ + /* try to match the minimum */ + while (count < pattern[1]) { + i = SRE_MATCH(state, pattern + 3, level + 1); + if (i <= 0) + return 0; + count += 1; } - if (pattern[pattern[0]] == SRE_OP_SUCCESS) { - /* tail is empty. we're finished */ - state->ptr = ptr; - return 1; - - } else { - /* general case */ - int matchmax = ((int)pattern[2] == 65535); - int c; + /* try to match the tail until the maximum */ + for (;;) { LASTMARK_SAVE(); - while (matchmax || count <= (int) pattern[2]) { - state->ptr = ptr; - i = SRE_MATCH(state, pattern + pattern[0], level + 1); - if (i) - return i; - state->ptr = ptr; - c = SRE_COUNT(state, pattern+3, 1, level+1); - if (c < 0) - return c; - if (c == 0) - break; - assert(c == 1); - ptr++; - count++; - LASTMARK_RESTORE(); - } - } - return 0; - - case SRE_OP_REPEAT: - /* create repeat context. all the hard work is done - by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ - /* <1=min> <2=max> item tail */ - TRACE(("|%p|%p|REPEAT %d %d\n", pattern, ptr, - pattern[1], pattern[2])); - - rep.count = -1; - rep.pattern = pattern; - - /* install new repeat context */ - rep.prev = state->repeat; - state->repeat = &rep; - - state->ptr = ptr; - i = SRE_MATCH(state, pattern + pattern[0], level + 1); - - state->repeat = rep.prev; - - return i; - - case SRE_OP_MAX_UNTIL: - /* maximizing repeat */ - /* <1=min> <2=max> item tail */ - - /* FIXME: we probably need to deal with zero-width - matches in here... */ - rp = state->repeat; - if (!rp) - return SRE_ERROR_STATE; - - state->ptr = ptr; - - count = rp->count + 1; - - TRACE(("|%p|%p|MAX_UNTIL %d\n", pattern, ptr, count)); - - if (count < rp->pattern[1]) { - /* not enough matches */ - rp->count = count; - /* RECURSIVE */ - i = SRE_MATCH(state, rp->pattern + 3, level + 1); + /* if the tail matches, we're done */ + i = SRE_MATCH(state, pattern + pattern[0], level + 1); if (i) return i; - rp->count = count - 1; - state->ptr = ptr; - return 0; - } - if (count < rp->pattern[2] || rp->pattern[2] == 65535) { - /* we may have enough matches, but if we can - match another item, do so */ - rp->count = count; - LASTMARK_SAVE(); - i = mark_save(state, 0, lastmark, &mark_stack_base); - if (i < 0) - return i; - /* RECURSIVE */ - i = SRE_MATCH(state, rp->pattern + 3, level + 1); - if (i) - return i; - i = mark_restore(state, 0, lastmark, &mark_stack_base); - if (i < 0) - return i; + if (count >= pattern[2] && pattern[2] != 65535) + return 0; + LASTMARK_RESTORE(); - rp->count = count - 1; - state->ptr = ptr; + + /* try one more item */ + i = SRE_MATCH(state, pattern + 3, level + 1); + if (i <= 0) + return 0; + count += 1; } - /* cannot match more repeated items here. make sure the - tail matches */ - state->repeat = rp->prev; - i = SRE_MATCH(state, pattern, level + 1); - if (i) - return i; - state->repeat = rp; - state->ptr = ptr; return 0; - case SRE_OP_MIN_UNTIL: - /* minimizing repeat */ - /* <1=min> <2=max> item tail */ - - rp = state->repeat; - if (!rp) - return SRE_ERROR_STATE; + case SRE_OP_MAX_REPEAT: + /* Greedy repeat. */ + /* <1=min> <2=max> item tail */ + TRACE(("|%p|%p|MAX_REPEAT %d %d\n", pattern, ptr, + pattern[1], pattern[2])); state->ptr = ptr; + state->inside_repeat = 1; + count = 0; - count = rp->count + 1; + /* try to match the minimum */ + while (count < pattern[1]) { + i = SRE_MATCH(state, pattern + 3, level + 1); + if (i <= 0) + return 0; + count += 1; + } - TRACE(("|%p|%p|MIN_UNTIL %d %p\n", pattern, ptr, count, - rp->pattern)); + STATE_SAVE(); - if (count < rp->pattern[1]) { - /* not enough matches */ - rp->count = count; - /* RECURSIVE */ - i = SRE_MATCH(state, rp->pattern + 3, level + 1); - if (i) + /* try to match more */ + while (count < pattern[2] || pattern[2] == 65535) { + i = SRE_MATCH(state, pattern + 3, level + 1); + if (i < 0) return i; - rp->count = count-1; - state->ptr = ptr; - return 0; + if (i == 0) { + break; + } + STATE_SAVE(); + count += 1; } - LASTMARK_SAVE(); - - /* see if the tail matches */ - state->repeat = rp->prev; - i = SRE_MATCH(state, pattern, level + 1); - if (i) - return i; - - state->ptr = ptr; - state->repeat = rp; + STATE_RESTORE(); - if (count >= rp->pattern[2] && rp->pattern[2] != 65535) - return 0; + /* try to match the tail until the minimum */ + for (;;) { + /* if the tail matches, we're done */ + i = SRE_MATCH(state, pattern + pattern[0], level + 1); + if (i) + return i; - LASTMARK_RESTORE(); + if (count == pattern[1]) + return 0; - rp->count = count; - /* RECURSIVE */ - i = SRE_MATCH(state, rp->pattern + 3, level + 1); - if (i) - return i; - rp->count = count - 1; - state->ptr = ptr; + /* try with one less match */ + STATE_RESTORE(); + count -= 1; + } return 0; @@ -1518,9 +1511,9 @@ state->lastindex = -1; - state->repeat = NULL; + state->inside_repeat = 0; - mark_fini(state); + data_stack_dealloc(state); } static void* @@ -1647,7 +1640,7 @@ state_fini(SRE_STATE* state) { Py_XDECREF(state->string); - mark_fini(state); + data_stack_dealloc(state); } /* calculate offset from start of string */ Index: Modules/sre.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/sre.h,v retrieving revision 2.22 diff -u -r2.22 sre.h --- Modules/sre.h 18 Mar 2002 18:46:14 -0000 2.22 +++ Modules/sre.h 20 Jun 2003 01:34:18 -0000 @@ -52,12 +52,6 @@ /* FIXME: shouldn't be a constant, really... */ #define SRE_MARK_SIZE 200 -typedef struct SRE_REPEAT_T { - int count; - SRE_CODE* pattern; /* points to REPEAT operator arguments */ - struct SRE_REPEAT_T *prev; /* points to previous repeat context */ -} SRE_REPEAT; - typedef struct { /* string pointers */ void* ptr; /* current position (also end of current slice) */ @@ -74,10 +68,11 @@ int lastmark; void* mark[SRE_MARK_SIZE]; /* dynamically allocated stuff */ - void** mark_stack; - int mark_stack_size; - int mark_stack_base; - SRE_REPEAT *repeat; /* current repeat context */ + void** data_stack; + int data_stack_size; + int data_stack_base; + /* flags */ + int inside_repeat; /* hooks */ SRE_TOLOWER_HOOK lower; } SRE_STATE; Index: Modules/sre_constants.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/sre_constants.h,v retrieving revision 2.15 diff -u -r2.15 sre_constants.h --- Modules/sre_constants.h 19 Apr 2003 12:56:08 -0000 2.15 +++ Modules/sre_constants.h 20 Jun 2003 01:34:18 -0000 @@ -11,7 +11,7 @@ * See the _sre.c file for information on usage and redistribution. */ -#define SRE_MAGIC 20030419 +#define SRE_MAGIC 20030614 #define SRE_OP_FAILURE 0 #define SRE_OP_SUCCESS 1 #define SRE_OP_ANY 2 @@ -26,23 +26,22 @@ #define SRE_OP_BIGCHARSET 11 #define SRE_OP_GROUPREF 12 #define SRE_OP_GROUPREF_IGNORE 13 -#define SRE_OP_IN 14 -#define SRE_OP_IN_IGNORE 15 -#define SRE_OP_INFO 16 -#define SRE_OP_JUMP 17 -#define SRE_OP_LITERAL 18 -#define SRE_OP_LITERAL_IGNORE 19 -#define SRE_OP_MARK 20 -#define SRE_OP_MAX_UNTIL 21 -#define SRE_OP_MIN_UNTIL 22 -#define SRE_OP_NOT_LITERAL 23 -#define SRE_OP_NOT_LITERAL_IGNORE 24 -#define SRE_OP_NEGATE 25 -#define SRE_OP_RANGE 26 -#define SRE_OP_REPEAT 27 -#define SRE_OP_REPEAT_ONE 28 +#define SRE_OP_GROUPREF_EXISTS 14 +#define SRE_OP_IN 15 +#define SRE_OP_IN_IGNORE 16 +#define SRE_OP_INFO 17 +#define SRE_OP_JUMP 18 +#define SRE_OP_LITERAL 19 +#define SRE_OP_LITERAL_IGNORE 20 +#define SRE_OP_MARK 21 +#define SRE_OP_NOT_LITERAL 22 +#define SRE_OP_NOT_LITERAL_IGNORE 23 +#define SRE_OP_NEGATE 24 +#define SRE_OP_RANGE 25 +#define SRE_OP_MIN_REPEAT 26 +#define SRE_OP_MAX_REPEAT 27 +#define SRE_OP_MAX_REPEAT_ONE 28 #define SRE_OP_SUBPATTERN 29 -#define SRE_OP_MIN_REPEAT_ONE 30 #define SRE_AT_BEGINNING 0 #define SRE_AT_BEGINNING_LINE 1 #define SRE_AT_BEGINNING_STRING 2 Index: Doc/lib/libre.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libre.tex,v retrieving revision 1.100 diff -u -r1.100 libre.tex --- Doc/lib/libre.tex 13 May 2003 14:40:24 -0000 1.100 +++ Doc/lib/libre.tex 20 Jun 2003 01:33:58 -0000 @@ -297,6 +297,15 @@ fixed length. Patterns which start with negative lookbehind assertions may match at the beginning of the string being searched. +\item[\code{(?(\var{id/name})yes-pattern|no-pattern)}] Will try to match +with \regexp{yes-pattern} if the group with given \var{id} or \var{name} +exists, and with \regexp{no-pattern} if it doesn't. \regexp{|no-pattern} +is optional and can be omitted. For example, +\regexp{(<)?(\e w+@\e w+(?:\e .\e w+)+)(?(1)>)} is a poor email matching +pattern, which will match with \code{''} as well as +\code{'user@host.com'}, but not with \code{'