""" Codec for the Punicode encoding, as specified in RFC 3492Written by Martin v. Löwis."""import codecs##################### Encoding #####################################def segregate(str):"""3.1 Basic code point segregation"""base = bytearray()extended = set()for c in str:if ord(c) < 128:base.append(ord(c))else:extended.add(c)extended = sorted(extended)return bytes(base), extendeddef selective_len(str, max):"""Return the length of str, considering only characters below max."""res = 0for c in str:if ord(c) < max:res += 1return resdef selective_find(str, char, index, pos):"""Return a pair (index, pos), indicating the next occurrence ofchar in str. index is the position of the character consideringonly ordinals up to and including char, and pos is the position inthe full string. index/pos is the starting position in the fullstring."""l = len(str)while 1:pos += 1if pos == l:return (-1, -1)c = str[pos]if c == char:return index+1, poselif c < char:index += 1def insertion_unsort(str, extended):"""3.2 Insertion unsort coding"""oldchar = 0x80result = []oldindex = -1for c in extended:index = pos = -1char = ord(c)curlen = selective_len(str, char)delta = (curlen+1) * (char - oldchar)while 1:index,pos = selective_find(str,c,index,pos)if index == -1:breakdelta += index - oldindexresult.append(delta-1)oldindex = indexdelta = 0oldchar = charreturn resultdef T(j, bias):# Punycode parameters: tmin = 1, tmax = 26, base = 36res = 36 * (j + 1) - biasif res < 1: return 1if res > 26: return 26return resdigits = b"abcdefghijklmnopqrstuvwxyz0123456789"def generate_generalized_integer(N, bias):"""3.3 Generalized variable-length integers"""result = bytearray()j = 0while 1:t = T(j, bias)if N < t:result.append(digits[N])return bytes(result)result.append(digits[t + ((N - t) % (36 - t))])N = (N - t) // (36 - t)j += 1def adapt(delta, first, numchars):if first:delta //= 700else:delta //= 2delta += delta // numchars# ((base - tmin) * tmax) // 2 == 455divisions = 0while delta > 455:delta = delta // 35 # base - tmindivisions += 36bias = divisions + (36 * delta // (delta + 38))return biasdef generate_integers(baselen, deltas):"""3.4 Bias adaptation"""# Punycode parameters: initial bias = 72, damp = 700, skew = 38result = bytearray()bias = 72for points, delta in enumerate(deltas):s = generate_generalized_integer(delta, bias)result.extend(s)bias = adapt(delta, points==0, baselen+points+1)return bytes(result)def punycode_encode(text):base, extended = segregate(text)deltas = insertion_unsort(text, extended)extended = generate_integers(len(base), deltas)if base:return base + b"-" + extendedreturn extended##################### Decoding #####################################def decode_generalized_number(extended, extpos, bias, errors):"""3.3 Generalized variable-length integers"""result = 0w = 1j = 0while 1:try:char = ord(extended[extpos])except IndexError:if errors == "strict":raise UnicodeError("incomplete punicode string")return extpos + 1, Noneextpos += 1if 0x41 <= char <= 0x5A: # A-Zdigit = char - 0x41elif 0x30 <= char <= 0x39:digit = char - 22 # 0x30-26elif errors == "strict":raise UnicodeError("Invalid extended code point '%s'"% extended[extpos])else:return extpos, Nonet = T(j, bias)result += digit * wif digit < t:return extpos, resultw = w * (36 - t)j += 1def insertion_sort(base, extended, errors):"""3.2 Insertion unsort coding"""char = 0x80pos = -1bias = 72extpos = 0while extpos < len(extended):newpos, delta = decode_generalized_number(extended, extpos,bias, errors)if delta is None:# There was an error in decoding. We can't continue because# synchronization is lost.return basepos += delta+1char += pos // (len(base) + 1)if char > 0x10FFFF:if errors == "strict":raise UnicodeError("Invalid character U+%x" % char)char = ord('?')pos = pos % (len(base) + 1)base = base[:pos] + chr(char) + base[pos:]bias = adapt(delta, (extpos == 0), len(base))extpos = newposreturn basedef punycode_decode(text, errors):if isinstance(text, str):text = text.encode("ascii")if isinstance(text, memoryview):text = bytes(text)pos = text.rfind(b"-")if pos == -1:base = ""extended = str(text, "ascii").upper()else:base = str(text[:pos], "ascii", errors)extended = str(text[pos+1:], "ascii").upper()return insertion_sort(base, extended, errors)### Codec APIsclass Codec(codecs.Codec):def encode(self, input, errors='strict'):res = punycode_encode(input)return res, len(input)def decode(self, input, errors='strict'):if errors not in ('strict', 'replace', 'ignore'):raise UnicodeError("Unsupported error handling "+errors)res = punycode_decode(input, errors)return res, len(input)class IncrementalEncoder(codecs.IncrementalEncoder):def encode(self, input, final=False):return punycode_encode(input)class IncrementalDecoder(codecs.IncrementalDecoder):def decode(self, input, final=False):if self.errors not in ('strict', 'replace', 'ignore'):raise UnicodeError("Unsupported error handling "+self.errors)return punycode_decode(input, self.errors)class StreamWriter(Codec,codecs.StreamWriter):passclass StreamReader(Codec,codecs.StreamReader):pass### encodings module APIdef getregentry():return codecs.CodecInfo(name='punycode',encode=Codec().encode,decode=Codec().decode,incrementalencoder=IncrementalEncoder,incrementaldecoder=IncrementalDecoder,streamwriter=StreamWriter,streamreader=StreamReader,)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。