add backtracking irc glob matching
This commit is contained in:
parent
0921cb8086
commit
ab66df4d43
2 changed files with 46 additions and 2 deletions
|
@ -18,3 +18,37 @@ def _collapse(pattern: str) -> str:
|
||||||
i += 1
|
i += 1
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
def _match(pattern: str, s: str):
|
||||||
|
i, j = 0, 0
|
||||||
|
|
||||||
|
i_backup = -1
|
||||||
|
j_backup = -1
|
||||||
|
while j < len(s):
|
||||||
|
p = (pattern[i:] or [None])[0]
|
||||||
|
|
||||||
|
if p == "*":
|
||||||
|
i += 1
|
||||||
|
i_backup = i
|
||||||
|
j_backup = j
|
||||||
|
|
||||||
|
elif p in ["?", s[j]]:
|
||||||
|
i += 1
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
if i_backup == -1:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
j_backup += 1
|
||||||
|
j = j_backup
|
||||||
|
i = i_backup
|
||||||
|
|
||||||
|
return i == len(pattern)
|
||||||
|
|
||||||
|
class Glob(object):
|
||||||
|
def __init__(self, pattern: str):
|
||||||
|
self._pattern = pattern
|
||||||
|
def match(self, s: str) -> bool:
|
||||||
|
return _match(self._pattern, s)
|
||||||
|
def compile(pattern: str):
|
||||||
|
return Glob(_collapse(pattern))
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from re import compile
|
from re import compile as re_compile
|
||||||
from typing import Optional, Pattern
|
from typing import Optional, Pattern
|
||||||
from irctokens import Hostmask
|
from irctokens import Hostmask
|
||||||
from ..interface import IMatchResponseParam, IMatchResponseHostmask, IServer
|
from ..interface import IMatchResponseParam, IMatchResponseHostmask, IServer
|
||||||
|
from ..glob import Glob, compile as glob_compile
|
||||||
from .. import formatting
|
from .. import formatting
|
||||||
|
|
||||||
class Any(IMatchResponseParam):
|
class Any(IMatchResponseParam):
|
||||||
|
@ -52,7 +53,7 @@ class Regex(IMatchResponseParam):
|
||||||
self._pattern: Optional[Pattern] = None
|
self._pattern: Optional[Pattern] = None
|
||||||
def match(self, server: IServer, arg: str) -> bool:
|
def match(self, server: IServer, arg: str) -> bool:
|
||||||
if self._pattern is None:
|
if self._pattern is None:
|
||||||
self._pattern = compile(self._value)
|
self._pattern = re_compile(self._value)
|
||||||
return bool(self._pattern.search(arg))
|
return bool(self._pattern.search(arg))
|
||||||
|
|
||||||
class Nickname(IMatchResponseHostmask):
|
class Nickname(IMatchResponseHostmask):
|
||||||
|
@ -67,3 +68,12 @@ class Nickname(IMatchResponseHostmask):
|
||||||
if self._folded is None:
|
if self._folded is None:
|
||||||
self._folded = server.casefold(self._nickname)
|
self._folded = server.casefold(self._nickname)
|
||||||
return self._folded == server.casefold(hostmask.nickname)
|
return self._folded == server.casefold(hostmask.nickname)
|
||||||
|
|
||||||
|
class Mask(IMatchResponseHostmask):
|
||||||
|
def __init__(self, mask: str):
|
||||||
|
self._mask = mask
|
||||||
|
self._compiled = Optional[Glob]
|
||||||
|
def match(self, server: IServer, hostmask: Hostmask):
|
||||||
|
if self._compiled is None:
|
||||||
|
self._compiled = glob_compile(self._mask)
|
||||||
|
return self._compiled.match(str(hostmask))
|
||||||
|
|
Loading…
Reference in a new issue