def testRegexFirstGroupMatch(self): s = 'oXooXoooXoX' self.assertEqual((1, 3), libc.regex_first_group_match('(X.)', s, 0)) # Match from position 3 self.assertEqual((4, 6), libc.regex_first_group_match('(X.)', s, 3)) # Match from position 3 self.assertEqual((8, 10), libc.regex_first_group_match('(X.)', s, 6))
def testRegexFirstGroupMatch(self): s = 'oXooXoooXoX' self.assertEqual((1, 3), libc.regex_first_group_match('(X.)', s, 0)) # Match from position 3 self.assertEqual((4, 6), libc.regex_first_group_match('(X.)', s, 3)) # Match from position 3 self.assertEqual((8, 10), libc.regex_first_group_match('(X.)', s, 6)) # Syntax Error self.assertRaises(RuntimeError, libc.regex_first_group_match, r'*', 'abcd', 0)
def Replace(self, s, op): # type: (str, suffix_op__PatSub) -> str regex = '(%s)' % self.regex # make it a group if op.replace_mode == Id.Lit_Slash: try: return _PatSubAll(s, regex, self.replace_str) # loop over matches except RuntimeError as e: # libc.regex_first_group_match raises RuntimeError. # note: MyPy doesn't know RuntimeError has e.message (and e.args) msg = e.message # type: str e_die('Error matching regex %r: %s', regex, msg, span_id=self.slash_spid) if op.replace_mode == Id.Lit_Pound: regex = '^' + regex elif op.replace_mode == Id.Lit_Percent: regex = regex + '$' m = libc.regex_first_group_match(regex, s, 0) #log('regex = %r, s = %r, match = %r', regex, s, m) if m is None: return s start, end = m return s[:start] + self.replace_str + s[end:]
def testSpecialCharsInCharClass(self): CASES = [ ("([a-z]+)", '123abc123', (3, 6)), # Uh what the heck, \- means the same thing as -? It's just ignored. At # least in GNU libc. # https://stackoverflow.com/questions/28495913/how-do-you-escape-a-hyphen-as-character-range-in-a-posix-regex # The <hyphen> character shall be treated as itself if it occurs first (after an initial '^', if any) or last in the list, or as an ending range point in a range expression ("([a\-z]+)", '123abc123', (3, 6)), # This is an inverted range. TODO: Need to fix the error message. #("([a\-.]+)", '123abc123', None), ("([\\\\]+)", 'a\\b', (1, 2)), # Can you escape ] with \? Yes in fnmatch, but NO here!!! ('([\\]])', '\\', None), ('([\\]])', ']', None), # Weird parsing!!! ('([\\]])', '\\]', (0, 2)), ] for pat, s, expected in CASES: result = libc.regex_first_group_match(pat, s, 0) self.assertEqual( expected, result, "FAILED: pat %r s %r result %s" % (pat, s, result))
def _AllMatchPositions(s, regex): """Returns a list of all (start, end) match positions of the regex against s. (If there are no matches, it returns the empty list.) """ matches = [] pos = 0 n = len(s) while pos < n: # needed to prevent infinite loop in (.*) case m = libc.regex_first_group_match(regex, s, pos) if m is None: break matches.append(m) start, end = m pos = end # advance position return matches
def _AllMatchPositions(s, regex): """Returns a list of all (start, end) match positions of the regex against s. (If there are no matches, it returns the empty list.) """ matches = [] pos = 0 while True: m = libc.regex_first_group_match(regex, s, pos) if m is None: break matches.append(m) start, end = m #log('m = %r, %r' % (start, end)) pos = end # advance position return matches
def Replace(self, s, op): regex = '(%s)' % self.regex # make it a group if op.do_all: return _PatSubAll(s, regex, self.replace_str) # loop over matches if op.do_prefix: regex = '^' + regex elif op.do_suffix: regex = regex + '$' m = libc.regex_first_group_match(regex, s, 0) #log('regex = %r, s = %r, match = %r', regex, s, m) if m is None: return s start, end = m return s[:start] + self.replace_str + s[end:]
def PatSub(s, op, pat, replace_str): """Helper for ${x/pat/replace}.""" #log('PAT %r REPLACE %r', pat, replace_str) regex, err = glob_.GlobToExtendedRegex(pat) if err: e_die("Can't convert glob to regex: %r", pat) if regex is None: # Simple/fast path for fixed strings if op.do_all: return s.replace(pat, replace_str) elif op.do_prefix: if s.startswith(pat): n = len(pat) return replace_str + s[n:] else: return s elif op.do_suffix: if s.endswith(pat): n = len(pat) return s[:-n] + replace_str else: return s else: return s.replace(pat, replace_str, 1) # just the first one else: regex = '(%s)' % regex # make it a group if op.do_all: return _PatSubAll(s, regex, replace_str) # loop over matches if op.do_prefix: regex = '^' + regex elif op.do_suffix: regex = regex + '$' m = libc.regex_first_group_match(regex, s, 0) log('regex = %r, s = %r, match = %r', regex, s, m) if m is None: return s start, end = m return s[:start] + replace_str + s[end:]
def Replace(self, s, op): regex = '(%s)' % self.regex # make it a group if op.replace_mode == Id.Lit_Slash: try: return _PatSubAll(s, regex, self.replace_str) # loop over matches except RuntimeError as e: e_die('Error matching regex %r: %s', regex, e, span_id=self.slash_spid) if op.replace_mode == Id.Lit_Pound: regex = '^' + regex elif op.replace_mode == Id.Lit_Percent: regex = regex + '$' m = libc.regex_first_group_match(regex, s, 0) #log('regex = %r, s = %r, match = %r', regex, s, m) if m is None: return s start, end = m return s[:start] + self.replace_str + s[end:]
def testRegexFirstGroupMatchError(self): # Helping to debug issue #291 s = '' if 0: libc.regex_first_group_match("(['+-'])", s, 6)