日本价格解析器应当在返回金额的同时,一并返回币种证据、原始文本和计税基础。先选定一个报价字段,对 Unicode 规范化加以防护,并搁置含糊的输入。一个 parsed 字段在成为被接受的监控记录之前,仍然需要经过检查。
可下载的 Python 示例把这条边界讲得很明确。它的 36 个合成离线用例产生了 36 个预期分类:11 个已解析字段、25 个待复核结果,夹具失败为零。没有测试过任何日本店铺或代理。有用的结果是一组可复现的决策,其中也包括解析器何时拒绝选定价格。
一个价格展示可以包含两个合法金额
日本国税厅在其关于总价标示的指引中给出了这个例子:
10,000円(税込価格11,000円)明确含税的金额是 11,000 日元,尽管 10,000 出现在前面。国税厅的示例允许同时包含含税和不含税数字的价格展示。取第一个数字就会丢失这一区别。国税厅 No. 6902,标示示例。
删除所有非数字字符更糟:把 Python 的 re.sub(r"\D", "", text) 应用到这个字符串上,会得到 1000011000。随附的解析器返回 review,原因为 unsupported_or_multiple_price_text。它不会从包含多个价格的容器中选定一个金额。
应在上游解决这个问题:在所选报价中识别出目标金额及其标签,并保留来源上下文。如果你的提取器无法区分这些金额,就让这条记录保持待复核状态。一项一般性的标示义务并不能证明任意一个提取字段的计税基础。
解析之前先要求币种上下文
¥ 字符并不能证明币种是日元。Unicode 规定 U+00A5 同时用于日元和人民币元,与字形样式无关。在提供 JPY 之前,先为同一报价取得明确的币种上下文。Unicode 17,“Yen and Yuan”。
该函数只接受三个键,其中 text 限定为 1–200 个字符的字符串。下面是一个合成的夹具输入,其证据引用有意写成了一个夹具标签:
{
"text": "¥1,298(税込)",
"currency": "JPY",
"currency_evidence": "fixture.selected_offer.priceCurrency"
}对于这个输入,记录下来的结果是:
{
"original": "¥1,298(税込)",
"status": "parsed",
"normalized": "¥1,298(税込)",
"amount_yen": 1298,
"currency": "JPY",
"currency_evidence": "fixture.selected_offer.priceCurrency",
"tax_basis": "included",
"tax_label": "税込"
}在适配器中,用这三个键调用所下载模块中的 parse_price(record)。把商品标识、URL、时间戳和其他监控上下文放在外层记录中;该函数的输入中如果有多余的键,会返回 invalid_record。
证据引用是调用方的一项断言。 该函数要求一个非空字符串,但既不获取它,也不验证它的真实性。作者用一个刻意伪造的引用做了一次探测,仍然得到了 parsed。因此,仅因页面上有一个形似日元符号的字形就提供 JPY,即使解析器通过,也会违背预期的约定。请单独核查底层的币种证据,并保留冲突。
在规范化改变字段之前加以防护
全角数字可以表示普通的十进制数字,但兼容性规范化也会改变其他字符。Unicode 的 NFKC 形式可能抹去宽度之外的区别;Python 通过 unicodedata.normalize 提供它。Unicode 兼容数字、规范化指引、Python unicodedata。
这个解析器在规范化整个字段之前,会先逐个检查字符。它允许以下字符发生变化:全角 ASCII U+FF01–U+FF5E、表意空格 U+3000 和全角日元符号 U+FFE5。其他在 NFKC 下会改变的字符一律转入复核。语法在规范化之后检查;允许的宽度转换本身并不会让一个输入成为价格。
这个顺序对 ¥①298(税込) 和 ¥¹298(税込) 很重要。盲目的兼容性折叠可能把带圈字符或上标字符变成普通数字。夹具把两者都以 unsupported_compatibility_character 搁置。它也搁置 ASCII 和全角反斜杠;一个字符在字体中的外观并不会让它成为日元符号。
像上面那条成功的记录一样,把 original 与 normalized 一起保留。这种带防护的策略专属于所下载的解析器。它并不是建议对商品名称、标识符或任意页面文本不加区分地应用 NFKC。
保留计税基础,但不计算税额
解析器接受一个整日元表达式:¥1298、1298円 或 JPY 1298,可以带分组正确的逗号。受支持的尾随税务标签可以出现在括号中,或者跟在空白之后。它把 税込 和 税込価格 映射为 included;把 税抜、税抜き 和 税別 映射为 excluded。没有标签时产生 unspecified。
下面是从实际执行的夹具中选出的部分结果。除非另有说明,输入都带有 currency: "JPY" 和上面所示的合成证据引用。
| 输入字段 | 结果 | 对后续比较的影响 |
|---|---|---|
¥1,298(税込) | parsed:1298,included | 把含税基础与金额一起保留。 |
1,180円(税抜) | parsed:1180,excluded | 不要悄悄把它当作与含税金额相同的基础来比较。 |
1,298円 | parsed:1298,unspecified | 如果任务要求已知的计税基础,这项要求仍未解决。 |
10,000円(税込価格11,000円) | review | 解析之前先选定目标字段,并为其提供证据。 |
12,98円(税込) | review | 这种分组不符合本语法。 |
¥①298(税込) | review | 不受支持的兼容性变化会在规范化之前被搁置。 |
¥1298(税込),币种缺失或为 CNY | review | 一个熟悉的字形无法提供所需的 JPY 上下文。 |
这里没有税率计算、货币换算或以分为单位的乘数。在这个解析器的整日元输入约定下,amount_yen 是一个整数;它并不规定每个 API 所使用的单位。不要根据附近的数字推算出缺失的总额或净额。
该语法还会搁置价格区间、分期付款、积分、多个价格、负数、小数、汉字数字单位、前置税务标签和前导零。其中一些可能是本范围之外的有效店铺展示方式。review 结果表示该输入在本语法下尚未解决,而不是说商家的展示无效。
运行同一个离线夹具
把 parse_price.py 和 fixtures.json 下载到同一个目录。脚本使用 Python 标准库;README 给出了适用于 Python 3.10 或更新版本的输入约定和限制。运行:
python3 parse_price.py fixtures.json > replay.json该命令不发出任何网络请求。把 replay.json 与已发布的 results.json 进行比较。结果一致的运行会报告 cases: 36、passed: 36 和 failed: 0。那 25 个待复核结果是预期中的决策,因此不算作夹具失败。
夹具会检查每个声明的预期字段,并保留完整的实际输出。退出状态 0 表示夹具的预期全部相符;状态 1 表示至少有一项不符;状态 2 表示夹具无效或无法读取。这些状态都不是店铺层面的验收信号。
原始的环境记录记载了 Python 3.14.7 和 Unicode 数据库 16.0.0。作者在 Python 3.14.8 上的重放同样使用 Unicode 数据库 16.0.0,生成了完全相同的结果 JSON。引用 Unicode 17 的文档并不意味着可执行程序使用了 Unicode 17 数据库。
判断已解析的字段是否可用
在接受一条监控记录之前,把该字段绑定到确切的商品和变体,保留来源和观测时间,验证币种证据,并确定你的比较所需的价格基准。当任务依赖数量、会员资格、促销条件和配送上下文时,也要检查它们。这些决策都在这个解析器之外。
例如,夹具中 1298 日元的含税字段和 1180 日元的不含税字段都能解析。但这并不会让它们之间的数值差成为测得的价格变化。一个没有标签的字段同样可以解析,却仍然不适合用于要求含税价格的比较。
另一篇价格与币种验证案例讨论的是相互冲突的报价信号和店铺信号。如果你的采集还需要日本出口或指定的移动接入,请使用日本代理评估指南获取这方面的证据。本地解析结果不提供任何关于出口的国家、网络或可用性的证据。
方法:智能体辅助的来源研究与综合,并于 2026 年 10 月 6 日执行了合成夹具以及上文另行说明的限制探测。这些用例展示的是所述的解析器行为;它们不是日本零售商的样本,也不是准确率基准。没有测试任何店铺、代理或税额计算。
访问开放时通知我。访问开放时发送一封邮件。仅此而已。