一、思路
首先,在Kotlin的Char文档中说明,其中字段code是以UTF-16编码返回的一个Int数据,具体克见下方链接
code - Kotlin Programming Language (kotlinlang.org)
然后UTF-16对于0x10000以下的都是以Unicode编码表示,所有编码一览可见下
Unicode 符号表 - 所有 Unicode 字符及其代码都在一页上 (◕‿◕) SYMBL
看重点的基本拉丁字母(0x0000 - 0x007F),其中包含了我们需要的数字和英文字母
所以,我们只需要专门处理0x7F以下的字符即可,遇到英文字母和数字开头的,就接着判断下一个,直到不是为止,然后再合到一起,遇到其他情况就直接丢出即可
二、代码实现
说了这么多,我们看代码的实现
/**
* 将中文所有单词分为单独的字,英文和数字分为连续的字符串,所有可见符号单独的符号(ascii码大于0x20)成为单独字符串。
*
* 如下所示
* ```
* "你好savet-save,欢迎购买TV show服务! 你需要花费29元,请支付".splitWord()
* ```
* 输出
* ```
* [你, 好, savet, -, save, ,, 欢, 迎, 购, 买, TV, show, 分, 为, !, 你, 需, 要, 花, 费, 29, 元, ,, 请, 支, 付]
* ```
*
* @return 分割好的List
*/
fun String.splitWord(): List<String> {
val characters: MutableList<String> = mutableListOf()
var i = 0
val num = this.length
while (i < num) {
// 基本字母
if (this[i].code <= 0x7F) {
if (this[i].code <= ' '.code) {
// 不可见字符忽略(空格和之前的)
i++
continue
}
val sb: StringBuilder = java.lang.StringBuilder()
// 数字
if (this[i].isDigit() || this[i].isAsciiLetter()) {
do {
sb.append(this[i])
i++
} while (i < num && (this[i].isDigit() || this[i].isAsciiLetter()))
characters.add(sb.toString())
} else {
// 其他可见字符
characters.add(this[i].toString())
i++
}
} else {
characters.add(this[i].toString())
i++ // +1
}
}
return characters
}
/**
* 判断是否是a-z或A-Z字符
*
* @return true - 是, false - 不是
*/
fun Char.isAsciiLetter(): Boolean {
return (this.code >= 'a'.code && this.code <= 'z'.code) ||
(this.code >= 'A'.code && this.code <= 'Z'.code)
}
这里为什么我又添加了一个isAsciiLetter()的拓展函数呢,因为我发现官方的isLetter会把中文的字也认为是一个字母,所以就自己写了个判断a-z或A-Z的函数
至此就大功告成了
三、使用示例
fun main() {
println("你好savet-save,欢迎购买TV show服务! 你需要花费29元,请支付".splitWord())
}
输出结果:
[你, 好, savet, -, save, ,, 欢, 迎, 购, 买, TV, show, 分, 为, !, 你, 需, 要, 花, 费, 29, 元, ,, 请, 支, 付]