Selfie
Loading...
Searching...
No Matches
PerCharacterEscaper.py
Go to the documentation of this file.
3 self,
4 escape_code_point: int,
5 escaped_code_points: list[int],
6 escaped_by_code_points: list[int],
7 ):
8 self.__escape_code_point: int = escape_code_point
9 self.__escaped_code_points: list[int] = escaped_code_points
10 self.__escaped_by_code_points: list[int] = escaped_by_code_points
11
12 def __first_offset_needing_escape(self, input_string: str) -> int:
13 length: int = len(input_string)
14 for offset in range(length):
15 codepoint: int = ord(input_string[offset])
16 if (
17 codepoint == self.__escape_code_point
18 or codepoint in self.__escaped_code_points
19 ):
20 return offset
21 return -1
22
23 def escape(self, input_string: str) -> str:
24 no_escapes: int = self.__first_offset_needing_escape(input_string)
25 if no_escapes == -1:
26 return input_string
27 else:
28 result: list[str] = []
29 result.append(input_string[:no_escapes])
30 for char in input_string[no_escapes:]:
31 codepoint: int = ord(char)
32 if codepoint in self.__escaped_code_points:
33 idx: int = self.__escaped_code_points.index(codepoint)
34 result.append(chr(self.__escape_code_point))
35 result.append(chr(self.__escaped_by_code_points[idx]))
36 else:
37 result.append(char)
38 return "".join(result)
39
40 def unescape(self, input_string: str) -> str:
41 if input_string.endswith(
42 chr(self.__escape_code_point)
43 ) and not input_string.endswith(chr(self.__escape_code_point) * 2):
44 raise ValueError(
45 f"Escape character '{chr(self.__escape_code_point)}' can't be the last character in a string."
46 )
47
48 no_escapes: int = self.__first_offset_needing_escape(input_string)
49 if no_escapes == -1:
50 return input_string
51 else:
52 result: list[str] = [input_string[:no_escapes]]
53 skip_next: bool = False
54 for i in range(no_escapes, len(input_string)):
55 if skip_next:
56 skip_next = False
57 continue
58 codepoint: int = ord(input_string[i])
59 if codepoint == self.__escape_code_point and (i + 1) < len(
60 input_string
61 ):
62 next_codepoint: int = ord(input_string[i + 1])
63 if next_codepoint in self.__escaped_by_code_points:
64 idx: int = self.__escaped_by_code_points.index(next_codepoint)
65 result.append(chr(self.__escaped_code_points[idx]))
66 skip_next = True
67 else:
68 result.append(input_string[i + 1])
69 skip_next = True
70 else:
71 result.append(chr(codepoint))
72 return "".join(result)
73
74 @classmethod
75 def self_escape(cls, escape_policy: str) -> "PerCharacterEscaper":
76 code_points: list[int] = [ord(c) for c in escape_policy]
77 escape_code_point: int = code_points[0]
78 return cls(escape_code_point, code_points, code_points)
79
80 @classmethod
81 def specified_escape(cls, escape_policy: str) -> "PerCharacterEscaper":
82 code_points: list[int] = [ord(c) for c in escape_policy]
83 if len(code_points) % 2 != 0:
84 raise ValueError(
85 "Escape policy string must have an even number of characters."
86 )
87 escape_code_point: int = code_points[0]
88 escaped_code_points: list[int] = code_points[0::2]
89 escaped_by_code_points: list[int] = code_points[1::2]
90 return cls(escape_code_point, escaped_code_points, escaped_by_code_points)
"PerCharacterEscaper" self_escape(cls, str escape_policy)
"PerCharacterEscaper" specified_escape(cls, str escape_policy)
__init__(self, int escape_code_point, list[int] escaped_code_points, list[int] escaped_by_code_points)