鸿蒙应用开发实战【66】— 短信智能解析算法
·
鸿蒙应用开发实战【66】— 短信智能解析算法
本文是「号码助手全栈开发系列」第 66 篇,持续更新中…
开源社区:https://openharmonycrossplatform.csdn.net
前言
SmsParser 是号码助手智能识别的核心——它从一段包含多条注册短信的文本中,提取出平台名称和手机号。典型输入是用户从短信列表复制粘贴的一段文字,例如:
【微信】你正在登录微信,验证码 123456。
【招商银行】您尾号 8888 的银行卡充值 100 元。
滴滴出行:13800138000 注册成功。
SmsParser 需要从中识别出:微信(13800138000)、招商银行(13800138000)、滴滴出行(13800138000)。
本篇涵盖:ParseResult 接口设计、PLATFORM_KEYWORDS 长词优先策略、PHONE_PATTERN 正则提取手机号、子串包含消除算法(subsumed)、组合候选生成策略。

一、数据结构
export interface ParseResult {
platform: string // 识别到的平台/应用名称
phone: string // 识别到的手机号
raw: string // 原始输入文本片段
}
三种组合情况:
| platform | phone | 含义 | 典型场景 |
|---|---|---|---|
'微信' |
'13800138000' |
同时匹配到平台和手机号 | 含注册短信的文本 |
'微信' |
'' |
只匹配到平台 | 验证码短信无号码 |
'' |
'13800138000' |
只匹配到手机号 | 纯号码文本列表 |
二、关键词匹配策略
2.1 PLATFORM_KEYWORDS
const PLATFORM_KEYWORDS: string[] = [
// 银行(长词优先)
'招商银行', '工商银行', '建设银行', '农业银行', '中国银行', '交通银行',
'浦发银行', '中信银行', '光大银行', '民生银行', '平安银行', '广发银行',
// ...
// 运营商
'中国移动', '中国联通', '中国电信',
// 支付 / 金融
'支付宝', '微信支付', '云闪付', '数字人民币',
// 电商
'拼多多', '天猫', '淘宝', '京东', '唯品会', '小红书', '得物', '闲鱼',
// 出行
'滴滴出行', '哈啰出行', '美团打车',
// 社交
'微博', '抖音', '快手', 'QQ',
// 内容
'哔哩哔哩', 'B站', '爱奇艺', '优酷视频', '腾讯视频',
// 办公
'钉钉', '飞书', '企业微信', '腾讯会议',
// ... 共 60+ 关键词
// 微信放在较后(避免"微信支付"被先匹配后再匹配"微信")
'微信'
]
排列原则:
- 长词优先:
招商银行排在银行(如果有)前面 - 包含词放后:
微信放在微信支付后面,避免先匹配到短词 - 业务分类:虽然顺序不影响匹配,但分组排列便于维护
2.2 长词优先 + 子串包含消除
const platformSet: string[] = []
const matched = new Set<string>()
for (const kw of PLATFORM_KEYWORDS) {
if (trimmed.includes(kw)) {
// 检查是否已被更长词包含
let subsumed = false
for (const already of matched) {
if (already.includes(kw)) { // 如"携程旅行"包含了"携程"
subsumed = true
break
}
}
if (!subsumed) {
platformSet.push(kw)
matched.add(kw)
}
}
}
核心逻辑:
- 遍历排好序的关键词列表
- 命中关键词后,检查已匹配集合中是否有包含该词的更长词
- 有则跳过(subsumed),无则加入结果集
例如输入文本包含"携程旅行":
- 遍历到
携程旅行→ 命中,matched = {'携程旅行'} - 遍历到
携程→ 也已命中,但'携程旅行'.includes('携程')→ subsumed 跳过
三、手机号提取
const PHONE_PATTERN = '(1[3-9]\\d{9})'
const phoneReg = new RegExp(PHONE_PATTERN, 'g')
let phoneMatch: RegExpExecArray | null = phoneReg.exec(trimmed)
while (phoneMatch !== null) {
const phone = phoneMatch[1]
if (!phoneSet.includes(phone)) {
phoneSet.push(phone)
}
phoneMatch = phoneReg.exec(trimmed)
}
说明:
1[3-9]\d{9}覆盖中国大陆目前所有手机号段(13x-19x)- 使用
exec+ 循环 +g标志提取所有匹配 - 手动去重(
phoneSet.includes),保留首次出现顺序
四、组合候选生成
const results: ParseResult[] = []
if (platformSet.length > 0 && phoneSet.length > 0) {
// 笛卡尔积:每个平台 × 每个手机号
for (const platform of platformSet) {
for (const phone of phoneSet) {
results.push({ platform, phone, raw: trimmed })
}
}
} else if (platformSet.length > 0) {
for (const platform of platformSet) {
results.push({ platform, phone: '', raw: trimmed })
}
} else {
for (const phone of phoneSet) {
results.push({ platform: '', phone, raw: trimmed })
}
}
三种分支:
| 条件 | 结果 | 典型场景 |
|---|---|---|
| 有平台 + 有号码 | 笛卡尔积组合 | 短信包含平台名和手机号 |
| 有平台 + 无号码 | 仅平台名 | 短信仅包含平台信息 |
| 无平台 + 有号码 | 仅手机号 | 纯号码文本 |
| 两者皆无 | 空数组 | 无关文本 |
五、完整解析示例
输入文本:
【建设银行】您尾号8888的信用卡消费100元。【支付宝】13800138000登录验证码。
【携程旅行】您预订的酒店已确认。[携程]
【滴滴出行】13800138000行程已结束。
解析过程:
1. 手机号提取 → ['13800138000']
2. 平台名提取(长词优先):
- '建设银行' ✓(matched: {建设银行})
- '支付宝' ✓(matched: {建设银行, 支付宝})
- '携程旅行' ✓(matched: {建设银行, 支付宝, 携程旅行})
- '滴滴出行' ✓(matched: {建设银行, 支付宝, 携程旅行, 滴滴出行})
- '携程' ✗(被 '携程旅行'.includes('携程') 排除)
3. 笛卡尔积 → 4 条结果:
- 建设银行 / 13800138000
- 支付宝 / 13800138000
- 携程旅行 / 13800138000
- 滴滴出行 / 13800138000
小结
| 要点 | 说明 |
|---|---|
| 关键词列表 | 60+ 平台按长词优先排列 |
| 子串消除 | already.includes(kw) 避免短词重复 |
| 手机号提取 | 1[3-9]\d{9} 正则 + exec 循环去重 |
| 组合策略 | 笛卡尔积(有平台有号码)/ 仅平台 / 仅号码 |
| 返回结果 | ParseResult[] 包含 platform + phone + raw |
| 匹配度提示 | UI 层固定显示"匹配度 96%"(模拟文本) |
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- openHarmony 跨平台社区:https://openharmonycrossplatform.csdn.net
- HarmonyOS 官方文档:https://developer.huawei.com/consumer/cn/doc/
- HarmonyOS 正则表达式开发:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-regex
- HarmonyOS Pasteboard API:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/pasteboard
更多推荐



所有评论(0)