HarmonyOS textProcessing文本处理完全指南:分词与实体抽取实战
适用版本 :HarmonyOS NEXT(API 23+)
开发工具 :DevEco Studio 6.1+
核心技术:Natural Language Kit、textProcessing、EntityType
效果

一、Natural Language Kit 概述
HarmonyOS SDK 内置的 Natural Language Kit(自然语言理解服务) 提供了两项核心文本分析能力:
| 能力 | 说明 | 典型场景 |
|---|---|---|
| 分词(WordSegment) | 将文本切分为独立词语单元 | 搜索引擎关键词提取、文本分析 |
| 实体抽取(Entity) | 从文本中识别具有特定意义的实体 | 地址解析、信息提取、智能表单 |
1.1 约束与限制
| 维度 | 限制 |
|---|---|
| 支持语言 | 简体中文、英文、繁体中文 |
| 文本长度 | 不超过1000字符 |
| 并发限制 | 同一用户不支持同一特性并发调用 |
| 模拟器 | 不支持,需真机调试 |
二、模块导入
typescript
// 分词功能
import { textProcessing } from '@kit.NaturalLanguageKit';
// 实体抽取功能(需额外导入EntityType)
import { textProcessing, EntityType } from '@kit.NaturalLanguageKit';
三、分词功能详解
3.1 API接口
typescript
textProcessing.getWordSegment(text: string): Promise<textProcessing.WordSegment[]>
返回值 WordSegment 结构:
| 属性 | 类型 | 说明 |
|---|---|---|
word |
string |
分词结果文本 |
wordTag |
string |
词性标签 |
3.2 基础示例
typescript
import { textProcessing } from '@kit.NaturalLanguageKit';
@Entry
@Component
struct WordSegmentDemo {
private inputText: string = '';
@State outputText: string = '';
build() {
Column() {
TextInput({ placeholder: '请输入要分词的文本' })
.height(40)
.fontSize(16)
.width('90%')
.margin(10)
.onChange((value: string) => {
this.inputText = value;
})
Button('获取分词结果')
.type(ButtonType.Capsule)
.fontColor(Color.White)
.margin(10)
.onClick(async () => {
try {
let result = await textProcessing.getWordSegment(this.inputText);
this.outputText = this.formatResult(result);
} catch (err) {
this.outputText = `错误: ${(err as Error).message}`;
}
})
Scroll() {
Text(this.outputText)
.fontSize(14)
.width('90%')
}
.height('50%')
.margin(10)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
private formatResult(segments: textProcessing.WordSegment[]): string {
if (!segments || !segments.length) {
return '无分词结果';
}
let output = `共 ${segments.length} 个词:\n\n`;
for (let i = 0; i < segments.length; i++) {
output += `[${i + 1}] ${segments[i].word} (${segments[i].wordTag})\n`;
}
return output;
}
}
3.3 分词结果示例
输入文本:"华为技术有限公司成立于深圳"
共 6 个词:
[1] 华为技术有限公司 (机构名)
[2] 成立 (动词)
[3] 于 (介词)
[4] 深圳 (地名)
四、实体抽取功能详解(重点)
4.1 API接口
typescript
textProcessing.getEntity(
text: string,
options: { entityTypes: EntityType[] }
): Promise<textProcessing.Entity[]>
4.2 支持的实体类型(EntityType)
| EntityType枚举值 | 含义 | 示例 |
|---|---|---|
EntityType.NAME |
人名 | 张三、李明 |
EntityType.PHONE_NO |
手机号 | 13800138000 |
EntityType.LOCATION |
地址/地点 | 北京市朝阳区XX路1号 |
EntityType.DATETIME |
日期时间 | 2025年6月18日 |
EntityType.EMAIL |
邮箱 | user@example.com |
EntityType.EXPRESS_NO |
快递单号 | SF1234567890 |
EntityType.FLIGHT_NO |
航班号 | CA1234 |
EntityType.URL |
网址 | https://example.com |
EntityType.VERIFICATION_CODE |
验证码 | 582916 |
EntityType.ID_NO |
身份证号 | 110101199001011234 |
4.3 返回值 Entity 结构
| 属性 | 类型 | 说明 |
|---|---|---|
text |
string |
识别出的实体文本 |
charOffset |
number |
实体在原文中的字符偏移量 |
type |
EntityType |
实体类型 |
jsonObject |
object |
实体附加信息(JSON格式) |
4.4 Entity.jsonObject 地址附加信息
对于LOCATION类型的实体,jsonObject包含丰富的地址结构信息:
| 字段 | 说明 |
|---|---|
coreLocation |
核心地址标识 |
province |
省份信息 |
city |
城市信息 |
district |
区县信息 |
county |
县级信息 |
adornLocation |
修饰性地址(如"XX小区门口") |
这些字段在地址解析场景中至关重要,可帮助区分"省市区"和"详细地址"。
4.5 基础示例:人名和手机号识别
typescript
import { textProcessing, EntityType } from '@kit.NaturalLanguageKit';
@Entry
@Component
struct EntityDemo {
private inputText: string = '';
@State outputText: string = '';
build() {
Column() {
TextInput({ placeholder: '输入包含姓名、电话的文本' })
.height(40)
.fontSize(16)
.width('90%')
.margin(10)
.onChange((value: string) => {
this.inputText = value;
})
Button('识别实体')
.type(ButtonType.Capsule)
.fontColor(Color.White)
.margin(10)
.onClick(async () => {
try {
let result = await textProcessing.getEntity(this.inputText, {
entityTypes: [EntityType.NAME, EntityType.PHONE_NO]
});
this.outputText = this.formatEntities(result);
} catch (err) {
this.outputText = `错误: ${(err as Error).message}`;
}
})
Scroll() {
Text(this.outputText)
.fontSize(14)
.width('90%')
}
.height('50%')
.margin(10)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
private formatEntities(entities: textProcessing.Entity[]): string {
if (!entities || !entities.length) {
return '未识别到实体';
}
let output = `识别到 ${entities.length} 个实体:\n\n`;
for (let i = 0; i < entities.length; i++) {
let entity = entities[i];
output += `实体[${i + 1}]\n`;
output += ` 文本: ${entity.text}\n`;
output += ` 类型: ${entity.type}\n`;
output += ` 偏移: ${entity.charOffset}\n\n`;
}
return output;
}
}
五、实战:快递地址智能解析
5.1 场景说明
用户粘贴一段快递地址文本,例如:
"张伟 13912345678 广东省深圳市南山区科技园南路88号创新大厦A座"
系统自动将其拆分为:
| 字段 | 解析结果 |
|---|---|
| 姓名 | 张伟 |
| 电话 | 13912345678 |
| 省市区 | 广东省深圳市南山区 |
| 详细地址 | 科技园南路88号创新大厦A座 |
5.2 核心解析逻辑
typescript
import { textProcessing, EntityType } from '@kit.NaturalLanguageKit';
private async parseAddressText(text: string): Promise<void> {
try {
let entities = await textProcessing.getEntity(text, {
entityTypes: [EntityType.NAME, EntityType.PHONE_NO, EntityType.LOCATION]
});
if (!entities || !entities.length) {
return;
}
for (let i = 0; i < entities.length; i++) {
let entity = entities[i];
if (entity.type === EntityType.NAME) {
// 提取姓名
this.recipientName = entity.text;
} else if (entity.type === EntityType.PHONE_NO) {
// 提取手机号
this.phoneNumber = entity.text;
} else if (entity.type === EntityType.LOCATION) {
// 地址实体需要特殊处理
let jsonObj = entity.jsonObject.toString();
// 判断是否为核心地址(含省、市、区/县)
let isCoreLocation =
jsonObj.includes('coreLocation') &&
jsonObj.includes('province') &&
jsonObj.includes('city') &&
(jsonObj.includes('district') || jsonObj.includes('county'));
// 判断是否为修饰性地址(如"XX号门口")
let isAdornLocation = jsonObj.includes('adornLocation');
if (isCoreLocation && !isAdornLocation &&
(i + 1) < entities.length &&
entities[i + 1].type === EntityType.LOCATION) {
// 当前实体为省市区
this.regionAddress = entity.text;
} else {
// 尝试按"区"或"县"拆分省市区和详细地址
if (entity.text.includes('区')) {
let parts = entity.text.split('区');
this.regionAddress = parts[0] + '区';
this.detailAddress = parts[1];
} else if (entity.text.includes('县')) {
let parts = entity.text.split('县');
this.regionAddress = parts[0] + '县';
this.detailAddress = parts[1];
} else {
this.detailAddress = entity.text;
}
}
}
}
} catch (err) {
console.error(`解析失败: ${(err as Error).message}`);
}
}
5.3 地址解析要点
- 请求3种实体类型 :
NAME(姓名)、PHONE_NO(电话)、LOCATION(地址) - 地址实体可能返回多个:第一个通常为省市区,第二个为详细地址
- 利用jsonObject判断地址性质 :
coreLocation标识核心地址,adornLocation标识修饰地址 - 按"区"或"县"拆分:当省市区和详细地址合并在一个实体中时,可用分隔字符拆分
六、错误处理最佳实践
typescript
try {
let result = await textProcessing.getEntity(text, {
entityTypes: [EntityType.NAME, EntityType.PHONE_NO, EntityType.LOCATION]
});
// 处理结果
} catch (err) {
let error = err as Error;
// 常见错误码处理
if (error.code === '10210001') {
// 输入文本为空
console.warn('输入文本不能为空');
} else if (error.code === '10210002') {
// 文本超长
console.warn('文本长度不能超过1000字符');
} else {
console.error(`未知错误: ${error.code} - ${error.message}`);
}
}
七、性能优化建议
- 避免重复调用 :同一段文本只调用一次
getEntity,缓存结果 - 按需指定entityTypes:只请求需要的实体类型,减少处理时间
- 控制文本长度:超过1000字符的文本需要分段处理
- 避免并发调用:同一特性不支持同一用户并发调用
八、与PasteButton配合使用
将剪贴板粘贴与文本解析结合,形成完整的"粘贴即解析"体验:
typescript
PasteButton()
.onClick(async () => {
// 第一步:通过安全控件读取剪贴板
await systemPasteboard.getData().then(async (data: pasteboard.PasteData) => {
const text = data.getPrimaryText();
if (text) {
// 第二步:调用实体抽取解析文本
try {
let entities = await textProcessing.getEntity(text, {
entityTypes: [EntityType.NAME, EntityType.PHONE_NO, EntityType.LOCATION]
});
this.processEntities(entities);
} catch (err) {
console.error('解析失败');
}
}
});
})
九、总结
textProcessing是HarmonyOS Natural Language Kit的核心API,提供了分词 和实体抽取 两大文本分析能力。在快递地址解析场景中,通过getEntity()配合EntityType.NAME、PHONE_NO、LOCATION三种实体类型,可以将非结构化的地址文本自动拆分为姓名、电话、省市区和详细地址,大幅提升用户填写效率。
核心要点回顾:
- 导入
@kit.NaturalLanguageKit模块 - 使用
EntityType枚举指定需要的实体类型 - 通过
Entity.jsonObject中的地址结构信息区分省市区和详细地址 - 与
PasteButton配合实现"粘贴即解析"的流畅体验