1 | from coalib.misc.StringConverter import StringConverter |
||
2 | from coalib.parsing.StringProcessing import unescape, convert_to_raw |
||
3 | |||
4 | |||
5 | class LineParser: |
||
6 | |||
7 | def __init__(self, |
||
8 | key_value_delimiters=('=',), |
||
9 | comment_seperators=('#',), |
||
10 | key_delimiters=(',', ' '), |
||
11 | section_name_surroundings=None, |
||
12 | section_override_delimiters=(".",)): |
||
13 | """ |
||
14 | Creates a new line parser. Please note that no delimiter or seperator |
||
15 | may be an "o" or you may encounter undefined behaviour with the |
||
16 | escapes. |
||
17 | |||
18 | :param key_value_delimiters: Delimiters that delimit a key from |
||
19 | a value |
||
20 | :param comment_seperators: Used to initiate a comment |
||
21 | :param key_delimiters: Delimiters between several keys |
||
22 | :param section_name_surroundings: Dictionary, e.g. {"[", "]"} means a |
||
23 | section name is surrounded by []. |
||
24 | If None, {"[": "]"} is used as |
||
25 | default. |
||
26 | :param section_override_delimiters: Delimiter for a section override. |
||
27 | E.g. "." would mean that |
||
28 | section.key is a possible key that |
||
29 | puts the key into the section |
||
30 | "section" despite of the current |
||
31 | section. |
||
32 | """ |
||
33 | section_name_surroundings = section_name_surroundings or {"[": "]"} |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
![]() |
|||
34 | |||
35 | self.key_value_delimiters = key_value_delimiters |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
36 | self.comment_seperators = comment_seperators |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
37 | self.key_delimiters = key_delimiters |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
38 | self.section_name_surroundings = section_name_surroundings |
||
39 | self.section_override_delimiters = section_override_delimiters |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
40 | |||
41 | def parse(self, line): |
||
42 | """ |
||
43 | Note that every value in the returned touple *besides the value* is |
||
44 | unescaped. This is so since the value is meant to be put into a Setting |
||
45 | later thus the escapes may be needed there. |
||
46 | |||
47 | :param line: the line to parse |
||
48 | :return: section_name (empty string if it's no section name), |
||
49 | [(section_override, key), ...], value, comment |
||
50 | """ |
||
51 | line, comment = self.__seperate_by_first_occurrence( |
||
52 | line, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
53 | self.comment_seperators) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
54 | comment = unescape(comment) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
55 | if line == "": |
||
56 | return '', [], '', comment |
||
57 | |||
58 | section_name = unescape(self.__get_section_name(line)) |
||
59 | if section_name != '': |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
60 | return section_name, [], '', comment |
||
61 | |||
62 | # Escapes in value might be needed by the bears |
||
63 | keys, value = self.__extract_keys_and_value(line) |
||
64 | |||
65 | # Add all the delimiters that stored as tuples |
||
66 | all_delimiters = self.key_value_delimiters |
||
67 | all_delimiters += self.key_delimiters |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
68 | all_delimiters += self.comment_seperators |
||
69 | all_delimiters += self.section_override_delimiters |
||
70 | all_delimiters = "".join(all_delimiters) |
||
71 | |||
72 | # Add all keys and values in section_name_surroundings, which is |
||
73 | # stored as a dict |
||
74 | all_delimiters += "".join(self.section_name_surroundings.keys()) |
||
75 | all_delimiters += "".join(self.section_name_surroundings.values()) |
||
76 | |||
77 | value = convert_to_raw(value, all_delimiters) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
78 | |||
79 | key_touples = [] |
||
80 | for key in keys: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
81 | key = convert_to_raw(key, all_delimiters) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
82 | section, key = self.__seperate_by_first_occurrence( |
||
83 | key, |
||
84 | self.section_override_delimiters, |
||
85 | True, |
||
86 | True) |
||
87 | key_touples.append((unescape(section), unescape(key))) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
88 | |||
89 | return '', key_touples, value, comment |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
90 | |||
91 | @staticmethod |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
92 | def __seperate_by_first_occurrence(string, |
||
93 | delimiters, |
||
94 | strip_delim=False, |
||
95 | return_second_part_nonempty=False): |
||
96 | """ |
||
97 | Seperates a string by the first of all given delimiters. Any whitespace |
||
98 | characters will be stripped away from the parts. |
||
99 | |||
100 | :param string: The string to seperate. |
||
101 | :param delimiters: The delimiters. |
||
102 | :param strip_delim: Strips the delimiter from the |
||
103 | result if true. |
||
104 | :param return_second_part_nonempty: If no delimiter is found and this |
||
105 | is true the contents of the string |
||
106 | will be returned in the second part |
||
107 | of the touple instead of the first |
||
108 | one. |
||
109 | :return: (first_part, second_part) |
||
110 | """ |
||
111 | temp_string = string.replace("\\\\", "oo") |
||
112 | i = temp_string.find("\\") |
||
113 | while i != -1: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
114 | temp_string = temp_string[:i] + "oo" + temp_string[i+2:] |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
115 | i = temp_string.find("\\", i+2) |
||
116 | |||
117 | delim_pos = len(string) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
118 | used_delim = "" |
||
119 | for delim in delimiters: |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
120 | pos = temp_string.find(delim) |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
121 | if 0 <= pos < delim_pos: |
||
122 | delim_pos = pos |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
123 | used_delim = delim |
||
124 | |||
125 | if return_second_part_nonempty and delim_pos == len(string): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
126 | return "", string.strip(" \n") |
||
127 | |||
128 | return ( |
||
129 | string[:delim_pos].strip(" \n"), |
||
130 | string[delim_pos + (len(used_delim) if strip_delim else 0):].strip( |
||
131 | " \n")) |
||
132 | |||
133 | def __get_section_name(self, line): |
||
134 | for begin, end in self.section_name_surroundings.items(): |
||
135 | if (line[0:len(begin)] == begin and |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
136 | line[len(line) - len(end):len(line)] == end): |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
137 | return line[len(begin):len(line) - len(end)].strip(" \n") |
||
138 | |||
139 | return '' |
||
140 | |||
141 | def __extract_keys_and_value(self, line): |
||
142 | key_part, value = self.__seperate_by_first_occurrence( |
||
143 | line, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
144 | self.key_value_delimiters, |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
145 | True, |
||
146 | True) |
||
147 | keys = list(StringConverter( |
||
148 | key_part, |
||
149 | list_delimiters=self.key_delimiters).__iter__( |
||
150 | remove_backslashes=False)) |
||
151 | |||
152 | return keys, value |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
153 |