from flask import Flask, request, render_template_string from decimal import Decimal, ROUND_HALF_UP, InvalidOperation import re from datetime import datetime app = Flask(__name__) # 入れ子構造を持つ単位変換用の辞書 CONVERSION_TABLE = { 'length': { 'm': 1, 'cm': 0.01, 'mm': 0.001, 'km': 1000, }, 'time': { 's': 1, 'min': 60, 'h': 3600, }, 'mass': { 'g': 1, 'kg': 1000, 'mg': 0.001, 'µg': 1e-6, }, 'volume': { 'L': 1, 'mL': 0.001, } } def log(message): """タイムスタンプ付きでメッセージを出力""" timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3] print(f"[{timestamp}] {message}") def parse_value_unit(value_unit_str): """数値と単位をパースして、共通単位に変換""" log(f"Parsing: {value_unit_str}") match = re.match(r"([\d.eE+-]+)\s*\[([a-zA-Zµ^2]+)\]", value_unit_str) if match: value, unit = match.groups() log(f"Parsed value: {value}, unit: {unit}") try: decimal_value = Decimal(value) except InvalidOperation: raise ValueError(f"Invalid numeric value: {value}") sig_figs = len(value.split('.')[1]) if '.' in value else 0 return decimal_value, unit, sig_figs else: raise ValueError("Invalid format. The input should be in the form 'value[unit]'.") def find_unit_family(unit): """指定された単位のファミリー(カテゴリ)を見つける""" for family, units in CONVERSION_TABLE.items(): if unit in units: return family raise ValueError(f"Unit {unit} not found in any known unit families.") def convert_to_common_unit(value, from_unit, to_unit): """異なる単位を同じ単位に変換する""" from_family = find_unit_family(from_unit) to_family = find_unit_family(to_unit) if from_family != to_family: raise ValueError(f"Cannot convert between different unit families: {from_unit} to {to_unit}") conversion_factor = CONVERSION_TABLE[from_family][from_unit] / CONVERSION_TABLE[to_family][to_unit] converted_value = value * Decimal(conversion_factor) log(f"Converting {value} {from_unit} to {converted_value} {to_unit}") return converted_value def calculate_expression(expression): """複数の数値を処理する計算(加算、減算、乗算、除算に対応)""" log(f"Calculating expression: {expression}") pattern = r"([\d.eE+-]+\s*\[[^\]]+\])" terms = re.findall(pattern, expression) log(f"Found terms: {terms}") if not terms: raise ValueError("Invalid expression format") # 最初の項目を取得 value1, unit1, sig_figs1 = parse_value_unit(terms[0]) total_value = value1 total_unit = unit1 sig_figs_list = [sig_figs1] for i in range(1, len(terms)): value2, unit2, sig_figs2 = parse_value_unit(terms[i]) sig_figs_list.append(sig_figs2) if unit1 != unit2 and ('*' not in expression and '/' not in expression): value2 = convert_to_common_unit(value2, unit2, unit1) if '*' in expression: total_value *= value2 total_unit = f"{total_unit}*{unit2}" elif '/' in expression: total_value /= value2 total_unit = f"{total_unit}/{unit2}" else: total_value += value2 log(f"Current total: {total_value}, current significant figures list: {sig_figs_list}") # 最も少ない有効数字に基づいて丸める min_sig_figs = min(sig_figs_list) rounded_result = total_value.quantize(Decimal('1e{0}'.format(-(min_sig_figs - 1))), rounding=ROUND_HALF_UP) # 小数点以下のゼロを省略せずに表示 rounded_result_str = format(rounded_result, 'f') log(f"Final result: {rounded_result_str} [{total_unit}]") return f"{rounded_result_str} [{total_unit}]" # HTMLテンプレート(バイト列でエンコード) template = b"""