comparison mercurial/utils/stringutil.py @ 45724:ac39a8a214b1

stringutil: add function to compile stringmatcher pattern into regexp Prepares for adding a revset predicate for "grep --diff". The grep logic needs a regexp object instead of a match function.
author Yuya Nishihara <yuya@tcha.org>
date Mon, 05 Oct 2020 20:40:39 +0900
parents edfc5820aae7
children 89a2afe31e82
comparison
equal deleted inserted replaced
45723:edfc5820aae7 45724:ac39a8a214b1
374 return kind, pattern, match 374 return kind, pattern, match
375 375
376 raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind) 376 raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind)
377 377
378 378
379 def substringregexp(pattern, flags=0):
380 """Build a regexp object from a string pattern possibly starting with
381 're:' or 'literal:' prefix.
382
383 helper for tests:
384 >>> def test(pattern, *tests):
385 ... regexp = substringregexp(pattern)
386 ... return [bool(regexp.search(t)) for t in tests]
387 >>> def itest(pattern, *tests):
388 ... regexp = substringregexp(pattern, remod.I)
389 ... return [bool(regexp.search(t)) for t in tests]
390
391 substring matching (no prefix):
392 >>> test(b'bcde', b'abc', b'def', b'abcdefg')
393 [False, False, True]
394
395 substring pattern should be escaped:
396 >>> substringregexp(b'.bc').pattern
397 '\\\\.bc'
398 >>> test(b'.bc', b'abc', b'def', b'abcdefg')
399 [False, False, False]
400
401 regex matching ('re:' prefix)
402 >>> test(b're:a.+b', b'nomatch', b'fooadef', b'fooadefbar')
403 [False, False, True]
404
405 force substring matches ('literal:' prefix)
406 >>> test(b'literal:re:foobar', b'foobar', b're:foobar')
407 [False, True]
408
409 case insensitive literal matches
410 >>> itest(b'BCDE', b'abc', b'def', b'abcdefg')
411 [False, False, True]
412
413 case insensitive regex matches
414 >>> itest(b're:A.+b', b'nomatch', b'fooadef', b'fooadefBar')
415 [False, False, True]
416 """
417 kind, pattern = _splitpattern(pattern)
418 if kind == b're':
419 try:
420 return remod.compile(pattern, flags)
421 except remod.error as e:
422 raise error.ParseError(
423 _(b'invalid regular expression: %s') % forcebytestr(e)
424 )
425 elif kind == b'literal':
426 return remod.compile(remod.escape(pattern), flags)
427
428 raise error.ProgrammingError(b'unhandled pattern kind: %s' % kind)
429
430
379 def shortuser(user): 431 def shortuser(user):
380 """Return a short representation of a user name or email address.""" 432 """Return a short representation of a user name or email address."""
381 f = user.find(b'@') 433 f = user.find(b'@')
382 if f >= 0: 434 if f >= 0:
383 user = user[:f] 435 user = user[:f]