diff --git a/Lib/test/test_re.py b/Lib/test/test_re.py index 65d7bec9bb41b3..062d812c822ab5 100644 --- a/Lib/test/test_re.py +++ b/Lib/test/test_re.py @@ -1950,6 +1950,28 @@ def test_locale_flag(self): self.assertRaises(ValueError, re.compile, b'(?a)', re.LOCALE) self.assertRaises(re.PatternError, re.compile, b'(?aL)') + def test_locale_ignorecase_negated_set(self): + IL = re.LOCALE | re.IGNORECASE + # [bc] matches b'B', so [^bc] must not. + self.assertTrue(re.fullmatch(rb'[bc]', b'B', IL)) + self.assertIsNone(re.fullmatch(rb'[^bc]', b'B', IL)) + self.assertIsNone(re.fullmatch(rb'[^b-c]', b'C', IL)) + self.assertIsNone(re.fullmatch(rb'[^bc]', b'c', IL)) + self.assertTrue(re.fullmatch(rb'[^bc]', b'a', IL)) + # A one-member set compiles to NOT_LITERAL_LOC_IGNORE. + self.assertIsNone(re.fullmatch(rb'[^b]', b'B', IL)) + self.assertTrue(re.fullmatch(rb'[^b]', b'a', IL)) + self.assertIsNone(re.fullmatch(rb'[^\wq]', b'Q', IL)) + # A sparse set compiles to a bitmap instead of ranges. + self.assertTrue(re.fullmatch(rb'[ace]', b'C', IL)) + self.assertIsNone(re.fullmatch(rb'[^ace]', b'C', IL)) + self.assertTrue(re.fullmatch(rb'[^ace]', b'b', IL)) + # An alternation folded into a set puts NEGATE in the middle of it. + self.assertIsNone(re.fullmatch(rb'(?:a|[^bc])', b'B', IL)) + self.assertTrue(re.fullmatch(rb'(?:a|[^bc])', b'A', IL)) + self.assertIsNone(re.fullmatch(rb'\w(? */ + if (lo == set[0] || up == set[0]) + return ok; + set++; + break; + + case SRE_OP_CATEGORY: + /* */ + if (sre_category(set[0], (int) lo) || + sre_category(set[0], (int) up)) + return ok; + set++; + break; + + case SRE_OP_CHARSET: + /* */ + if ((lo < 256 && (set[lo/SRE_CODE_BITS] + & (1u << (lo & (SRE_CODE_BITS-1))))) || + (up < 256 && (set[up/SRE_CODE_BITS] + & (1u << (up & (SRE_CODE_BITS-1)))))) + return ok; + set += 256/SRE_CODE_BITS; + break; + + case SRE_OP_RANGE: + /* */ + if ((set[0] <= lo && lo <= set[1]) || + (set[0] <= up && up <= set[1])) + return ok; + set += 2; + break; + + case SRE_OP_NEGATE: + ok = !ok; + break; + + default: + /* internal error -- there's not much we can do about it + here, so let's just pretend it didn't match... */ + return 0; + } + } } LOCAL(Py_ssize_t) SRE(match)(SRE_STATE* state, const SRE_CODE* pattern, int toplevel);