Files
Android-pyApi/android_pyapi/java/util_regex.py
T
shuiyu1123 bfe27fdc08 feat: Android-pyApi v1.0 - 全面翻译 Android SDK API 为 Python
52 个模块覆盖 Android + Java + org.json 标准库
2026-06-24 11:16:16 +00:00

287 lines
8.2 KiB
Python

"""
Java regex standard library APIs implemented in Python.
java.util.regex package - Pattern, Matcher, MatchResult, PatternSyntaxException.
"""
from .._core import Stub
from .io import IOException
from .lang import RuntimeException
import re as _re
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
IllegalStateException = type("IllegalStateException", (RuntimeException,), {})
__all__ = [
"Pattern", "Matcher", "MatchResult", "PatternSyntaxException",
]
# ============================================================
# PatternSyntaxException
# ============================================================
class PatternSyntaxException(IllegalArgumentException):
def __init__(self, desc, regex, index):
super().__init__(f"{desc}: {regex} at index {index}")
self._desc = desc
self._regex = regex
self._index = index
def getDescription(self):
return self._desc
def getPattern(self):
return self._regex
def getIndex(self):
return self._index
def getMessage(self):
return f"{self._desc} near index {self._index}: {self._regex}"
# ============================================================
# MatchResult
# ============================================================
class MatchResult(Stub):
def start(self, group=None):
raise NotImplementedError
def end(self, group=None):
raise NotImplementedError
def group(self, group=None):
raise NotImplementedError
def groupCount(self):
raise NotImplementedError
# ============================================================
# Matcher
# ============================================================
class Matcher(MatchResult):
def __init__(self, pattern, input_str):
super().__init__()
self._pattern = pattern
self._input = input_str
self._re_pattern = pattern._pattern
self._match = None
self._region_start = 0
self._region_end = len(input_str)
self._transparent_bounds = False
self._anchoring_bounds = True
self._last_match = None
def matches(self):
self._match = self._re_pattern.fullmatch(self._input, self._region_start, self._region_end)
self._last_match = self._match
return self._match is not None
def find(self, start=None):
if start is not None:
self._match = self._re_pattern.search(self._input, start, self._region_end)
else:
if self._match is None:
self._match = self._re_pattern.search(self._input, self._region_start, self._region_end)
else:
pos = self._match.end()
self._match = self._re_pattern.search(self._input, pos, self._region_end)
if self._match:
self._last_match = self._match
return self._match is not None
def lookingAt(self):
self._match = self._re_pattern.match(self._input, self._region_start, self._region_end)
self._last_match = self._match
return self._match is not None
def start(self, group=0):
if self._match is None:
raise IllegalStateException("No match available")
if group == 0:
return self._match.start()
return self._match.start(group)
def end(self, group=0):
if self._match is None:
raise IllegalStateException("No match available")
if group == 0:
return self._match.end()
return self._match.end(group)
def group(self, group=0):
if self._match is None:
raise IllegalStateException("No match available")
if isinstance(group, str):
return self._match.group(group)
return self._match.group(group)
def groupCount(self):
return self._re_pattern.groups
def replaceAll(self, replacement):
return self._re_pattern.sub(replacement, self._input)
def replaceFirst(self, replacement):
return self._re_pattern.sub(replacement, self._input, count=1)
def appendReplacement(self, sb, replacement):
if self._match is None:
raise IllegalStateException("No match available")
self._append_pos = getattr(self, '_append_pos', 0)
sb.append(self._input[self._append_pos:self._match.start()])
sb.append(self._re_pattern.sub(replacement, self._match.group(), count=1))
self._append_pos = self._match.end()
return self
def appendTail(self, sb):
self._append_pos = getattr(self, '_append_pos', 0)
sb.append(self._input[self._append_pos:])
return sb
def reset(self, input_str=None):
if input_str is not None:
self._input = input_str
self._region_end = len(input_str)
self._match = None
self._last_match = None
return self
def region(self, start, end):
self._region_start = start
self._region_end = end
return self
def regionStart(self):
return self._region_start
def regionEnd(self):
return self._region_end
def hasTransparentBounds(self):
return self._transparent_bounds
def hasAnchoringBounds(self):
return self._anchoring_bounds
def useAnchoringBounds(self, value):
self._anchoring_bounds = value
return self
def useTransparentBounds(self, value):
self._transparent_bounds = value
return self
def hitEnd(self):
return self._match is not None and self._match.end() >= self._region_end
def requireEnd(self):
return self._match is not None and not self.hitEnd()
def toMatchResult(self):
result = Matcher(self._pattern, self._input)
result._match = self._match
result._last_match = self._last_match
return result
def pattern(self):
return self._pattern
def toString(self):
return f"Matcher[pattern={self._pattern.pattern()}]"
def namedGroups(self):
return self._re_pattern.groupindex
class IllegalStateException(RuntimeException):
pass
# ============================================================
# Pattern
# ============================================================
class Pattern(Stub):
CANON_EQ = 128
CASE_INSENSITIVE = 2
COMMENTS = 4
DOTALL = 32
LITERAL = 16
MULTILINE = 8
UNICODE_CASE = 64
UNICODE_CHARACTER_CLASS = 256
UNIX_LINES = 1
_re_flags_map = {
0: 0, # default
2: _re.IGNORECASE,
8: _re.MULTILINE,
32: _re.DOTALL,
64: _re.UNICODE,
4: _re.VERBOSE,
}
def __init__(self, regex, flags=0):
super().__init__()
self._regex = str(regex)
self._flags = flags
re_flags = 0
for java_flag, py_flag in self._re_flags_map.items():
if flags & java_flag:
re_flags |= py_flag
try:
self._pattern = _re.compile(self._regex, re_flags)
except _re.error as e:
raise PatternSyntaxException(str(e), self._regex, e.pos if hasattr(e, 'pos') else 0)
@staticmethod
def compile(regex, flags=0):
return Pattern(regex, flags)
def matcher(self, input_str):
return Matcher(self, input_str)
def split(self, input_str, limit=0):
if limit <= 0:
parts = self._pattern.split(str(input_str))
if limit == 0:
while parts and parts[-1] == "":
parts.pop()
else:
parts = self._pattern.split(str(input_str), maxsplit=limit - 1)
while len(parts) < limit:
parts.append("")
return parts
def splitAsStream(self, input_str):
return iter(self.split(input_str))
@staticmethod
def matches(regex, input_str):
return bool(_re.fullmatch(regex, str(input_str)))
@staticmethod
def quote(s):
return _re.escape(str(s))
def flags(self):
return self._flags
def pattern(self):
return self._regex
def toString(self):
return self._regex
def predicate(self):
return lambda s: bool(self._pattern.fullmatch(str(s)))
def asPredicate(self):
return self.predicate()
def asMatchPredicate(self):
return lambda s: bool(self._pattern.fullmatch(str(s)))