Failed Conditions
Pull Request — master (#1152)
by Lasse
03:36
created

coalib.parsing.LineParser.__seperate_by_first_occurrence()   C

Complexity

Conditions 7

Size

Total Lines 41

Duplication

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