## Secret Labs' Regular Expression Engine## convert template to internal format## Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved.## See the sre.py file for information on usage and redistribution.#"""Internal support module for sre"""import _sreimport sre_parsefrom sre_constants import *assert _sre.MAGIC == MAGIC, "SRE module mismatch"_LITERAL_CODES = {LITERAL, NOT_LITERAL}_REPEATING_CODES = {REPEAT, MIN_REPEAT, MAX_REPEAT}_SUCCESS_CODES = {SUCCESS, FAILURE}_ASSERT_CODES = {ASSERT, ASSERT_NOT}_UNIT_CODES = _LITERAL_CODES | {ANY, IN}# Sets of lowercase characters which have the same uppercase._equivalences = (# LATIN SMALL LETTER I, LATIN SMALL LETTER DOTLESS I(0x69, 0x131), # iı# LATIN SMALL LETTER S, LATIN SMALL LETTER LONG S(0x73, 0x17f), # ss# MICRO SIGN, GREEK SMALL LETTER MU(0xb5, 0x3bc), # μμ# COMBINING GREEK YPOGEGRAMMENI, GREEK SMALL LETTER IOTA, GREEK PROSGEGRAMMENI(0x345, 0x3b9, 0x1fbe), # \u0345ιι# GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS, GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA(0x390, 0x1fd3), # ΐΐ# GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS, GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA(0x3b0, 0x1fe3), # ΰΰ# GREEK SMALL LETTER BETA, GREEK BETA SYMBOL(0x3b2, 0x3d0), # ββ# GREEK SMALL LETTER EPSILON, GREEK LUNATE EPSILON SYMBOL(0x3b5, 0x3f5), # εε# GREEK SMALL LETTER THETA, GREEK THETA SYMBOL(0x3b8, 0x3d1), # θθ# GREEK SMALL LETTER KAPPA, GREEK KAPPA SYMBOL(0x3ba, 0x3f0), # κκ# GREEK SMALL LETTER PI, GREEK PI SYMBOL(0x3c0, 0x3d6), # ππ# GREEK SMALL LETTER RHO, GREEK RHO SYMBOL(0x3c1, 0x3f1), # ρρ# GREEK SMALL LETTER FINAL SIGMA, GREEK SMALL LETTER SIGMA(0x3c2, 0x3c3), # ςσ# GREEK SMALL LETTER PHI, GREEK PHI SYMBOL(0x3c6, 0x3d5), # φφ# LATIN SMALL LETTER S WITH DOT ABOVE, LATIN SMALL LETTER LONG S WITH DOT ABOVE(0x1e61, 0x1e9b), # ṡṡ# LATIN SMALL LIGATURE LONG S T, LATIN SMALL LIGATURE ST(0xfb05, 0xfb06), # stst)# Maps the lowercase code to lowercase codes which have the same uppercase._ignorecase_fixes = {i: tuple(j for j in t if i != j)for t in _equivalences for i in t}def _combine_flags(flags, add_flags, del_flags,TYPE_FLAGS=sre_parse.TYPE_FLAGS):if add_flags & TYPE_FLAGS:flags &= ~TYPE_FLAGSreturn (flags | add_flags) & ~del_flagsdef _compile(code, pattern, flags):# internal: compile a (sub)patternemit = code.append_len = lenLITERAL_CODES = _LITERAL_CODESREPEATING_CODES = _REPEATING_CODESSUCCESS_CODES = _SUCCESS_CODESASSERT_CODES = _ASSERT_CODESiscased = Nonetolower = Nonefixes = Noneif flags & SRE_FLAG_IGNORECASE and not flags & SRE_FLAG_LOCALE:if flags & SRE_FLAG_UNICODE:iscased = _sre.unicode_iscasedtolower = _sre.unicode_tolowerfixes = _ignorecase_fixeselse:iscased = _sre.ascii_iscasedtolower = _sre.ascii_tolowerfor op, av in pattern:if op in LITERAL_CODES:if not flags & SRE_FLAG_IGNORECASE:emit(op)emit(av)elif flags & SRE_FLAG_LOCALE:emit(OP_LOCALE_IGNORE[op])emit(av)elif not iscased(av):emit(op)emit(av)else:lo = tolower(av)if not fixes: # asciiemit(OP_IGNORE[op])emit(lo)elif lo not in fixes:emit(OP_UNICODE_IGNORE[op])emit(lo)else:emit(IN_UNI_IGNORE)skip = _len(code); emit(0)if op is NOT_LITERAL:emit(NEGATE)for k in (lo,) + fixes[lo]:emit(LITERAL)emit(k)emit(FAILURE)code[skip] = _len(code) - skipelif op is IN:charset, hascased = _optimize_charset(av, iscased, tolower, fixes)if flags & SRE_FLAG_IGNORECASE and flags & SRE_FLAG_LOCALE:emit(IN_LOC_IGNORE)elif not hascased:emit(IN)elif not fixes: # asciiemit(IN_IGNORE)else:emit(IN_UNI_IGNORE)skip = _len(code); emit(0)_compile_charset(charset, flags, code)code[skip] = _len(code) - skipelif op is ANY:if flags & SRE_FLAG_DOTALL:emit(ANY_ALL)else:emit(ANY)elif op in REPEATING_CODES:if flags & SRE_FLAG_TEMPLATE:raise error("internal: unsupported template operator %r" % (op,))if _simple(av[2]):if op is MAX_REPEAT:emit(REPEAT_ONE)else:emit(MIN_REPEAT_ONE)skip = _len(code); emit(0)emit(av[0])emit(av[1])_compile(code, av[2], flags)emit(SUCCESS)code[skip] = _len(code) - skipelse:emit(REPEAT)skip = _len(code); emit(0)emit(av[0])emit(av[1])_compile(code, av[2], flags)code[skip] = _len(code) - skipif op is MAX_REPEAT:emit(MAX_UNTIL)else:emit(MIN_UNTIL)elif op is SUBPATTERN:group, add_flags, del_flags, p = avif group:emit(MARK)emit((group-1)*2)# _compile_info(code, p, _combine_flags(flags, add_flags, del_flags))_compile(code, p, _combine_flags(flags, add_flags, del_flags))if group:emit(MARK)emit((group-1)*2+1)elif op in SUCCESS_CODES:emit(op)elif op in ASSERT_CODES:emit(op)skip = _len(code); emit(0)if av[0] >= 0:emit(0) # look aheadelse:lo, hi = av[1].getwidth()if lo != hi:raise error("look-behind requires fixed-width pattern")emit(lo) # look behind_compile(code, av[1], flags)emit(SUCCESS)code[skip] = _len(code) - skipelif op is CALL:emit(op)skip = _len(code); emit(0)_compile(code, av, flags)emit(SUCCESS)code[skip] = _len(code) - skipelif op is AT:emit(op)if flags & SRE_FLAG_MULTILINE:av = AT_MULTILINE.get(av, av)if flags & SRE_FLAG_LOCALE:av = AT_LOCALE.get(av, av)elif flags & SRE_FLAG_UNICODE:av = AT_UNICODE.get(av, av)emit(av)elif op is BRANCH:emit(op)tail = []tailappend = tail.appendfor av in av[1]:skip = _len(code); emit(0)# _compile_info(code, av, flags)_compile(code, av, flags)emit(JUMP)tailappend(_len(code)); emit(0)code[skip] = _len(code) - skipemit(FAILURE) # end of branchfor tail in tail:code[tail] = _len(code) - tailelif op is CATEGORY:emit(op)if flags & SRE_FLAG_LOCALE:av = CH_LOCALE[av]elif flags & SRE_FLAG_UNICODE:av = CH_UNICODE[av]emit(av)elif op is GROUPREF:if not flags & SRE_FLAG_IGNORECASE:emit(op)elif flags & SRE_FLAG_LOCALE:emit(GROUPREF_LOC_IGNORE)elif not fixes: # asciiemit(GROUPREF_IGNORE)else:emit(GROUPREF_UNI_IGNORE)emit(av-1)elif op is GROUPREF_EXISTS:emit(op)emit(av[0]-1)skipyes = _len(code); emit(0)_compile(code, av[1], flags)if av[2]:emit(JUMP)skipno = _len(code); emit(0)code[skipyes] = _len(code) - skipyes + 1_compile(code, av[2], flags)code[skipno] = _len(code) - skipnoelse:code[skipyes] = _len(code) - skipyes + 1else:raise error("internal: unsupported operand type %r" % (op,))def _compile_charset(charset, flags, code):# compile charset subprogramemit = code.appendfor op, av in charset:emit(op)if op is NEGATE:passelif op is LITERAL:emit(av)elif op is RANGE or op is RANGE_UNI_IGNORE:emit(av[0])emit(av[1])elif op is CHARSET:code.extend(av)elif op is BIGCHARSET:code.extend(av)elif op is CATEGORY:if flags & SRE_FLAG_LOCALE:emit(CH_LOCALE[av])elif flags & SRE_FLAG_UNICODE:emit(CH_UNICODE[av])else:emit(av)else:raise error("internal: unsupported set operator %r" % (op,))emit(FAILURE)def _optimize_charset(charset, iscased=None, fixup=None, fixes=None):# internal: optimize character setout = []tail = []charmap = bytearray(256)hascased = Falsefor op, av in charset:while True:try:if op is LITERAL:if fixup:lo = fixup(av)charmap[lo] = 1if fixes and lo in fixes:for k in fixes[lo]:charmap[k] = 1if not hascased and iscased(av):hascased = Trueelse:charmap[av] = 1elif op is RANGE:r = range(av[0], av[1]+1)if fixup:if fixes:for i in map(fixup, r):charmap[i] = 1if i in fixes:for k in fixes[i]:charmap[k] = 1else:for i in map(fixup, r):charmap[i] = 1if not hascased:hascased = any(map(iscased, r))else:for i in r:charmap[i] = 1elif op is NEGATE:out.append((op, av))else:tail.append((op, av))except IndexError:if len(charmap) == 256:# character set contains non-UCS1 character codescharmap += b'0円' * 0xff00continue# Character set contains non-BMP character codes.if fixup:hascased = True# There are only two ranges of cased non-BMP characters:# 10400-1044F (Deseret) and 118A0-118DF (Warang Citi),# and for both ranges RANGE_UNI_IGNORE works.if op is RANGE:op = RANGE_UNI_IGNOREtail.append((op, av))break# compress character mapruns = []q = 0while True:p = charmap.find(1, q)if p < 0:breakif len(runs) >= 2:runs = Nonebreakq = charmap.find(0, p)if q < 0:runs.append((p, len(charmap)))breakruns.append((p, q))if runs is not None:# use literal/rangefor p, q in runs:if q - p == 1:out.append((LITERAL, p))else:out.append((RANGE, (p, q - 1)))out += tail# if the case was changed or new representation is more compactif hascased or len(out) < len(charset):return out, hascased# else original character set is good enoughreturn charset, hascased# use bitmapif len(charmap) == 256:data = _mk_bitmap(charmap)out.append((CHARSET, data))out += tailreturn out, hascased# To represent a big charset, first a bitmap of all characters in the# set is constructed. Then, this bitmap is sliced into chunks of 256# characters, duplicate chunks are eliminated, and each chunk is# given a number. In the compiled expression, the charset is# represented by a 32-bit word sequence, consisting of one word for# the number of different chunks, a sequence of 256 bytes (64 words)# of chunk numbers indexed by their original chunk position, and a# sequence of 256-bit chunks (8 words each).# Compression is normally good: in a typical charset, large ranges of# Unicode will be either completely excluded (e.g. if only cyrillic# letters are to be matched), or completely included (e.g. if large# subranges of Kanji match). These ranges will be represented by# chunks of all one-bits or all zero-bits.# Matching can be also done efficiently: the more significant byte of# the Unicode character is an index into the chunk number, and the# less significant byte is a bit index in the chunk (just like the# CHARSET matching).charmap = bytes(charmap) # should be hashablecomps = {}mapping = bytearray(256)block = 0data = bytearray()for i in range(0, 65536, 256):chunk = charmap[i: i + 256]if chunk in comps:mapping[i // 256] = comps[chunk]else:mapping[i // 256] = comps[chunk] = blockblock += 1data += chunkdata = _mk_bitmap(data)data[0:0] = [block] + _bytes_to_codes(mapping)out.append((BIGCHARSET, data))out += tailreturn out, hascased_CODEBITS = _sre.CODESIZE * 8MAXCODE = (1 << _CODEBITS) - 1_BITS_TRANS = b'0' + b'1' * 255def _mk_bitmap(bits, _CODEBITS=_CODEBITS, _int=int):s = bits.translate(_BITS_TRANS)[::-1]return [_int(s[i - _CODEBITS: i], 2)for i in range(len(s), 0, -_CODEBITS)]def _bytes_to_codes(b):# Convert block indices to word arraya = memoryview(b).cast('I')assert a.itemsize == _sre.CODESIZEassert len(a) * a.itemsize == len(b)return a.tolist()def _simple(p):# check if this subpattern is a "simple" operatorif len(p) != 1:return Falseop, av = p[0]if op is SUBPATTERN:return av[0] is None and _simple(av[-1])return op in _UNIT_CODESdef _generate_overlap_table(prefix):"""Generate an overlap table for the following prefix.An overlap table is a table of the same size as the prefix whichinforms about the potential self-overlap for each index in the prefix:- if overlap[i] == 0, prefix[i:] can't overlap prefix[0:...]- if overlap[i] == k with 0 < k <= i, prefix[i-k+1:i+1] overlaps withprefix[0:k]"""table = [0] * len(prefix)for i in range(1, len(prefix)):idx = table[i - 1]while prefix[i] != prefix[idx]:if idx == 0:table[i] = 0breakidx = table[idx - 1]else:table[i] = idx + 1return tabledef _get_iscased(flags):if not flags & SRE_FLAG_IGNORECASE:return Noneelif flags & SRE_FLAG_UNICODE:return _sre.unicode_iscasedelse:return _sre.ascii_iscaseddef _get_literal_prefix(pattern, flags):# look for literal prefixprefix = []prefixappend = prefix.appendprefix_skip = Noneiscased = _get_iscased(flags)for op, av in pattern.data:if op is LITERAL:if iscased and iscased(av):breakprefixappend(av)elif op is SUBPATTERN:group, add_flags, del_flags, p = avflags1 = _combine_flags(flags, add_flags, del_flags)if flags1 & SRE_FLAG_IGNORECASE and flags1 & SRE_FLAG_LOCALE:breakprefix1, prefix_skip1, got_all = _get_literal_prefix(p, flags1)if prefix_skip is None:if group is not None:prefix_skip = len(prefix)elif prefix_skip1 is not None:prefix_skip = len(prefix) + prefix_skip1prefix.extend(prefix1)if not got_all:breakelse:breakelse:return prefix, prefix_skip, Truereturn prefix, prefix_skip, Falsedef _get_charset_prefix(pattern, flags):while True:if not pattern.data:return Noneop, av = pattern.data[0]if op is not SUBPATTERN:breakgroup, add_flags, del_flags, pattern = avflags = _combine_flags(flags, add_flags, del_flags)if flags & SRE_FLAG_IGNORECASE and flags & SRE_FLAG_LOCALE:return Noneiscased = _get_iscased(flags)if op is LITERAL:if iscased and iscased(av):return Nonereturn [(op, av)]elif op is BRANCH:charset = []charsetappend = charset.appendfor p in av[1]:if not p:return Noneop, av = p[0]if op is LITERAL and not (iscased and iscased(av)):charsetappend((op, av))else:return Nonereturn charsetelif op is IN:charset = avif iscased:for op, av in charset:if op is LITERAL:if iscased(av):return Noneelif op is RANGE:if av[1] > 0xffff:return Noneif any(map(iscased, range(av[0], av[1]+1))):return Nonereturn charsetreturn Nonedef _compile_info(code, pattern, flags):# internal: compile an info block. in the current version,# this contains min/max pattern width, and an optional literal# prefix or a character maplo, hi = pattern.getwidth()if hi > MAXCODE:hi = MAXCODEif lo == 0:code.extend([INFO, 4, 0, lo, hi])return# look for a literal prefixprefix = []prefix_skip = 0charset = [] # not usedif not (flags & SRE_FLAG_IGNORECASE and flags & SRE_FLAG_LOCALE):# look for literal prefixprefix, prefix_skip, got_all = _get_literal_prefix(pattern, flags)# if no prefix, look for charset prefixif not prefix:charset = _get_charset_prefix(pattern, flags)## if prefix:## print("*** PREFIX", prefix, prefix_skip)## if charset:## print("*** CHARSET", charset)# add an info blockemit = code.appendemit(INFO)skip = len(code); emit(0)# literal flagmask = 0if prefix:mask = SRE_INFO_PREFIXif prefix_skip is None and got_all:mask = mask | SRE_INFO_LITERALelif charset:mask = mask | SRE_INFO_CHARSETemit(mask)# pattern lengthif lo < MAXCODE:emit(lo)else:emit(MAXCODE)prefix = prefix[:MAXCODE]emit(min(hi, MAXCODE))# add literal prefixif prefix:emit(len(prefix)) # lengthif prefix_skip is None:prefix_skip = len(prefix)emit(prefix_skip) # skipcode.extend(prefix)# generate overlap tablecode.extend(_generate_overlap_table(prefix))elif charset:charset, hascased = _optimize_charset(charset)assert not hascased_compile_charset(charset, flags, code)code[skip] = len(code) - skipdef isstring(obj):return isinstance(obj, (str, bytes))def _code(p, flags):flags = p.state.flags | flagscode = []# compile info block_compile_info(code, p, flags)# compile the pattern_compile(code, p.data, flags)code.append(SUCCESS)return codedef _hex_code(code):return '[%s]' % ', '.join('%#0*x' % (_sre.CODESIZE*2+2, x) for x in code)def dis(code):import syslabels = set()level = 0offset_width = len(str(len(code) - 1))def dis_(start, end):def print_(*args, to=None):if to is not None:labels.add(to)args += ('(to %d)' % (to,),)print('%*d%s ' % (offset_width, start, ':' if start in labels else '.'),end=' '*(level-1))print(*args)def print_2(*args):print(end=' '*(offset_width + 2*level))print(*args)nonlocal levellevel += 1i = startwhile i < end:start = iop = code[i]i += 1op = OPCODES[op]if op in (SUCCESS, FAILURE, ANY, ANY_ALL,MAX_UNTIL, MIN_UNTIL, NEGATE):print_(op)elif op in (LITERAL, NOT_LITERAL,LITERAL_IGNORE, NOT_LITERAL_IGNORE,LITERAL_UNI_IGNORE, NOT_LITERAL_UNI_IGNORE,LITERAL_LOC_IGNORE, NOT_LITERAL_LOC_IGNORE):arg = code[i]i += 1print_(op, '%#02x (%r)' % (arg, chr(arg)))elif op is AT:arg = code[i]i += 1arg = str(ATCODES[arg])assert arg[:3] == 'AT_'print_(op, arg[3:])elif op is CATEGORY:arg = code[i]i += 1arg = str(CHCODES[arg])assert arg[:9] == 'CATEGORY_'print_(op, arg[9:])elif op in (IN, IN_IGNORE, IN_UNI_IGNORE, IN_LOC_IGNORE):skip = code[i]print_(op, skip, to=i+skip)dis_(i+1, i+skip)i += skipelif op in (RANGE, RANGE_UNI_IGNORE):lo, hi = code[i: i+2]i += 2print_(op, '%#02x %#02x (%r-%r)' % (lo, hi, chr(lo), chr(hi)))elif op is CHARSET:print_(op, _hex_code(code[i: i + 256//_CODEBITS]))i += 256//_CODEBITSelif op is BIGCHARSET:arg = code[i]i += 1mapping = list(b''.join(x.to_bytes(_sre.CODESIZE, sys.byteorder)for x in code[i: i + 256//_sre.CODESIZE]))print_(op, arg, mapping)i += 256//_sre.CODESIZElevel += 1for j in range(arg):print_2(_hex_code(code[i: i + 256//_CODEBITS]))i += 256//_CODEBITSlevel -= 1elif op in (MARK, GROUPREF, GROUPREF_IGNORE, GROUPREF_UNI_IGNORE,GROUPREF_LOC_IGNORE):arg = code[i]i += 1print_(op, arg)elif op is JUMP:skip = code[i]print_(op, skip, to=i+skip)i += 1elif op is BRANCH:skip = code[i]print_(op, skip, to=i+skip)while skip:dis_(i+1, i+skip)i += skipstart = iskip = code[i]if skip:print_('branch', skip, to=i+skip)else:print_(FAILURE)i += 1elif op in (REPEAT, REPEAT_ONE, MIN_REPEAT_ONE):skip, min, max = code[i: i+3]if max == MAXREPEAT:max = 'MAXREPEAT'print_(op, skip, min, max, to=i+skip)dis_(i+3, i+skip)i += skipelif op is GROUPREF_EXISTS:arg, skip = code[i: i+2]print_(op, arg, skip, to=i+skip)i += 2elif op in (ASSERT, ASSERT_NOT):skip, arg = code[i: i+2]print_(op, skip, arg, to=i+skip)dis_(i+2, i+skip)i += skipelif op is INFO:skip, flags, min, max = code[i: i+4]if max == MAXREPEAT:max = 'MAXREPEAT'print_(op, skip, bin(flags), min, max, to=i+skip)start = i+4if flags & SRE_INFO_PREFIX:prefix_len, prefix_skip = code[i+4: i+6]print_2(' prefix_skip', prefix_skip)start = i + 6prefix = code[start: start+prefix_len]print_2(' prefix','[%s]' % ', '.join('%#02x' % x for x in prefix),'(%r)' % ''.join(map(chr, prefix)))start += prefix_lenprint_2(' overlap', code[start: start+prefix_len])start += prefix_lenif flags & SRE_INFO_CHARSET:level += 1print_2('in')dis_(start, i+skip)level -= 1i += skipelse:raise ValueError(op)level -= 1dis_(0, len(code))def compile(p, flags=0):# internal: convert pattern list to internal formatif isstring(p):pattern = pp = sre_parse.parse(p, flags)else:pattern = Nonecode = _code(p, flags)if flags & SRE_FLAG_DEBUG:print()dis(code)# map in either directiongroupindex = p.state.groupdictindexgroup = [None] * p.state.groupsfor k, i in groupindex.items():indexgroup[i] = kreturn _sre.compile(pattern, flags | p.state.flags, code,p.state.groups-1,groupindex, tuple(indexgroup))
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。