mirror of
https://github.com/jlu5/PyLink.git
synced 2024-11-27 13:09:23 +01:00
utils: add match_text(), general glob matching function
In preparation for ircmatch removal (#636)
This commit is contained in:
parent
e25a5df4db
commit
b7d93fe86a
@ -187,6 +187,70 @@ class UtilsTestCase(unittest.TestCase):
|
||||
utils.parse_duration("4s3d")
|
||||
utils.parse_duration("1m5w")
|
||||
|
||||
def test_match_text(self):
|
||||
f = utils.match_text # glob, target
|
||||
|
||||
# Base cases
|
||||
self.assertTrue(f("", ""))
|
||||
self.assertFalse(f("test", ""))
|
||||
self.assertFalse(f("", "abcdef"))
|
||||
self.assertFalse(f("", "*")) # specified the wrong way
|
||||
self.assertFalse(f("", "?"))
|
||||
self.assertTrue(f("foo", "foo"))
|
||||
self.assertFalse(f("foo", "bar"))
|
||||
self.assertFalse(f("foo", "food"))
|
||||
|
||||
# Test use of *
|
||||
self.assertTrue(f("*", "b"))
|
||||
self.assertTrue(f("*", "abc"))
|
||||
self.assertTrue(f("*", ""))
|
||||
self.assertTrue(f("*!*@*", "nick!user@host"))
|
||||
self.assertTrue(f("*@*", "rick!user@lost"))
|
||||
self.assertTrue(f("ni*!*@*st", "nick!user@roast"))
|
||||
self.assertFalse(f("nick!*abcdef*@*st*", "nick!user@roast"))
|
||||
self.assertTrue(f("*!*@*.overdrive.pw", "abc!def@abc.users.overdrive.pw"))
|
||||
|
||||
# Test use of ?
|
||||
self.assertTrue(f("?", "b"))
|
||||
self.assertFalse(f("?", "abc"))
|
||||
self.assertTrue(f("Guest?????!???irc@users.overdrive.pw", "Guest12567!webirc@users.overdrive.pw"))
|
||||
self.assertFalse(f("Guest????!webirc@users.overdrive.pw", "Guest23457!webirc@users.overdrive.pw"))
|
||||
|
||||
def test_match_text_complex(self):
|
||||
f = utils.match_text # glob, target
|
||||
|
||||
# Test combination of * and ?
|
||||
for glob in {"*?", "?*"}:
|
||||
self.assertTrue(f(glob, "a"))
|
||||
self.assertTrue(f(glob, "ab"))
|
||||
self.assertFalse(f(glob, ""))
|
||||
|
||||
self.assertTrue(f("ba*??*ll", "basketball"))
|
||||
self.assertFalse(f("ba*??*ll", "ball"))
|
||||
self.assertFalse(f("ba*??*ll", "basketballs"))
|
||||
|
||||
self.assertTrue(f("**", "fooBarBaz"))
|
||||
self.assertTrue(f("*?*?*?*", "cat"))
|
||||
self.assertTrue(f("*??****?*", "cat"))
|
||||
self.assertFalse(f("*??****?*?****", "MAP"))
|
||||
|
||||
def test_match_text_casemangle(self):
|
||||
f = utils.match_text # glob, target, manglefunc
|
||||
|
||||
# We are case insensitive by default
|
||||
self.assertTrue(f("Test", "TEST"))
|
||||
self.assertTrue(f("ALPHA*", "alphabet"))
|
||||
|
||||
# But we can override this preference
|
||||
self.assertFalse(f("Test", "TEST", None))
|
||||
self.assertFalse(f("*for*", "BEForE", None))
|
||||
self.assertTrue(f("*corn*", "unicorns", None))
|
||||
|
||||
# Or specify some other filter func
|
||||
self.assertTrue(f('005', '5', lambda s: s.zfill(3)))
|
||||
self.assertTrue(f('*0*', '14', lambda s: s.zfill(6)))
|
||||
self.assertFalse(f('*9*', '14', lambda s: s.zfill(13)))
|
||||
self.assertTrue(f('*chin*', 'machine', str.upper))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
28
utils.py
28
utils.py
@ -12,6 +12,7 @@ import os
|
||||
import collections
|
||||
import argparse
|
||||
import ipaddress
|
||||
import functools
|
||||
|
||||
from .log import log
|
||||
from . import world, conf, structures
|
||||
@ -821,3 +822,30 @@ def parse_duration(text):
|
||||
raise ValueError("Failed to parse duration string %r" % text)
|
||||
|
||||
return result
|
||||
|
||||
@functools.lru_cache(maxsize=1024)
|
||||
def _glob2re(glob):
|
||||
"""Converts an IRC-style glob to a regular expression."""
|
||||
patt = ['^']
|
||||
|
||||
for char in glob:
|
||||
if char == '*' and patt[-1] != '*': # Collapse ** into *
|
||||
patt.append('.*')
|
||||
elif char == '?':
|
||||
patt.append('.')
|
||||
else:
|
||||
patt.append(re.escape(char))
|
||||
|
||||
patt.append('$')
|
||||
return ''.join(patt)
|
||||
|
||||
def match_text(glob, text, filterfunc=str.lower):
|
||||
"""
|
||||
Returns whether glob matches text. If filterfunc is specified, run filterfunc on glob and text
|
||||
before preforming matches.
|
||||
"""
|
||||
if filterfunc:
|
||||
glob = filterfunc(glob)
|
||||
text = filterfunc(text)
|
||||
|
||||
return re.match(_glob2re(glob), text)
|
||||
|
Loading…
Reference in New Issue
Block a user