
在 HarmonyOSArkTS开发里字符串这个基础类型真的是又爱又恨。表面上看谁不会写let str: string hello可真到上手做项目从 TextInput 输入校验、网络参数拼接、JSON 解析到列表搜索、中文排序、emoji 截断几乎每一个能让你加班到深夜的 bug背后都站着字符串处理。说它是“全栈”级别的基本功一点都不夸张因为 UI 层、逻辑层、数据层处处都有它的影子。这篇手册是我在自己的 HarmonyOS 应用开发过程中沉淀下来的字符串实战笔记整理成了一套可以直接照着用的方案先讲高频 API 的调用姿势和坑再把转换、格式化、校验、序列化这些常见场景串起来最后附上性能优化和排查问题的经验。适合刚开始接触 ArkTS 的开发者也适合从 Web/小程序转过来、被字符串 API 差异坑过的人。你不需要一次性读完把它当成工具书遇到问题回来翻对应章节就行。1. 别小看字符串HarmonyOS 里它比你想的更“全栈”我一开始做 HarmonyOS 开发时总觉得字符串就是length、substring、indexOf那三板斧和别的语言没区别。直到我接手一个业务模块要同时处理输入框内容、本地缓存、网络请求参数和列表展示才发现字符串这层基本功如果不够扎实会在每一个环节拖你后腿。举几个实际场景TextInput 组件拿到的永远是字符串哪怕你只想要数字也得先过一层转换和校验。网络请求体里的 JSON、表单数据本质上是把对象、数组、布尔值“拼接”成字符串再在另一端“拆开”。这个过程中只要有一处转义没处理好整个接口就挂了。列表搜索、关键词高亮、敏感信息脱敏你输入的是字符串输出的是新字符串中间还要考虑正则、编码、大小写。日志打印、错误提示、埋点上报看起来不起眼但字符串切分或拼接出错直接导致线上问题无法定位。所以我把字符串称为“全栈”不是说你要用字符串去写后端而是说字符串贯穿了一款 App 的完整链路展示层靠它逻辑层靠它数据交互也靠它。尤其是 ArkTS 这种基于 TypeScript 语言、带严格类型约束的开发环境字符串的应用姿势和纯 JavaScript 或者传统 Java 都有差异如果不提前摸清规律后面排查问题会很痛苦。我这篇手册不会只罗列 API而是会把每一个操作放在真实的业务场景里讲告诉你为什么这么写、有什么副作用、替代方案是什么。读完你再回来看项目里的字符串处理代码应该会有一种“原来这里可以这么写”的顿悟感。2. 高频 API 盘点这些方法我天天用但踩坑也最多2.1 长度、截取、拼接的基础认知字符串求长度第一反应是str.length。在 ArkTS 里这个属性确实好用但要注意它数的是 UTF-16 编码单元而不是“用户看到的字符个数”。如果你处理的文本里有 emoji、生僻汉字或者特殊符号length可能会比你预期的大。let emoji ; console.log(emoji.length); // 输出 2因为它用两个 UTF-16 编码单元表示 let chinese 汉; console.log(chinese.length); // 输出 1常见汉字一个编码单元就够了截取字符串时我推荐优先用substring和slice。它俩的差别很细但在实战中容易踩坑substring(start, end)如果start大于end会自动交换这两个参数。它不接受负数负数会被当成 0。slice(start, end)不会交换参数但支持负数表示从末尾往前数。let text HarmonyOS; console.log(text.substring(1, 3)); // ar console.log(text.slice(1, 3)); // ar console.log(text.substring(3, 1)); // ar参数被交换了 console.log(text.slice(3, 1)); // 参数不交换范围为空 console.log(text.slice(-3)); // iOS从末尾取三位拼接字符串我见过不少str str xxx的写法简单场景没问题但高频循环里不建议这么干。原因放到第 5 节细说这里先记住一个原则少量拼接随便用批量拼接时考虑数组join或者模板字符串。模板字符串是 ArkTS/TypeScript 里我很推荐的方式它最大的优势是可读性。比起一堆加号和引号模板字符串能把变量和静态文本混排得明明白白let name HarmonyOS; let version 5; let desc 当前系统${name}版本${version};2.2 大小写转换、去空格、比较三个最容易想当然的操作字符串大小写转换没什么好说的toUpperCase()和toLowerCase()是基础。但要注意有些语言环境下的特殊字符转换结果可能和你预期不一样。比如土耳其语环境下I.toLowerCase()的结果不是i而是ı不带点的 i。HarmonyOS 应用面向全球用户时这个细节会引发隐藏的 bug尤其是做搜索功能时大小写归一化一定要谨慎。去空格这块ArkTS 提供了trim()、trimStart()、trimEnd()。trim()去掉开头和结尾的空白字符不会去掉字符串内部的空格。我遇到过新手把trim()当成“去掉所有空格”来用结果数据里中间的空格纹丝不动。想去掉内部所有空格得用replaceAll( , )注意它只会消除半角空格全角空格\u3000要用正则/\s/g才能覆盖。let input HarmonyOS 开发 ; console.log(input.trim()); // HarmonyOS 开发 console.log(input.replaceAll( , )); // HarmonyOS开发 console.log(input.replace(/\s/g, )); // HarmonyOS开发包含全角空格场景更保险比较字符串是否相等新手最容易直接写。这在 ArkTS 里对字符串类型是有效的因为它是值类型比较不像某些语言里对象引用比较会有坑。但如果你要比较的字符串可能来自不同来源比如一个是string类型另一个是String对象那还是建议用严格相等避免类型转换引发意外。如果要忽略大小写比较别自己写str1.toLowerCase() str2.toLowerCase()性能不好而且一旦某个字符toLowerCase()有特殊行为就容易出错。更稳的做法是用toLocaleLowerCase()配合localeCompare或者干脆在输入阶段就统一把所有内容trim()toLowerCase()后续比较就简单了。2.3 分割与遍历从 split 到 for...ofsplit应该是使用频率极高的 API把字符串按分隔符拆成数组。注意两点第一分隔符如果是字符串字面量它按完全匹配切割如果是正则可以按一组字符切割。let csv apple,orange;banana; console.log(csv.split(/[,;]/)); // [apple, orange, banana]第二split()会把字符串按 UTF-16 编码单元拆开对于 emoji 这类双编码单元字符拆完就变成乱码了。想按“用户感知字符”拆更稳的方式是用Array.from(str)或者for...of循环let emojiStr ab; console.log(emojiStr.split()); // [a, \uD83D, \uDE00, b]乱码了 console.log(Array.from(emojiStr)); // [a, , b]正确遍历字符串我推荐for...of它能正确处理四字节字符。下标遍历for (let i 0; i str.length; i)遇到 emoji 会读到无效的半个字符做回文判断、字符统计这类操作时结果天差地别。2.4 查找与替换indexOf、includes、replaceAll 的选择判断一个字符串是否包含另一个includes()最直观。需要知道位置时用indexOf()。需要统计出现次数时可以配合split的奇妙用法let sentence HarmonyOS is great, HarmonyOS is powerful; let count sentence.split(HarmonyOS).length - 1; console.log(count); // 2替换字符串时replace()默认只替换第一个匹配项如果要替换所有用replaceAll()或者给replace()传正则并加g标志。这是老掉牙的坑了但我几乎每周都在代码评审里看到let text 2024-01-01 2024-02-01; console.log(text.replace(-, /)); // 2024/01-01 2024/02-01 console.log(text.replaceAll(-, /)); // 2024/01/01 2024/02/01 console.log(text.replace(/-/g, /)); // 2024/01/01 2024/02/01正则还牵扯到转义问题。比如你要把[123]这个字符串里的方括号替换成圆括号如果直接写replace([, ()没问题但一旦你用的是replace(/[/g, ()会直接报错因为/在正则里是分隔符方括号是元字符。更常见的坑是用户输入里本来就含正则元字符你想做“把用户输入的 abc 替换成 def”就需要先把用户输入转义成安全文本。3. 转换全家桶数字、数组、JSON 一张表说清3.1 字符串转数字光有 Number 还不够从输入框拿到123要变成数字 123你有几个选择Number(123)最常用空字符串转成 0带非法字符返回NaN。parseInt(123abc)解析到第一个非法字符为止返回 123。注意它会把0x10识别成十六进制但不同环境下行为可能不一致建议总是显式传进制参数parseInt(str, 10)。parseFloat(3.14abc)解析浮点数到第一个非法字符为止。一元加号123效果类似Number()适合写紧凑代码。我给出的建议是表单输入验证场景先用trim()清理空白再用正则校验格式最后才转数字这样能避免很多NaN进入计算流程。let userInput 42 ; let trimmed userInput.trim(); if (/^\d$/.test(trimmed)) { let num Number(trimmed); console.log(num); // 42 }3.2 数组与字符串互相转换split 和 join 的完美对称数组转字符串用join字符串转数组用split。这组操作是我做标签系统、批量筛选、日志埋点时最常用的。let tags [HarmonyOS, ArkTS, 实战]; let tagStr tags.join(,); // HarmonyOS,ArkTS,实战 let tagList tagStr.split(,); // [HarmonyOS, ArkTS, 实战]join还可以指定空字符串直接把数组拼成一个连续字符串。这在生成随机验证码、拼接图片 URL 列表时非常有用let chars [A, B, C, D]; let code chars.join(); // ABCD3.3 对象与 JSON 序列化别把 JSON.stringify 当万能胶HarmonyOS 应用和服务器通信JSON 基本是标配。JSON.stringify可以把对象转成 JSON 字符串JSON.parse可以把字符串转回对象。但有几个细节非踩坑不能体会第一JSON.stringify会忽略值为undefined的函数字段、Symbol 字段遇到循环引用会直接抛错。如果你序列化的对象里有Map、Set、Date默认结果可能不是你想要的需要先给它一个toJSON方法或做预处理。第二JSON.parse对非法 JSON 字符串会直接抛异常。从网络返回的字符串务必放在try...catch里解析否则一个后端多余的空格或转义逗号就能让你的 App 白屏。let raw {name:HarmonyOS,version:5}; try { let obj JSON.parse(raw); console.log(obj.name); } catch (e) { console.error(解析失败, e); }第三对象转 JSON 字符串时中文会被默认原样保留不会做 Unicode 转义。这没问题网络传输和服务器都能正常处理。但如果你要把它放进 URL 参数或某些老旧网关就需要注意encodeURIComponent的配合使用。3.4 URL 编码、Base64、Unicode 转义容易被忽视的一层在 HarmonyOS 开发中网络请求地址、WebView 参数、分享链接都经常需要做 URL 编码。encodeURIComponent和decodeURIComponent是最常用的但要注意它和encodeURI的区别encodeURI不会编码:/?#[]等 URL 结构符适合直接编码整个 URL。encodeURIComponent会编码几乎所有非字母数字的字符适合编码参数值。let keyword HarmonyOS 开发; let url https://example.com/search?q${encodeURIComponent(keyword)}; console.log(url); // qHarmonyOS%20%E5%BC%80%E5%8F%91Base64 编码在图片上传、扫码、签名场景里很常见。HarmonyOS 里有util.Base64Helper可以处理具体 API 版本有差异使用时记得查一下当前 SDK 的包路径。编码后的字符串可能包含、/、等字符放进 URL 时同样要编码不然会被截断或转义。Unicode 转义在写国际化资源时很常见。\uXXXX表示一个 UTF-16 编码单元String.fromCharCode和charCodeAt可以互相转换。遇到需要把中文变成\u5f00\u53d1这样的格式时可以用循环实现但注意四字节字符要拆成两个代理对处理。4. 实战案例一个注册页面的字符串全流程理论讲多了容易飘我来拆一个真实存在的场景注册页面。这个页面上有用户名输入框、手机号输入框、验证码输入框和一个提交按钮。用户填完点提交前端要校验输入、组装请求体、解析返回结果再把结果展示到界面上。整个过程几乎把字符串操作全走了一遍。4.1 输入校验长度、字符集、正则用户名校验规则一般是长度 3~20 个字符只能包含字母、数字、下划线。手机号校验规则按国内来说是一段 11 位数字。这里有几个容易掉进去的坑校验长度之前一定要trim()否则用户输入前后空格长度检测会误判。中文用户名的长度计算别用length因为汉字在 JS/TS 里是一个编码单元可用户感知上是“一个字符”如果你要按字节数限制逻辑又不一样。正则里的\d只匹配 ASCII 数字某些语言环境可能会匹配其他数字字符为了保险手机号场景直接用[0-9]。function validateUsername(name: string): boolean { const trimmed name.trim(); if (trimmed.length 3 || trimmed.length 20) { return false; } return /^[a-zA-Z0-9_]$/.test(trimmed); } function validatePhone(phone: string): boolean { const trimmed phone.trim(); return /^1[3-9]\d{9}$/.test(trimmed); }这里我强烈建议使用“先 trim 后校验”的原则既保证用户输入不被误杀又能统一后续传给后端的数据格式。4.2 格式化手机号脱敏、银行卡分段注册功能一般用不上脱敏但“手机号脱敏展示”是很多 App 个人信息页的标配。比如把13812345678显示成138****5678。字符串截取加拼接就能完成function maskPhone(phone: string): string { const cleaned phone.replace(/\s/g, ); if (cleaned.length ! 11) { return phone; } return cleaned.slice(0, 3) **** cleaned.slice(7); }如果要做银行卡号或信用卡号分段展示比如每 4 位加一个空格可以用正则一行搞定let cardNo 6222021234567890; let formatted cardNo.replace(/(\d{4})(?\d)/g, $1 ); console.log(formatted); // 6222 0212 3456 7890这种“格式化”操作的共同点是先清理原始字符串里的杂质空格、横线再按规则重新拼接。顺序反了结果就会乱。4.3 与 UI 组件对接TextInput 的 onChange 和 Text 显示HarmonyOS 里TextInput 组件通过onChange回调把用户输入的内容返回给你类型就是字符串。做受控组件或者非受控处理时每次变更都可能触发重绘所以高频操作要注意性能。我处理输入时的习惯是用onChange((value: string) { ... })拿到最新字符串先做必要的trim或格式限制。如果要做“只允许输入数字”这种限制不要等到提交时才校验而是在onChange里直接过滤非法字符把新的字符串回填给组件。如果要做“防抖搜索”那么回调函数里收集字符串后用定时器或setTimeout延迟触发后续逻辑避免每次按键都立即发起网络请求。State username: string ; onChange (value: string) { // 只保留字母、数字、下划线 let filtered value.replace(/[^a-zA-Z0-9_]/g, ); this.username filtered; };展示层用Text组件渲染时字符串里如果包含换行可以用\n但注意不同设备的字体渲染宽度不同长文本最好让组件自动换行别自己截断除非你明确知道需求。4.4 网络请求中的字符串处理组装表单、JSON 解析注册接口通常要传一个 JSON 对象里面包含用户名、手机号、验证码。调用网络前组装 JSON 字符串是必经之路let payload { username: this.username, phone: this.phone, code: this.code, }; let requestBody JSON.stringify(payload);这一步看起来简单但有几个注意点this.username里的值一定要经过校验否则后端可能收到不可控字符引发安全问题。如果传FormData表单那么就是一堆keyvalue用拼接需要用到encodeURIComponent对每个值编码否则特殊字符会破坏请求格式。服务端返回的响应体是字符串要先JSON.parse。解析前最好判断一下字符串是否为空或者是否为null别指望所有后端都规范返回 JSON。解析响应后前端经常要更新界面上的提示文案。比如“注册成功”或“手机号已存在”这些字符串在业务代码里反复出现最好抽成常量避免拼写错误。5. 性能与内存字符串操作没你想的那么廉价5.1 不可变性拼接和替换为什么会“变慢”字符串在 ArkTS/JavaScript/TypeScript 里是不可变的。这意味着你对一个字符串做、replace、substring等操作时并不会修改原来的字符串而是生成一个全新的字符串对象旧字符串等待垃圾回收。低频场景无感但如果你在一个for循环里拼接 5000 次字符串每次操作都会创建新对象内存和 CPU 开销迅速上升。这就像你在一张纸上写字每写一个字就换一张新纸最后虽然字全写对了纸却浪费了一大堆。我在项目里做过一个简单基准测试用拼接 10000 个短字符串耗时约几十毫秒用数组push加join拼接同样内容耗时只有几毫秒甚至更少。数据量越大差距越明显。5.2 高频拼接数组 join 还是模板字符串批量拼接字符串时我推荐用数组收集再joinlet parts: string[] []; for (let i 0; i 10000; i) { parts.push(item-${i}); } let result parts.join(,);模板字符串在少量拼接时最优雅可读性好但不要在巨大的循环里使用嵌套模板字符串因为每次迭代都涉及解析和拼接。还有一点HarmonyOS 应用运行在设备上性能瓶颈比 PC 上更明显。如果你处理的是来自文件、网络日志或数据库的大段文本比如几十 KB 的日志字符串频繁切割、查找、替换会导致明显的卡顿。这种场景下优先用indexOf定位再用slice截取避免使用大量正则。5.3 大文本的裁剪、截断、懒加载列表页展示长文本时经常需要做“超过 N 字显示省略号”。一个简单的截断函数function truncate(text: string, maxLen: number): string { if (text.length maxLen) { return text; } return text.slice(0, maxLen) ...; }但这里有个问题如果你按length截断遇到 emoji 或特殊字符截出来可能是一个不完整的字符显示成乱码。更稳的方案是用Array.from(text)转成字符数组按字符个数截断或者用Intl.Segmenter如果运行环境支持做更精准的文本分割。处理超大文本比如文件内容时别一次性加载到字符串里再截取可以分段读取、按行处理只保留需要的部分。HarmonyOS 的文件读取 API 支持设置读取大小配合字符串的split(\n)可以逐行分析内存占用会友好很多。5.4 StringBuilder 等替代方案ArkTS 中怎么办做过 Java 开发的人可能第一反应是找StringBuilder。ArkTS/TypeScript 标准库里没有这个类但你可以自己封装一个轻量版本class StringBuilder { private parts: string[] []; append(str: string): StringBuilder { this.parts.push(str); return this; } toString(): string { return this.parts.join(); } }用起来就是let sb new StringBuilder(); sb.append(Hello); sb.append( ); sb.append(HarmonyOS); console.log(sb.toString()); // Hello HarmonyOS本质上是把多次拼接变成一次join底层原理和我前面说的数组拼接一致。如果你嫌封装麻烦直接用数组也行。关键是理解“减少中间字符串对象创建”这个思路。6. 常见 Bug 与排查技巧实录6.1 中文、emoji、四字节字符的 length 陷阱前面反复提到 emoji 问题我再强调一遍。length属性统计的是 UTF-16 编码单元数量而消费者视角的“字符数”更接近“码点”数量。做字数限制、输入框字数统计、评论区楼层展示时这两种统计的差异非常致命。解决方案有三种用Array.from(str).length按码点统计简单直接。用for...of循环计数。使用Intl.Segmenter如果目标设备支持做更细粒度的文本分割。我自己的经验是绝大多数业务场景用Array.from就够了性能可接受代码也简单。6.2 TextInput 值里的不可见字符空格、换行、零宽字符用户从网页或聊天软件复制内容粘贴到输入框时常常会带上不可见字符。最常见的是普通空格、全角空格、换行符偶尔还会出现零宽空格U200B。这些字符用肉眼根本看不出来但会导致字符串比较失败、正则校验不通过、长度统计超限。排查技巧遇到“数据看着一样但程序说不一样”的情况先把字符串的每个字符的 Unicode 码点打印出来let s abc; for (let ch of s) { console.log(ch.codePointAt(0).toString(16)); }如果看到200b、3000这类“幽灵字符”就知道问题在哪了。解决方式是清洗输入去掉零宽字符、统一空格类型再做后续处理。HarmonyOS 的 TextInput 组件也可以设置showErrorText的时机把握准确但更实际的做法是在数据源头做清洗。6.3 类型转换NaN 和 undefined 的来源parseInt()返回NaNNumber(null)返回 0Number(undefined)返回NaN。这三个结果差异足以让一个表单校验逻辑全线崩溃。我来列一张速查表你迟早用得上输入值parseInt(x, 10)Number(x)x123123123123NaN00 NaN0012abc12NaNNaNnullNaN00undefinedNaNNaNNaN0x101616163.1433.143.14我的习惯是如果数据可能为null或空先统一做字符串化但要注意String(null)会变成nullString(undefined)变成undefined。真正稳妥的写法是提前做空值判断别把脏数据交给转换函数。6.4 正则转义想匹配点和方括号请先学会说谎正则里.表示任意字符[是字符集的开始*、、?都有特殊含义。如果你要按字面意义匹配这些符号必须转义。很多新手在字符串里写.来匹配小数点结果把a1b2也匹配了因为.可以匹配任意字符。更常见的是动态正则。比如用户输入一个关键词你想用它做正则搜索就必须先对关键词转义function escapeRegExp(text: string): string { return text.replace(/[.*?^${}()|[\]\\]/g, \\$); }这样用户输入的[abc]才会被当作普通字符串去匹配而不是字符集。这个函数我放在工具类里几乎每个项目都会用到。6.5 与后端交互时字符串编码不一致HarmonyOS 应用请求后端接口时如果后端接口返回的中文乱码问题通常出在字符编码上。HTTP 请求头里的Content-Type要带上charsetutf-8服务端也要按 UTF-8 返回。如果涉及到 URL 参数拼接一律用encodeURIComponent处理不要直接拼接中文。本地存储场景中读写 Preference 或文件时也建议统一 UTF-8 编码。HarmonyOS 提供了一些转码工具具体 API 可以查官方文档但核心原则只有一条全局统一字符编码不要在不同模块之间来回转码。结语字符串这点事值得多花时间磨字符串操作在 HarmonyOS 开发里看着不起眼实际却是最影响开发效率的细节之一。我自己的体会是与其在网上搜零散的报错解决方案不如花半天时间把字符串的 API、转换、正则、编码、性能这几条线彻底过一遍后面能省下大量排错时间。如果你现在正在做一个和输入、展示、网络请求强相关的功能我建议你拿这个小册子里的代码片段当模板先跑通再优化。尤其是trim()和encodeURIComponent这两个函数用好了能避免一大半字符相关的诡异 bug。后续如果你想把字符串处理能力再往上提一层可以研究一下Intl这个内置对象它对多语言环境下的字符串比较、日期格式化、数字格式化支持得很好。另一个方向是正则表达式的性能优化复杂正则写不好在小内存设备上能卡到让人崩溃。这篇文章算是我个人项目里的一个阶段性沉淀代码片段都是实际跑过的但设备型号和 SDK 版本不同API 细节可能会有微调。你照着写的时候如果遇到编译报错优先查一下当前项目的 SDK 版本和官方 API 变更日志。