OzoneAsai commited on
Commit
64e6fb0
·
verified ·
1 Parent(s): e674fc9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +188 -0
app.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from decimal import Decimal, ROUND_HALF_UP
3
+ import re
4
+ from datetime import datetime
5
+
6
+ app = Flask(__name__)
7
+
8
+ # 入れ子構造を持つ単位変換用の辞書
9
+ CONVERSION_TABLE = {
10
+ 'length': {
11
+ 'm': 1,
12
+ 'cm': 0.01,
13
+ 'mm': 0.001,
14
+ 'km': 1000,
15
+ },
16
+ 'time': {
17
+ 's': 1,
18
+ 'min': 60,
19
+ 'h': 3600,
20
+ },
21
+ 'mass': {
22
+ 'g': 1,
23
+ 'kg': 1000,
24
+ 'mg': 0.001,
25
+ 'µg': 1e-6,
26
+ },
27
+ 'volume': {
28
+ 'L': 1,
29
+ 'mL': 0.001,
30
+ }
31
+ }
32
+
33
+ def log(message):
34
+ """タイムスタンプ付きでメッセージを出力"""
35
+ timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
36
+ print(f"[{timestamp}] {message}")
37
+
38
+ def parse_value_unit(value_unit_str):
39
+ """数値と単位をパースして、共通単位に変換"""
40
+ log(f"Parsing: {value_unit_str}")
41
+ match = re.match(r"([\d.]+)\s*\[([a-zA-Zµ^2]+)\]", value_unit_str)
42
+ if match:
43
+ value, unit = match.groups()
44
+ log(f"Parsed value: {value}, unit: {unit}")
45
+ return Decimal(value), unit
46
+ else:
47
+ raise ValueError("Invalid format. The input should be in the form 'value[unit]'.")
48
+
49
+ def find_unit_family(unit):
50
+ """指定された単位のファミリー(カテゴリ)を見つける"""
51
+ for family, units in CONVERSION_TABLE.items():
52
+ if unit in units:
53
+ return family
54
+ raise ValueError(f"Unit {unit} not found in any known unit families.")
55
+
56
+ def convert_to_common_unit(value, from_unit, to_unit):
57
+ """異なる単位を同じ単位に変換する"""
58
+ from_family = find_unit_family(from_unit)
59
+ to_family = find_unit_family(to_unit)
60
+
61
+ if from_family != to_family:
62
+ raise ValueError(f"Cannot convert between different unit families: {from_unit} to {to_unit}")
63
+
64
+ conversion_factor = CONVERSION_TABLE[from_family][from_unit] / CONVERSION_TABLE[to_family][to_unit]
65
+ converted_value = value * Decimal(conversion_factor)
66
+ log(f"Converting {value} {from_unit} to {converted_value} {to_unit}")
67
+ return converted_value
68
+
69
+ def calculate_expression(expression):
70
+ """複数の数値を処理する計算(加算、減算、乗算、除算に対応)"""
71
+ log(f"Calculating expression: {expression}")
72
+ pattern = r"([\d.]+\s*\[[^\]]+\])"
73
+ terms = re.findall(pattern, expression)
74
+ log(f"Found terms: {terms}")
75
+
76
+ if not terms:
77
+ raise ValueError("Invalid expression format")
78
+
79
+ # 最初の項目を取得
80
+ value1, unit1 = parse_value_unit(terms[0])
81
+ total_value = value1
82
+ decimal_places_list = [len(str(value1).replace('.', '').replace('-', ''))] # 有効数字のリストを保存
83
+
84
+ for i in range(1, len(terms)):
85
+ value2, unit2 = parse_value_unit(terms[i])
86
+
87
+ # 単位変換
88
+ if unit1 != unit2:
89
+ value2 = convert_to_common_unit(value2, unit2, unit1)
90
+
91
+ total_value += value2
92
+ decimal_places_list.append(len(str(value2).replace('.', '').replace('-', '')))
93
+ log(f"Current total: {total_value}, current significant figures list: {decimal_places_list}")
94
+
95
+ # 最も少ない有効数字に基づいて丸める
96
+ min_sig_figs = min(decimal_places_list)
97
+ rounded_result = total_value.quantize(Decimal('1e{0}'.format(-(min_sig_figs - 1))), rounding=ROUND_HALF_UP)
98
+ log(f"Final result: {rounded_result} [{unit1}]")
99
+
100
+ return f"{rounded_result} [{unit1}]"
101
+
102
+ # HTMLテンプレート(バイト列でエンコード)
103
+ template = b"""
104
+ <!DOCTYPE html>
105
+ <html lang="en">
106
+ <head>
107
+ <meta charset="UTF-8">
108
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
109
+ <title>Unit Calculator</title>
110
+ <style>
111
+ body {
112
+ font-family: Arial, sans-serif;
113
+ background-color: #f4f4f4;
114
+ margin: 0;
115
+ padding: 20px;
116
+ }
117
+ h1 {
118
+ color: #333;
119
+ }
120
+ form {
121
+ margin-bottom: 20px;
122
+ }
123
+ input[type="text"] {
124
+ padding: 8px;
125
+ width: 300px;
126
+ font-size: 16px;
127
+ }
128
+ button {
129
+ padding: 8px 12px;
130
+ font-size: 16px;
131
+ background-color: #007BFF;
132
+ color: #fff;
133
+ border: none;
134
+ cursor: pointer;
135
+ }
136
+ button:hover {
137
+ background-color: #0056b3;
138
+ }
139
+ .result {
140
+ font-size: 20px;
141
+ font-weight: bold;
142
+ color: #007BFF;
143
+ }
144
+ </style>
145
+ </head>
146
+ <body>
147
+ <h1>Unit Calculator</h1>
148
+ <form id="calcForm">
149
+ <label for="expression">Enter expression:</label>
150
+ <input type="text" id="expression" name="expression" required>
151
+ <button type="submit">Calculate</button>
152
+ </form>
153
+ <div id="result" class="result"></div>
154
+
155
+ <script>
156
+ document.getElementById('calcForm').addEventListener('submit', function(event) {
157
+ event.preventDefault();
158
+ var expression = document.getElementById('expression').value;
159
+ var xhr = new XMLHttpRequest();
160
+ xhr.open('POST', '/calculate', true);
161
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
162
+ xhr.onreadystatechange = function () {
163
+ if (xhr.readyState === 4 && xhr.status === 200) {
164
+ document.getElementById('result').innerText = 'Result: ' + xhr.responseText;
165
+ }
166
+ };
167
+ xhr.send('expression=' + encodeURIComponent(expression));
168
+ });
169
+ </script>
170
+ </body>
171
+ </html>
172
+ """
173
+
174
+ @app.route('/', methods=['GET'])
175
+ def index():
176
+ return render_template_string(template.decode('utf-8'))
177
+
178
+ @app.route('/calculate', methods=['POST'])
179
+ def calculate():
180
+ expression = request.form['expression']
181
+ try:
182
+ result = calculate_expression(expression)
183
+ return result
184
+ except Exception as e:
185
+ return f"Error: {str(e)}", 400
186
+
187
+ if __name__ == '__main__':
188
+ app.run(debug=True)