-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstring_parser.py
More file actions
163 lines (128 loc) · 5.29 KB
/
Copy pathstring_parser.py
File metadata and controls
163 lines (128 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#String Building algorithm for the Overwatch Workshop
#
#Heavily inspired by Deltins ParseString algorithm
#https://github.com/ItsDeltin/Overwatch-Script-To-Workshop/blob/91f6d89cae2dda77d40139a589c22077def7654f/Deltinteger/Deltinteger/Elements/Values.cs#L729
#Parts copied are used with permission.
import logging
import re
class StringParser():
SYMBOLS = "-></*-+=()!?"
PARAM_REPLACE_RE = re.compile("(\\\\{[0-9]+?\\\\})")
PARAM_MATCH_RE = re.compile("^\\{([0-9]+?)\\}")
PARAM_ONLY_RE = re.compile("^\\{([0-9]+?)\\}$")
logger = logging.getLogger("OS.StringParser")
def __init__(self, db_file="res/strings.txt"):
self.words = []
self.us_words = []
if db_file:
self.loadWords(db_file)
def loadWords(self, path):
"""
Load words from a file.
"""
with open(path, "r") as f:
for line in f.readlines():
if line.startswith("//"):
continue
self.words.append(line.strip("\n").lower())
self.sort()
def sort(self):
"""
Sort the internal list of words after
certain criteria.
"""
#Right so I don't have fancy incremental sorting like C# does.
#What I *can* do is split the list into multiple lists, then merge
#TODO: temporary fix
for i in self.words:
if "_" in i:
j = i.replace("_", " ")
self.us_words.append((i, j))
hasParam = []
for i in self.words[:]:
if "{0}" in i:
hasParam.append(i)
self.words.remove(i)
hasParamAndSymbol = []
for i in hasParam[:]:
for char in self.SYMBOLS:
if char in i:
hasParamAndSymbol.append(i)
hasParam.remove(i)
break
hasSymbol = []
for i in self.words[:]:
for char in self.SYMBOLS:
if char in i:
hasSymbol.append(i)
self.words.remove(i)
break
#Sorting key function
def f(x):
return len(x)
hasParam.sort(key=f)
hasParamAndSymbol.sort(key=f)
hasSymbol.sort(key=f)
self.words.sort(key=f)
self.words.extend(hasSymbol)
self.words.extend(hasParam)
self.words.extend(hasParamAndSymbol)
self.words.reverse()
def parse(self, s, params, depth=0):
"""
Parse a string into a value understood by OWW.
s should be an instance of str.
You can specify parameters inside your string using
the {n} syntax. Parameters will be substituted in order
of occurance.
If s contains words or phrases not recognized by the parser,
ValueError is raised.
If params contains more items than s has parameters, the remaining
items are silently dropped.
If params contains less items than s has parameters, TypeError is raised.
The returned value will be a string consisting of one or multiple calls
to the String() OWW function.
"""
final_string = ""
#TODO: temporary fix
if not depth:
for template, phrase in self.us_words:
s = s.replace(phrase, template)
#special case for when the string passed to the parse() method
#is literally just "{n}"
m = self.PARAM_ONLY_RE.fullmatch(s)
if m is not None:
return params[int(m.group(1))]
for template in self.words:
temp_re = "^%s$" % re.sub(self.PARAM_REPLACE_RE, "(.+)", re.escape(template))
self.logger.debug("Testing string template '%s' (-> RE template '%s')..." % (template, temp_re))
match = re.match(temp_re, s)
if match is not None:
try:
self.logger.debug("Match found: %s" % template)
#TODO: Temporary fix
#string_args = ['"%s"' % template]
string_args = ['"%s"' % template.replace("_", " ")]
#check parameters
for group in match.groups():
#is parameter formatted?
self.logger.debug("Parsing group '%s'..." % group)
paramStr = re.fullmatch(self.PARAM_MATCH_RE, group)
if paramStr:
#substitute parameter
try:
string_args.append(params[int(paramStr.group(1))])
except IndexError:
raise TypeError("Not enough arguments to format string.")
else:
#keep parsing
string_args.append(self.parse(group, params))
string_args.extend(["null"] * (4 - len(string_args)))
final_string += "String(%s)" % ", ".join(string_args)
break
except ValueError as e:
self.logger.debug("%s. Trying next template..." % str(e))
continue
else:
raise ValueError("Can't match string '%s': No matching template found." % s)
return final_string