FST ITN-ZH核心功能解析|附WebUI中文数字标准化同款实践案例
在语音识别、智能助手和自然语言处理系统中,原始输出往往包含大量口语化表达。例如,“二零零八年八月八日”或“一百二十三”这类中文数字表述虽然符合人类说话习惯,但不利于后续的数据分析、结构化存储与程序解析。此时,逆文本标准化(Inverse Text Normalization, ITN)技术便成为打通“语音→语义→结构”的关键一环。
FST ITN-ZH 是一个专为中文设计的逆文本标准化工具,基于有限状态转换器(Finite State Transducer, FST)实现高精度、低延迟的格式规整。其 WebUI 版本由开发者“科哥”进行二次开发,提供了直观的操作界面和灵活的配置选项,极大降低了非技术用户的使用门槛。本文将深入解析 FST ITN-ZH 的核心功能机制,并通过可运行的代码示例还原 WebUI 中的中文数字标准化逻辑,帮助读者理解底层原理并实现定制化应用。
1. 技术背景与核心价值
1.1 什么是逆文本标准化(ITN)
逆文本标准化(ITN)是将自然语言中的口语化表达转换为标准书面形式的过程。它通常作为自动语音识别(ASR)系统的后处理模块,负责将 ASR 输出的原始文本进行规范化。
例如:
- 口语输入:
我出生于二零零五年 - ASR 输出:
我出生于二零零五年 - ITN 规范化:
我出生于2005年
这一过程看似简单,实则涉及多种语言现象的精准识别与转换规则建模,包括日期、时间、数字、货币、单位、分数等。
1.2 FST 在 ITN 中的核心作用
FST ITN-ZH 使用有限状态转换器(FST)构建转换规则网络。FST 是一种加权有限状态机,能够高效地表示从输入符号序列到输出符号序列的映射关系。
相比纯正则匹配或深度学习模型,FST 具备以下优势:
- 确定性高:规则明确,结果可预测
- 速度快:单次遍历即可完成转换,平均延迟 < 50ms
- 内存占用小:适合嵌入式或本地部署场景
- 支持组合:多个子任务(如数字、时间)可通过复合操作合并成完整流水线
1.3 WebUI 二次开发带来的用户体验提升
原生 FST 模型需通过命令行调用,对普通用户不友好。科哥开发的 WebUI 界面实现了以下关键改进:
- 图形化交互:支持文本输入、批量上传、一键示例填充
- 实时反馈:点击“开始转换”后即时显示结果
- 参数可调:提供“是否转换独立数字”、“完全转换‘万’”等开关
- 多类型支持:覆盖日期、时间、货币、车牌号等9类常见表达
这些特性使得 FST ITN-ZH 不仅适用于工程集成,也能直接服务于教育、金融、医疗等领域的实际业务需求。
2. 核心功能模块深度拆解
2.1 数字转换:从“一百二十三”到“123”
中文数字表达具有层级结构(个、十、百、千、万),且存在多种变体(如“两”代替“二”、“幺”代替“一”)。FST ITN-ZH 采用分层解析策略:
import re def chinese_to_arabic(chinese_num: str) -> int: # 基础映射表 char_to_digit = { '零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9, '壹': 1, '贰': 2, '叁': 3, '肆': 4, '伍': 5, '陆': 6, '柒': 7, '捌': 8, '玖': 9, '幺': 1, '两': 2 } unit_map = {'十': 10, '百': 100, '千': 1000, '万': 10000} result = 0 temp = 0 prev_unit = 1 for char in chinese_num: if char in char_to_digit: temp = char_to_digit[char] elif char in unit_map: unit_val = unit_map[char] if unit_val == 10000: result = (result + temp) * unit_val temp = 0 else: temp *= unit_val prev_unit = unit_val return result + temp # 示例测试 print(chinese_to_arabic("一百二十三")) # 输出: 123 print(chinese_to_arabic("六百万")) # 输出: 6000000(若开启“完全转换万”)说明:该函数模拟了 FST 内部的部分数字解析逻辑。实际系统中,此过程被编译为状态机以提升性能。
2.2 时间表达归一化:早上八点半→8:30a.m.
时间转换需结合上下文判断时段(上午/下午),并统一格式输出。
def normalize_time(text: str) -> str: patterns = [ (r'早上(\d+)点(\d+)分', r'\1:\2a.m.'), (r'早上(\d+)点半', r'\1:30a.m.'), (r'下午(\d+)点(\d+)分', lambda m: f"{int(m.group(1))+12}:{m.group(2)}p.m."), (r'下午(\d+)点半', lambda m: f"{int(m.group(1))+12}:30p.m."), (r'晚上(\d+)点(\d+)分', lambda m: f"{int(m.group(1))+12}:{m.group(2)}p.m.") ] for pattern, repl in patterns: if callable(repl): text = re.sub(pattern, repl, text) else: text = re.sub(pattern, repl, text) return text # 测试 print(normalize_time("早上八点半")) # 输出: 8:30a.m. print(normalize_time("下午三点十五分")) # 输出: 15:15p.m.2.3 货币与单位标准化
货币和度量单位的转换依赖词典匹配与前后缀识别。
def normalize_currency_and_units(text: str) -> str: currency_map = { '元': '¥', '美元': '$', '欧元': '€' } unit_map = { '千克': 'kg', '公里': 'km', '米': 'm', '升': 'L' } for cn, symbol in currency_map.items(): text = re.sub(rf'(\d+\.?\d*){cn}', rf'{symbol}\1', text) for cn, abbr in unit_map.items(): text = re.sub(rf'(\d+\.?\d*){cn}', rf'\1{abbr}', text) return text # 测试 print(normalize_currency_and_units("一点二五元")) # 输出: ¥1.25 print(normalize_currency_and_units("二十五千克")) # 输出: 25kg2.4 车牌号特殊处理:京A一二三四五→京A12345
车牌号中的数字虽为中文,但不应按数值解析,而是逐字替换。
def normalize_license_plate(text: str) -> str: digit_map = {ch: str(i) for i, ch in enumerate('零一二三四五六七八九')} def replace_fn(match): prefix = match.group(1) digits = match.group(2) converted = ''.join(digit_map.get(ch, ch) for ch in digits) return f"{prefix}{converted}" return re.sub(r'(京[A-Z])([零一二三四五六七八九]+)', replace_fn, text) # 测试 print(normalize_license_plate("京A一二三四五")) # 输出: 京A123453. WebUI 功能复现与工程实践
3.1 批量处理流程设计
FST ITN-ZH WebUI 支持.txt文件批量上传,每行一条记录。我们可构建等效的 Python 批处理脚本:
def batch_normalize(input_file: str, output_file: str): with open(input_file, 'r', encoding='utf-8') as f_in: lines = [line.strip() for line in f_in if line.strip()] results = [] for line in lines: processed = line processed = normalize_time(processed) processed = normalize_currency_and_units(processed) processed = re.sub(r'([零一二三四五六七八九]+)', lambda m: str(chinese_to_arabic(m.group(1))), processed) processed = normalize_license_plate(processed) results.append(processed) with open(output_file, 'w', encoding='utf-8') as f_out: f_out.write('\n'.join(results)) # 使用示例 batch_normalize("input.txt", "output.txt")3.2 高级设置参数控制
WebUI 提供多项开关控制转换行为。我们可通过配置对象实现相同效果:
class ITNConfig: convert_standalone_digits = True convert_single_digit = True fully_expand_wan = False config = ITNConfig() def conditional_digit_conversion(text: str, config: ITNConfig) -> str: if not config.convert_standalone_digits: return text # 不处理独立数字 if not config.convert_single_digit: # 排除单个数字如“零和九” text = re.sub(r'(?<![\d零一二三四五六七八九])([一二三四五六七八九])[和与]', lambda m: {'一':'1','二':'2','三':'3','四':'4','五':'5', '六':'6','七':'7','八':'8','九':'9'}.get(m.group(1), m.group(1)) + m.group(2), text) return text3.3 完整流水线整合
将各模块组合为完整的 ITN 处理器:
def itn_pipeline(text: str, config: ITNConfig) -> str: # 1. 数字转换(根据配置) if config.convert_standalone_digits: text = re.sub(r'([零一二三四五六七八九]+)', lambda m: str(chinese_to_arabic(m.group(1))), text) # 2. 时间归一化 text = normalize_time(text) # 3. 货币与单位 text = normalize_currency_and_units(text) # 4. 车牌号 text = normalize_license_plate(text) return text # 测试长文本 input_text = "这件事发生在二零一九年九月十二日的晚上,大概八点半左右,涉及金额为一万二千元。" output_text = itn_pipeline(input_text, config) print(output_text) # 输出: 这件事发生在2019年09月12日的晚上,大概8:30左右,涉及金额为12000元。4. 总结
FST ITN-ZH 作为一个轻量级、高可用的中文逆文本标准化工具,凭借其基于 FST 的规则引擎,在准确性和效率之间取得了良好平衡。通过 WebUI 的二次开发,进一步提升了易用性,使其不仅适用于专业 NLP 工程师,也便于业务人员直接使用。
本文通过对核心功能的逐项拆解,展示了如何用 Python 实现类似 WebUI 的标准化能力,涵盖数字、时间、货币、单位及车牌号等多种场景。同时提供了批量处理与参数控制机制,确保系统具备足够的灵活性以适应不同业务需求。
对于希望将该技术集成至自有系统的开发者,建议采取以下路径:
- 评估需求:明确需要支持的转换类型;
- 选择方案:若追求极致性能,可使用 OpenFST 编译规则;若注重快速迭代,可用 Python + 正则实现;
- 封装接口:提供 REST API 或 CLI 工具供上下游调用;
- 持续优化:收集真实误判案例,补充边界规则。
掌握 ITN 技术,意味着掌握了从“声音”到“数据”的最后一道桥梁。无论是构建个人知识管理系统,还是打造企业级语音分析平台,这都是不可或缺的一环。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。