阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
译文里的
1,234.50
变成
1.234,50
,可能只是数字区域格式改变,也可能被错误解析成另一个数量。数字核对必须先声明输入规则,再比较规范化值;币种和单位应作为另一项独立字段保留。
不让服务器语言代替业务协议
本文仅覆盖两种明确格式:逗号千位、点号小数,以及点号千位、逗号小数。空格千位、括号负数、科学计数法和其他写法不在范围内。来源规则不明时,应拒绝猜测。
先校验格式,再做 Decimal 转换
import re
from decimal import Decimal
def amount(text, style):
rules = {
"comma_group": (r"-?(?:[0-9]{1,3}(?:,[0-9]{3})+|[0-9]+)(?:\.[0-9]+)?", ",", "."),
"dot_group": (r"-?(?:[0-9]{1,3}(?:\.[0-9]{3})+|[0-9]+)(?:,[0-9]+)?", ".", ",")
}
if style not in rules:
raise ValueError("unknown number convention")
pattern, grouping, decimal = rules[style]
if re.fullmatch(pattern, text) is None:
raise ValueError("number does not match declared convention")
return Decimal(text.replace(grouping, "").replace(decimal, "."))
assert amount("1,234.50", "comma_group") == amount("1.234,50", "dot_group")
assert amount("-12.50", "comma_group") == Decimal("-12.50")
assert (amount("12.50", "comma_group"), "USD") != (amount("12.50", "comma_group"), "EUR")
for bad in ["12,34.50", "1,234.50 USD", "NaN"]:
try:
amount(bad, "comma_group")
except ValueError:
pass
else:
raise AssertionError("invalid number accepted")
数值相同还不够
这段代码接收已经定位的金额字符串,不从任意文档里自动找到金额。定位字段时应保留标签、币种与来源位置。数字相同但单位从公斤变成磅,或者从总价变成单价,都不是一次正确的核对。
对照结果
应检查
不应自动做
值相同、币种不同
货币标记是否被改
默认视为等价
格式不符合声明
来源区域或提取错误
无条件删除所有标点
负号消失
原文与译文上下文
自动取绝对值
精度减少
是否按规则舍入
把差异一律忽略
Decimal 解决的只是部分问题
使用 Decimal 可以避免某些二进制浮点表示误差,但不能替你选择舍入规则、解释税额或执行汇率换算。对数值做任何转换,都应该在清单中保留转换前后的值和原因。
翻译文件中的数字值得单独验收
通过
OmniDoc(产品入口)
处理报价、报表或技术资料时,可以先整理金额与单位检查项,再对照译稿。数字检查负责发现疑点,最终仍要回到原文确定它代表哪一个业务字段。
参考:
Python decimal
。
- 1 -
更新于 2026-10-08