Skip to content

Commit 774dbfd

Browse files
author
Matthew Barnett
committed
# Git issue 498: Conditional negative lookahead inside positive lookahead fails to match
Conditional node needed an additional member that points to the true branch.
1 parent 9f03255 commit 774dbfd

File tree

5 files changed

+29
-9
lines changed

5 files changed

+29
-9
lines changed

changelog.txt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
Version: 2023.6.3
2+
3+
# Git issue 498: Conditional negative lookahead inside positive lookahead fails to match
4+
Conditional node needed an additional member that points to the true branch.
5+
16
Version: 2023.5.5
27

38
Removed semicolon after 'else' in 'munge_name'.
@@ -86,11 +91,11 @@ Version: 2022.3.2
8691

8792
Git issue 453: Document last supported python2 version
8893

89-
Added a brief reference to the last version to support Python 2 in README.rst.
94+
Added a brief reference to the last version to support Python 2 in README.rst.
9095

9196
Git issue 456: RegexFlag exists in re, but not regex
9297

93-
Updated the flags to use enum now that regex supports only Python 3.6+.
98+
Updated the flags to use enum now that regex supports only Python 3.6+.
9499

95100
Version: 2022.1.21
96101

@@ -1225,13 +1230,13 @@ Version: 2013.1.25
12251230
Version: 2013.1.24
12261231

12271232
Hg issue 86: Enhance API of captures() to enable retrieval of ALL groups at once, as a dictionary
1228-
Added capturesdict() method to match object.
1233+
Added capturesdict() method to match object.
12291234

12301235
Hg issue 87: Allow duplicate names of groups
1231-
Now allowed.
1236+
Now allowed.
12321237

12331238
Hg issue 88: regex.match() hangs
1234-
Fixed.
1239+
Fixed.
12351240

12361241
Version: 2013.1.20
12371242

regex_3/_regex.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ typedef struct RE_Node {
291291
union {
292292
struct {
293293
RE_NextNode next_2;
294+
struct RE_Node* true_node; /* Used by a CONDITIONAL node. */
294295
} nonstring;
295296
struct {
296297
/* Used only if (node->status & RE_STATUS_STRING) is true. */
@@ -15272,7 +15273,7 @@ Py_LOCAL_INLINE(int) basic_match(RE_State* state, BOOL search) {
1527215273
/* It's a negative lookaround that's failed. Go to the 'true'
1527315274
* branch.
1527415275
*/
15275-
node = conditional->next_1.node;
15276+
node = conditional->nonstring.true_node;
1527615277

1527715278
goto advance;
1527815279
}
@@ -16990,7 +16991,6 @@ Py_LOCAL_INLINE(int) basic_match(RE_State* state, BOOL search) {
1699016991

1699116992
if (!lookaround->match) {
1699216993
/* It's a negative lookaround that's failed. */
16993-
1699416994
node = lookaround->nonstring.next_2.node;
1699516995
goto advance;
1699616996
}
@@ -22986,6 +22986,14 @@ Py_LOCAL_INLINE(void) skip_one_way_branches(PatternObject* pattern) {
2298622986
node->nonstring.next_2.node = next->next_1.node;
2298722987
modified = TRUE;
2298822988
}
22989+
22990+
/* Check the true branch for CONDITIONAL. */
22991+
next = node->nonstring.true_node;
22992+
if (next && next->op == RE_OP_BRANCH &&
22993+
!next->nonstring.true_node) {
22994+
node->nonstring.true_node = next->next_1.node;
22995+
modified = TRUE;
22996+
}
2298922997
}
2299022998
} while (modified);
2299122999

@@ -24443,6 +24451,7 @@ Py_LOCAL_INLINE(int) build_CONDITIONAL(RE_CompileArgs* args) {
2444324451
/* end test node -> true branch -> end node */
2444424452
add_node(end_test_node, subargs.start);
2444524453
add_node(subargs.end, end_node);
24454+
test_node->nonstring.true_node = subargs.start;
2444624455

2444724456
if (args->code[0] == RE_OP_NEXT) {
2444824457
/* There's a false branch. */

regex_3/regex.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@
241241
"VERSION1", "X", "VERBOSE", "W", "WORD", "error", "Regex", "__version__",
242242
"__doc__", "RegexFlag"]
243243

244-
__version__ = "2.5.128"
244+
__version__ = "2.5.129"
245245

246246
# --------------------------------------------------------------------
247247
# Public interface.

regex_3/test_regex.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4332,6 +4332,12 @@ def test_hg_bugs(self):
43324332
# Git issue 494: Backtracking failure matching regex ^a?(a?)b?c\1$ against string abca
43334333
self.assertEqual(regex.search(r"^a?(a?)b?c\1$", "abca").span(), (0, 4))
43344334

4335+
# Git issue 498: Conditional negative lookahead inside positive lookahead fails to match
4336+
self.assertEqual(regex.match(r"(?(?=a).|..)", "ab").span(), (0, 1))
4337+
self.assertEqual(regex.match(r"(?(?=b).|..)", "ab").span(), (0, 2))
4338+
self.assertEqual(regex.match(r"(?(?!a).|..)", "ab").span(), (0, 2))
4339+
self.assertEqual(regex.match(r"(?(?!b).|..)", "ab").span(), (0, 1))
4340+
43354341
def test_fuzzy_ext(self):
43364342
self.assertEqual(bool(regex.fullmatch(r'(?r)(?:a){e<=1:[a-z]}', 'e')),
43374343
True)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
setup(
99
name='regex',
10-
version='2023.5.5',
10+
version='2023.6.3',
1111
description='Alternative regular expression module, to replace re.',
1212
long_description=long_description,
1313
long_description_content_type='text/x-rst',

0 commit comments

Comments
 (0)