Parser of berki style problems and generator of latex file
Samo Penic
2018-11-25 32d3f2f0b9ba799d732255599e1731074a9e6e57
commit | author | age
91fb15 1 from . import Exceptions
5288d6 2 from math import floor, log10
d89217 3
7b5760 4 STRING = 1
SP 5 FLOAT = 2
6
7
8 class Variable:
7e7033 9     def __init__(self, value=None, formatting=None):
993a25 10         self.formatted_value = None
7b5760 11         try:
SP 12             self.value = float(value)
7e7033 13             self.type = FLOAT
7b5760 14         except (ValueError, TypeError):
SP 15             self.type = STRING
08b2a2 16             self.value = value
SP 17             self.formatted_value = value
7b5760 18         if formatting is not None:
33c054 19             self.format_float(formatting)
7b5760 20         self.formatting = formatting
08b2a2 21
SP 22     def is_float(self):
ce4fc9 23         if self.type == FLOAT:
08b2a2 24             return True
SP 25         else:
26             return False
7b5760 27
33c054 28     def format_float(self, formatting=None):
993a25 29         if formatting is None:
SP 30             formatting = self.formatting
31         formatter = FormatterFactory.get_formatter(formatting)
32         self.formatted_value = formatter.getValue(self.value)
7b5760 33
da1010 34     def format_as_tex(self, formatting=None, glyph=None, unit=None, dollar="$"):
993a25 35         if formatting is None:
SP 36             formatting = self.formatting
04ee9d 37         formatter = FormatterFactory.get_formatter(formatting)
da1010 38         if formatting.split()[0] == "prefix":
SP 39             leading_space = ""
40         else:
39922f 41             leading_space = "\,"
5bc997 42         if formatting == "str" or formatting == "string":
04ee9d 43             return formatter.toFormat(self.value)
08b2a2 44         elif glyph is None and unit is None:
da1010 45             return ("{}{}{}{}").format(
SP 46                 dollar, formatter.toFormat(self.value), leading_space, dollar
08b2a2 47             )
da1010 48         elif glyph is None and unit is not None:
SP 49             return ("{}{}{}\mathrm{{{}}}{}{}").format(
50                 dollar, formatter.toFormat(self.value), leading_space, unit, dollar
51             )
52         elif glyph is not None and unit is None:
53             return ("{}{}={}{}{}").format(
54                 dollar, glyph, formatter.toFormat(self.value), leading_space, dollar
55             )
56         else:
57             return ("{}{}={}{}\mathrm{{{}}}{}").format(
58                 dollar,
59                 glyph,
60                 formatter.toFormat(self.value),
61                 leading_space,
62                 unit,
63                 dollar,
64             )
7b5760 65
SP 66     def get_formatted_value(self):
993a25 67         return self.formatted_value
08b2a2 68         # if self.type != STRING else self.value
7b5760 69
ef19a9 70     def __str__(self):
SP 71         return str(self.format_as_tex())
72
78d798 73     def __repr__(self):
SP 74         return self.__str__()
75
7b5760 76
d89217 77 class FormatterFactory:
404823 78     @staticmethod
SP 79     def get_formatter(formatstring):
80         spl = formatstring.split()
81         type = spl[0]
82         arglist = spl[1:]
83
5bc997 84         if type == "sci" or type == "scientific":
d89217 85             return SciFloatFormatter(arglist)
5bc997 86         elif type == "str" or type == "string":
993a25 87             return StringFormatter()
5bc997 88         elif type == "eng" or type == "engineering":
993a25 89             return EngFloatFormatter(arglist)
5bc997 90         elif type == "prefix":
SP 91             return PrefixFloatFormatter(arglist)
92         elif type == "dec" or type == "decimal":
839d16 93             return DecFloatFormatter(arglist)
404823 94         else:
SP 95             return None
5288d6 96
SP 97     @staticmethod
98     def fexp(f):
99         return int(floor(log10(abs(f)))) if f != 0 else 0
100
101     @staticmethod
102     def fman(f):
7b5760 103         return f / 10 ** FormatterFactory.fexp(f)
993a25 104
SP 105
106 class StringFormatter(FormatterFactory):
107     def __init__(self):
108         pass
109
110     def toFormat(self, string):
32d3f2 111         return string.replace('"', "")
993a25 112
SP 113     def getValue(self, string):
32d3f2 114         return '"{}"'.format(str(string.replace('"', "")))
SP 115
404823 116
839d16 117 class DecFloatFormatter(FormatterFactory):
SP 118     def __init__(self, formatparameters):
119         if len(formatparameters) != 1:
120             raise Exceptions.WrongParameters("Dec format accept only one argument")
121         self.precision = int(formatparameters[0])
122
123     def toFormat(self, num):
124         try:
125             num = float(num)
126         except ValueError:
127             raise ValueError
128         except TypeError:
129             raise ValueError
130
32d3f2 131         num = float(("{:." + str(self.precision - 1) + "e}").format(num))
SP 132         places = self.fexp(num)
34c8f6 133
32d3f2 134         decimal_places = self.precision - places - 1
SP 135         if decimal_places < 0:
136             decimal_places = 0
137         format_str = "{:" + str(places) + "." + str(decimal_places) + "f}"
839d16 138
8fe4d9 139         return format_str.format(num).replace(".", ",\!")
34c8f6 140
839d16 141     def getValue(self, num):
34c8f6 142
32d3f2 143         num = float(("{:." + str(self.precision - 1) + "e}").format(num))
SP 144         places = self.fexp(num)
34c8f6 145
32d3f2 146         decimal_places = self.precision - places - 1
SP 147         if decimal_places < 0:
148             decimal_places = 0
149         format_str = "{:" + str(places) + "." + str(decimal_places) + "f}"
150         val = format_str.format(num)
839d16 151         return float(val)
SP 152
404823 153
d89217 154 class SciFloatFormatter(FormatterFactory):
SP 155     def __init__(self, formatparameters):
404823 156         if len(formatparameters) != 1:
91fb15 157             raise Exceptions.WrongParameters("Sci format accept only one argument")
404823 158         self.precision = int(formatparameters[0])
SP 159
160     def toFormat(self, num):
161         try:
162             num = float(num)
163         except ValueError:
164             raise ValueError
165         except TypeError:
166             raise ValueError
167
7b5760 168         exp = self.fexp(num)
SP 169         man = self.fman(num)
78d798 170         if exp == 0:
08b2a2 171             return (
SP 172                 ("{:." + str(self.precision - 1) + "f}").format(man).replace(".", ",\!")
173             )
78d798 174         else:
08b2a2 175             return (
SP 176                 ("{:." + str(self.precision - 1) + "f} \cdot 10^{{{}}}")
177                 .format(man, int(exp))
178                 .replace(".", ",\!")
78d798 179             )
d89217 180
33c054 181     def getValue(self, num):
SP 182         exp = self.fexp(num)
183         man = self.fman(num)
78d798 184         man = ("{:." + str(self.precision - 1) + "f}e{}").format(man, int(exp))
33c054 185         return float(man)
d89217 186
78d798 187
ce4fc9 188 class EngFloatFormatter(FormatterFactory):
d89217 189     def __init__(self, formatparameters):
SP 190         if len(formatparameters) != 1:
191             raise Exceptions.WrongParameters("Eng format accept only one argument")
192         self.precision = int(formatparameters[0])
193
ce4fc9 194     def realign3(self, exp, man):
SP 195         mul = exp % 3
196         man = man * 10 ** mul
197         exp = exp - mul
198         return (exp, man)
199
d89217 200     def toFormat(self, num):
SP 201         try:
202             num = float(num)
ce4fc9 203         except ValueError:
d89217 204             raise ValueError
ce4fc9 205         except TypeError:
SP 206             raise ValueError
32d3f2 207         # Clip precision firstly
SP 208         num = float(("{:." + str(self.precision - 1) + "e}").format(num))
ce4fc9 209         exp = self.fexp(num)
SP 210         man = self.fman(num)
211         (exp, man) = self.realign3(exp, man)
32d3f2 212         decimal_places = self.precision - self.fexp(man) - 1
SP 213         if decimal_places < 0:
214             decimal_places = 0
ce4fc9 215         if exp == 0:
32d3f2 216             return ("{:." + str(decimal_places) + "f}").format(man).replace(".", ",\!")
ce4fc9 217         else:
SP 218             return (
32d3f2 219                 ("{:." + str(decimal_places) + "f} \cdot 10^{{{}}}")
ce4fc9 220                 .format(man, int(exp))
SP 221                 .replace(".", ",\!")
222             )
223
224     def getValue(self, num):
225         exp = self.fexp(num)
226         man = self.fman(num)
227         man = ("{:." + str(self.precision - 1) + "f}e{}").format(man, int(exp))
228         return float(man)
229
230
5bc997 231 class PrefixFloatFormatter(EngFloatFormatter):
ce4fc9 232     def __init__(self, formatparameters):
SP 233         if len(formatparameters) != 1:
234             raise Exceptions.WrongParameters("Dec format accept only one argument")
235         self.precision = int(formatparameters[0])
236
237     def exp2prefix(self, exp):
238         prefixes = {
239             "24": "Y",
240             "21": "Z",
241             "18": "E",
242             "15": "P",
243             "12": "T",
244             "9": "G",
245             "6": "M",
246             "3": "k",
247             "-3": "m",
da1010 248             "-6": "\\upmu",
SP 249             "-9": "n",
250             "-12": "p",
251             "-15": "f",
252             "-18": "a",
253             "-21": "z",
254             "-24": "y",
ce4fc9 255         }
SP 256         try:
257             prefix = prefixes[str(exp)]
258         except KeyError:
da1010 259             raise Exceptions.PrefixError(
SP 260                 "Could not change exponent " + str(exp) + " into prefix form!"
261             )
ce4fc9 262         return prefix
SP 263
264     def toFormat(self, num):
265         try:
266             num = float(num)
267         except ValueError:
268             raise ValueError
269         except TypeError:
270             raise ValueError
32d3f2 271         # Clip precision firstly
SP 272         num = float(("{:." + str(self.precision - 1) + "e}").format(num))
ce4fc9 273         exp = self.fexp(num)
SP 274         man = self.fman(num)
275         (exp, man) = self.realign3(exp, man)
32d3f2 276         decimal_places = self.precision - self.fexp(man) - 1
SP 277         if decimal_places < 0:
278             decimal_places = 0
ce4fc9 279         if exp == 0:
SP 280             return (
32d3f2 281                 ("{:." + str(decimal_places) + "f}\,").format(man).replace(".", ",\!")
ce4fc9 282             )
SP 283         else:
284             prefix = self.exp2prefix(exp)
285             return (
32d3f2 286                 ("{:." + str(decimal_places) + "f}\,\mathrm{{{}}}")
ce4fc9 287                 .format(man, prefix)
SP 288                 .replace(".", ",\!")
289             )