文本规范化:数字、日期、时间、货币、单位的标准化转换
各位同学,咱们今天聊聊文本规范化。说实话,这活儿看着不起眼,但我在实际项目中吃过不少亏。你想想看,语音识别出来的结果,要是数字、日期这些基础信息都乱七八糟,后面的语义解析根本没法做。
文本规范化,说白了就是把口语化的表达转成标准格式。比如「二零二三年五月二十号」变成「2023-05-20」,「一百二十块五毛」变成「120.5元」。嗯,这里要注意,不同场景下的标准不一样,咱们得灵活处理。
数字的标准化
数字这块,我习惯分三种情况处理:整数、小数、序数。每种都有坑。
核心原则:中文数字转阿拉伯数字,但要保留原始语义。比如「两」和「二」在口语中经常混用,但「两」通常表示数量,「二」表示序号。
举个例子,我在项目中遇到过用户说「我要订两间房」,结果识别成「我要订2间房」。这没问题。但要是「第二间房」被转成「第2间房」,也OK。真正麻烦的是「一百二十」这种,有人会说「一百二」,有人会说「一百二十」,还有人会说「一百廿」——嗯,后者现在很少见了。
# 数字规范化示例
def normalize_number(text):
# 中文数字映射
chinese_num = {'零':0, '一':1, '二':2, '两':2, '三':3, '四':4,
'五':5, '六':6, '七':7, '八':8, '九':9}
# 单位映射
units = {'十':10, '百':100, '千':1000, '万':10000, '亿':100000000}
# 处理逻辑(简化版)
result = 0
temp = 0
for char in text:
if char in chinese_num:
temp = chinese_num[char]
elif char in units:
if temp == 0:
temp = 1
result += temp * units[char]
temp = 0
result += temp
return result
我的小技巧:处理「两」和「二」时,我一般保留原始用词。因为「两块钱」和「二块钱」虽然数值一样,但语感不同。不过要是做金融数据,统一转成阿拉伯数字更安全。
日期的标准化
日期格式,说实话,这是语音识别后处理里最头疼的部分之一。为什么?因为口语表达太灵活了。
「明天」、「后天」、「大后天」、「昨天」、「前天」——这些相对日期怎么转?「下周三」、「这个月十五号」、「去年春节」——这些带参照的日期怎么处理?
我曾经在一个客服项目中,用户说「我要预约这周五」,结果系统转成了「2023-11-17」。但问题是,用户说这话的时候是周四晚上11点59分。按常理,「这周五」应该指两天后,但系统按当天算,转成了第二天。嗯,这就是个典型的坑。
| 口语表达 | 标准格式 | 注意事项 |
|---|---|---|
| 今天 | 2023-11-15 | 需要获取当前日期 |
| 明天 | 2023-11-16 | 注意跨月、跨年 |
| 下周一 | 2023-11-20 | 周一是一周的开始 |
| 去年三月 | 2022-03 | 年份减1 |
| 五月二十号 | 2023-05-20 | 默认当年,跨年需处理 |
避坑指南:我曾经在处理「下个月三号」时,没考虑当月最后一天的情况。比如1月31号说「下个月三号」,按我的逻辑转成了2月3号。但2月没有31号,用户实际想说的是3月3号。所以,日期计算一定要考虑月份天数。
时间的标准化
时间规范化相对简单,但也有细节。口语中常说「三点」、「三点半」、「差一刻三点」、「三点零五分」。这些都要转成24小时制。
我个人习惯用正则表达式先提取时间模式,再统一转换。比如:
# 时间规范化示例
import re
def normalize_time(text):
# 匹配 "差一刻三点" 这种模式
pattern = r'差一刻?(\d+)点'
match = re.search(pattern, text)
if match:
hour = int(match.group(1))
# 差一刻 = 45分,所以是 hour-1:45
result_hour = hour - 1
return f"{result_hour:02d}:45"
# 匹配 "三点半" 这种模式
pattern = r'(\d+)点半'
match = re.search(pattern, text)
if match:
hour = int(match.group(1))
return f"{hour:02d}:30"
# 匹配 "三点零五分" 这种模式
pattern = r'(\d+)点(\d+)分'
match = re.search(pattern, text)
if match:
hour = int(match.group(1))
minute = int(match.group(2))
return f"{hour:02d}:{minute:02d}"
return text
我的经验:处理「中午十二点」和「凌晨十二点」时,要区分是12:00还是00:00。我一般结合上下文判断,如果前面有「晚上」、「凌晨」等词,就转成00:00;否则默认12:00。
货币的标准化
货币这块,核心是统一货币单位和数值格式。口语中常说「一百二十块」、「一百二十元」、「一百二十块钱」。嗯,这些都要转成「120元」。
但要注意,不同货币的符号不同。人民币是「元」,美元是「美元」或「刀」,欧元是「欧元」。我建议统一用ISO货币代码,比如CNY、USD、EUR。
我在跨境电商项目中遇到过用户说「这个包五十刀」,系统转成了「50刀」。但后续处理时,「刀」这个单位没法直接计算。所以,我后来统一转成「50美元」或「50 USD」。
| 口语表达 | 标准格式 | 说明 |
|---|---|---|
| 一百二十块 | 120元 | 人民币 |
| 五十刀 | 50美元 | 美元 |
| 三欧元 | 3欧元 | 欧元 |
| 十块五毛 | 10.5元 | 带角分 |
单位的标准化
单位规范化,说白了就是统一度量衡。口语中常说「一米八」、「一百八十公分」、「一点八米」。这些都要转成标准单位。
我建议建立一个单位映射表,把常见的中文单位转成国际标准单位。比如:
- 长度:公分→厘米,尺→0.333米,寸→0.0333米
- 重量:斤→0.5千克,两→50克,磅→0.4536千克
- 体积:升→1立方分米,毫升→1立方厘米
- 面积:亩→666.67平方米,公顷→10000平方米
避坑指南:我曾经在处理「一斤苹果」时,直接转成了「0.5千克苹果」。但用户后续问「多少钱一斤」,系统却显示「每千克XX元」。这就造成了单位不一致。所以,我建议保留原始单位,只在计算时统一转换。
嗯,文本规范化这块内容不少,但核心就三点:识别口语表达、映射到标准格式、处理边界情况。你想想看,只要把这三点做好,后面的语义解析就轻松多了。
我个人习惯是先做规则匹配,再辅以机器学习模型处理模糊情况。比如「一百二十」这种明确表达用规则,「大概一百多」这种模糊表达用模型。两者结合,效果最好。
好了,今天就聊到这儿。下一章咱们讲语义解析中的实体识别,到时候再细聊。