-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnumber_format.py
106 lines (90 loc) · 3.15 KB
/
number_format.py
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
#!/usr/bin/env python3
"""Parse and use C and numpy style format strings for usage with python"""
import re
class NumberFmt:
"""
Class to store format of numbers
"""
def __init__(self, number=None):
self.flags = ""
self.specifier = "f"
self.width = 14
self.precision = 9
if number is not None:
self.parse(number)
def parse(self, number):
"""
Parse format of number string.
It is not possible to determine all flags from single number, but works for most cases.
"""
try:
float(number)
except ValueError:
print("String is not a number")
self.width = len(number)
# test for signed flag
leading_spaces = len(number) - len(number.lstrip(" "))
if number[leading_spaces] == "+": # '-' is ambiguous
self.flags = "+"
dot_position = number.find(".")
if dot_position == -1: # number is an integer
self.specifier = "d"
self.precision = None
return
# check for exponential format
for e in ["e", "E"]:
e_position = number.find(e)
if e_position != -1:
self.specifier = e
self.precision = e_position - dot_position - 1
return
self.specifier = "f"
self.precision = len(number) - dot_position - 1
return
def get(self):
"""Return format as C style string"""
if self.precision:
fmt_str = "%{}{}.{}{}".format(
self.flags, self.width, self.precision, self.specifier
)
else:
fmt_str = "%{}{}{}".format(self.flags, self.width, self.specifier)
return fmt_str
def set(self, format_string):
"""Set class variables to the given Cg type string"""
if format_string[0] != "%":
raise ValueError("Not a C style number format")
if not format_string[1].isdigit():
self.flags = format_string[1]
self.width = int("".join(filter(str.isdigit, format_string.split(".")[0])))
self.precision = int("".join(filter(str.isdigit, format_string.split(".")[1])))
self.specifier = format_string[-1]
def get_string_from_file(filename, col):
"""
Get number string of file from the first non-header line and the given column
Tested only with plumed files
"""
with open(filename) as f:
for line in f:
if line.startswith("#"):
continue
pat = re.compile("\s*[\d+-.]+") # columns with trailing whitespace
try:
numstring = pat.findall(line)[col]
except IndexError: # happens if e.g. value is inf
continue
return numstring[1::] # remove delimiting whitespace
if __name__ == "__main__":
numbers = [
"21.5624",
"1.6345e-05",
"+6.276E+02",
"3122225",
"-2.43123",
" -63214",
" +3.541",
]
for num in numbers:
fmt = NumberFmt(num)
formatted_num = fmt.get() % (float(num))
print(num + ": " + fmt.get() + " -> " + formatted_num)