KMP 实现鸿蒙跨端:Kotlin JSON格式化和验证算法
·
目录
概述
本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的JSON格式化和验证算法系统。这个案例展示了如何使用 Kotlin 的字符串操作、正则表达式和结构分析来创建一个功能丰富的JSON处理工具。通过 KMP,这个算法可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持用户输入进行实时处理。
算法的特点
- 格式化功能:自动格式化 JSON 为易读的形式
- 验证功能:检查 JSON 的有效性和括号匹配
- 结构分析:提供详细的 JSON 结构分析
- 键值提取:自动提取 JSON 中的所有键
- 跨端兼容:一份 Kotlin 代码可同时服务多个平台
算法功能
1. JSON验证
- 格式检查:验证 JSON 是否以 { 或 [ 开头和结尾
- 括号匹配:检查大括号和方括号是否匹配
- 结构完整性:验证 JSON 结构是否完整
2. JSON格式化
- 缩进处理:添加适当的缩进和换行
- 空格处理:在冒号后添加空格
- 字符串保护:保护字符串中的特殊字符
3. 结构分析
- 对象统计:统计 JSON 中的对象数量
- 数组统计:统计 JSON 中的数组数量
- 深度计算:计算 JSON 的最大嵌套深度
- 键值提取:提取所有的键名
4. 值类型统计
- 字符串值:统计字符串类型的值
- 数值:统计数字类型的值
- 布尔值:统计布尔类型的值
- 空值:统计 null 值
5. 大小对比
- 原始大小:原始 JSON 的字节数
- 格式化后:格式化后的字节数
- 大小变化:显示大小的变化
核心实现
1. JSON验证
val isValidJson = try {
val trimmed = inputJson.trim()
(trimmed.startsWith("{") && trimmed.endsWith("}")) ||
(trimmed.startsWith("[") && trimmed.endsWith("]"))
} catch (e: Exception) {
false
}
2. 括号匹配检查
val openBraces = inputJson.count { it == '{' }
val closeBraces = inputJson.count { it == '}' }
val bracesMatched = openBraces == closeBraces
3. 键值提取
val keys = mutableListOf<String>()
val keyPattern = Regex("\"([^\"]+)\"\\s*:")
keyPattern.findAll(inputJson).forEach { match ->
keys.add(match.groupValues[1])
}
4. 深度计算
var maxDepth = 0
var currentDepth = 0
for (char in inputJson) {
when (char) {
'{', '[' -> {
currentDepth++
maxDepth = maxOf(maxDepth, currentDepth)
}
'}', ']' -> currentDepth--
}
}
5. JSON格式化
fun formatJson(json: String): String {
val result = StringBuilder()
var indent = 0
var inString = false
var i = 0
while (i < json.length) {
val char = json[i]
when {
char == '"' && (i == 0 || json[i - 1] != '\\') -> {
inString = !inString
result.append(char)
}
!inString && (char == '{' || char == '[') -> {
result.append(char)
indent++
result.append("\n")
result.append(" ".repeat(indent))
}
!inString && (char == '}' || char == ']') -> {
indent--
result.append("\n")
result.append(" ".repeat(indent))
result.append(char)
}
!inString && char == ',' -> {
result.append(char)
result.append("\n")
result.append(" ".repeat(indent))
}
!inString && char == ':' -> {
result.append(char)
result.append(" ")
}
char != ' ' || inString -> {
result.append(char)
}
}
i++
}
return result.toString()
}
实战案例

案例:完整的JSON格式化和验证算法
Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun jsonFormatterValidator(inputJson: String = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"): String {
if (inputJson.isEmpty()) {
return "❌ 错误: JSON 不能为空\n请输入要格式化的 JSON"
}
// 1. 验证 JSON 格式
val isValidJson = try {
val trimmed = inputJson.trim()
(trimmed.startsWith("{") && trimmed.endsWith("}")) ||
(trimmed.startsWith("[") && trimmed.endsWith("]"))
} catch (e: Exception) {
false
}
// 2. 格式化 JSON
val formatted = try {
formatJson(inputJson)
} catch (e: Exception) {
"格式化失败: ${e.message}"
}
// 3. 统计 JSON 结构
val braceCount = inputJson.count { it == '{' }
val bracketCount = inputJson.count { it == '[' }
val colonCount = inputJson.count { it == ':' }
val commaCount = inputJson.count { it == ',' }
val quoteCount = inputJson.count { it == '"' }
// 4. 检查括号匹配
val openBraces = inputJson.count { it == '{' }
val closeBraces = inputJson.count { it == '}' }
val openBrackets = inputJson.count { it == '[' }
val closeBrackets = inputJson.count { it == ']' }
val bracesMatched = openBraces == closeBraces
val bracketsMatched = openBrackets == closeBrackets
// 5. 提取 JSON 键
val keys = mutableListOf<String>()
val keyPattern = Regex("\"([^\"]+)\"\\s*:")
keyPattern.findAll(inputJson).forEach { match ->
keys.add(match.groupValues[1])
}
// 6. 计算 JSON 深度
var maxDepth = 0
var currentDepth = 0
for (char in inputJson) {
when (char) {
'{', '[' -> {
currentDepth++
maxDepth = maxOf(maxDepth, currentDepth)
}
'}', ']' -> currentDepth--
}
}
// 7. 统计值的类型
val stringValues = inputJson.split(":").count { it.contains("\"") }
val numberValues = inputJson.split(":").count {
val value = it.trim().split(",")[0].trim()
value.matches(Regex("-?\\d+(\\.\\d+)?"))
}
val booleanValues = inputJson.count { it.toString().matches(Regex("true|false")) }
val nullValues = inputJson.split(":").count { it.contains("null") }
// 8. 原始 JSON 大小
val originalSize = inputJson.length
val formattedSize = formatted.length
return "📋 JSON 格式化和验证\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"1️⃣ 验证结果:\n" +
" JSON 有效性: ${if (isValidJson) "✅ 有效" else "❌ 无效"}\n" +
" 大括号匹配: ${if (bracesMatched) "✅ 匹配" else "❌ 不匹配"}\n" +
" 方括号匹配: ${if (bracketsMatched) "✅ 匹配" else "❌ 不匹配"}\n\n" +
"2️⃣ 结构分析:\n" +
" 对象数量: $braceCount\n" +
" 数组数量: $bracketCount\n" +
" 冒号数量: $colonCount\n" +
" 逗号数量: $commaCount\n" +
" 引号数量: $quoteCount\n" +
" 最大深度: $maxDepth\n\n" +
"3️⃣ 键值统计:\n" +
" 键的数量: ${keys.size}\n" +
" 键列表: ${if (keys.isEmpty()) "无" else keys.joinToString(", ")}\n\n" +
"4️⃣ 值类型统计:\n" +
" 字符串值: $stringValues 个\n" +
" 数值: $numberValues 个\n" +
" 布尔值: $booleanValues 个\n" +
" 空值: $nullValues 个\n\n" +
"5️⃣ 大小对比:\n" +
" 原始大小: $originalSize 字节\n" +
" 格式化后: $formattedSize 字节\n\n" +
"6️⃣ 格式化结果:\n" +
"$formatted\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 处理完成!"
}
fun formatJson(json: String): String {
val result = StringBuilder()
var indent = 0
var inString = false
var i = 0
while (i < json.length) {
val char = json[i]
when {
char == '"' && (i == 0 || json[i - 1] != '\\') -> {
inString = !inString
result.append(char)
}
!inString && (char == '{' || char == '[') -> {
result.append(char)
indent++
result.append("\n")
result.append(" ".repeat(indent))
}
!inString && (char == '}' || char == ']') -> {
indent--
result.append("\n")
result.append(" ".repeat(indent))
result.append(char)
}
!inString && char == ',' -> {
result.append(char)
result.append("\n")
result.append(" ".repeat(indent))
}
!inString && char == ':' -> {
result.append(char)
result.append(" ")
}
char != ' ' || inString -> {
result.append(char)
}
}
i++
}
return result.toString()
}
ArkTS 调用代码(带输入框)
import { jsonFormatterValidator } from './hellokjs';
@Entry
@Component
struct Index {
@State message: string = '加载中...';
@State results: string[] = [];
@State caseTitle: string = 'JSON格式化和验证';
@State inputText: string = '{"name":"John","age":30,"city":"New York"}';
aboutToAppear(): void {
this.loadResults();
}
loadResults(): void {
try {
const results: string[] = [];
const algorithmResult = jsonFormatterValidator(this.inputText);
results.push(algorithmResult);
this.results = results;
this.message = '✓ 处理完成';
} catch (error) {
this.message = `✗ 错误: ${error}`;
}
}
build() {
Column() {
// 顶部标题栏
Row() {
Text('KMP 鸿蒙跨端')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Spacer()
Text('Kotlin 案例')
.fontSize(14)
.fontColor(Color.White)
}
.width('100%')
.height(50)
.backgroundColor('#3b82f6')
.padding({ left: 20, right: 20 })
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.SpaceBetween)
// 案例标题
Column() {
Text(this.caseTitle)
.fontSize(20)
.fontWeight(FontWeight.Bold)
.fontColor('#1f2937')
Text(this.message)
.fontSize(13)
.fontColor('#6b7280')
.margin({ top: 5 })
}
.width('100%')
.padding({ left: 20, right: 20, top: 20, bottom: 15 })
.alignItems(HorizontalAlign.Start)
// 输入框区域
Column() {
Text('输入 JSON:')
.fontSize(14)
.fontWeight(FontWeight.Bold)
.fontColor('#1f2937')
.margin({ bottom: 8 })
TextInput({ placeholder: '输入要格式化的 JSON...', text: this.inputText })
.width('100%')
.height(60)
.padding(12)
.border({ width: 1, color: '#d1d5db' })
.borderRadius(6)
.onChange((value: string) => {
this.inputText = value
})
Button('格式化')
.width('100%')
.height(40)
.margin({ top: 12 })
.backgroundColor('#3b82f6')
.fontColor(Color.White)
.onClick(() => {
this.loadResults()
})
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 16 })
// 结果显示区域
Scroll() {
Column() {
ForEach(this.results, (result: string) => {
Column() {
Text(result)
.fontSize(13)
.fontFamily('monospace')
.fontColor('#374151')
.width('100%')
.margin({ top: 10 })
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.border({ width: 1, color: '#e5e7eb' })
.borderRadius(8)
.margin({ bottom: 12 })
})
}
.width('100%')
.padding({ left: 16, right: 16 })
}
.layoutWeight(1)
.width('100%')
// 底部按钮区域
Row() {
Button('示例 JSON')
.width('48%')
.height(44)
.backgroundColor('#10b981')
.fontColor(Color.White)
.fontSize(14)
.onClick(() => {
this.inputText = '{"name":"John","age":30,"city":"New York"}'
this.loadResults()
})
Button('清空')
.width('48%')
.height(44)
.backgroundColor('#6b7280')
.fontColor(Color.White)
.fontSize(14)
.onClick(() => {
this.inputText = ''
this.results = []
})
}
.width('100%')
.padding({ left: 16, right: 16, bottom: 20 })
}
.width('100%')
.height('100%')
.backgroundColor('#f9fafb')
}
}
编译过程详解
Kotlin 到 JavaScript 的转换
| Kotlin 特性 | JavaScript 等价物 |
|---|---|
| count() | 条件计数循环 |
| Regex.findAll() | 字符串 match 方法 |
| StringBuilder | 字符串连接 |
| when 表达式 | switch 或 if-else |
| repeat() | 字符串重复 |
关键转换点
- 字符串遍历:转换为 for 循环
- 正则表达式:转换为 JavaScript RegExp
- 集合操作:转换为数组操作
- 字符串处理:保持功能一致
算法扩展
扩展 1:添加 JSON 压缩
fun compressJson(json: String): String {
return json.replace(Regex("\\s+"), "")
.replace(Regex(":\\s+"), ":")
.replace(Regex(",\\s+"), ",")
}
扩展 2:添加 JSON 路径查询
fun getJsonValue(json: String, path: String): String {
val keys = path.split(".")
var current = json
for (key in keys) {
val pattern = Regex("\"$key\"\\s*:\\s*([^,}\\]]+)")
val match = pattern.find(current)
if (match != null) {
current = match.groupValues[1]
} else {
return "未找到"
}
}
return current
}
扩展 3:添加 JSON 转换
fun jsonToMap(json: String): Map<String, String> {
val result = mutableMapOf<String, String>()
val keyPattern = Regex("\"([^\"]+)\"\\s*:\\s*([^,}]+)")
keyPattern.findAll(json).forEach { match ->
result[match.groupValues[1]] = match.groupValues[2]
}
return result
}
扩展 4:添加 JSON 差异对比
fun compareJson(json1: String, json2: String): List<String> {
val differences = mutableListOf<String>()
val keys1 = extractKeys(json1)
val keys2 = extractKeys(json2)
for (key in keys1) {
if (!keys2.contains(key)) {
differences.add("键 '$key' 仅在第一个 JSON 中存在")
}
}
return differences
}
最佳实践
1. 使用 count() 统计
// ✅ 好:使用 count()
val braceCount = json.count { it == '{' }
// ❌ 不好:使用 filter().size
val braceCount = json.filter { it == '{' }.size
2. 使用正则表达式提取
// ✅ 好:使用 Regex.findAll()
val keys = mutableListOf<String>()
Regex("\"([^\"]+)\"\\s*:").findAll(json).forEach { match ->
keys.add(match.groupValues[1])
}
// ❌ 不好:手动查找
var start = 0
while (true) {
start = json.indexOf("\"", start)
// 复杂的查找逻辑
}
3. 保护字符串内容
// ✅ 好:检查是否在字符串中
var inString = false
for (char in json) {
if (char == '"') inString = !inString
if (!inString && char == '{') { /* 处理 */ }
}
// ❌ 不好:忽略字符串内容
for (char in json) {
if (char == '{') { /* 处理 */ }
}
4. 使用 StringBuilder 构建结果
// ✅ 好:使用 StringBuilder
val result = StringBuilder()
for (char in json) {
result.append(char)
}
// ❌ 不好:字符串连接
var result = ""
for (char in json) {
result += char
}
常见问题
Q1: 如何处理转义字符?
A: 检查前一个字符是否为反斜杠:
var inString = false
for (i in json.indices) {
if (json[i] == '"' && (i == 0 || json[i - 1] != '\\')) {
inString = !inString
}
}
Q2: 如何提取嵌套的 JSON 值?
A: 使用递归或栈来跟踪深度:
fun getNestedValue(json: String, path: List<String>): String {
var current = json
for (key in path) {
val pattern = Regex("\"$key\"\\s*:\\s*\\{([^}]+)\\}")
val match = pattern.find(current)
if (match != null) {
current = "{${match.groupValues[1]}}"
}
}
return current
}
Q3: 如何验证 JSON 的完整性?
A: 检查所有括号是否匹配:
fun isValidJson(json: String): Boolean {
var braceCount = 0
var bracketCount = 0
var inString = false
for (i in json.indices) {
if (json[i] == '"' && (i == 0 || json[i - 1] != '\\')) {
inString = !inString
}
if (!inString) {
when (json[i]) {
'{' -> braceCount++
'}' -> braceCount--
'[' -> bracketCount++
']' -> bracketCount--
}
}
}
return braceCount == 0 && bracketCount == 0
}
Q4: 如何处理大型 JSON 文件?
A: 使用流式处理而不是一次性加载:
fun processLargeJson(filePath: String): Sequence<String> {
return java.io.File(filePath).useLines { lines ->
lines.filter { it.contains(":") }
.map { it.trim() }
.toList()
.asSequence()
}
}
Q5: 如何实现 JSON 的美化打印?
A: 使用缩进和换行:
fun prettyPrintJson(json: String, indent: Int = 2): String {
val result = StringBuilder()
var indentLevel = 0
var inString = false
for (char in json) {
when {
char == '"' -> {
inString = !inString
result.append(char)
}
!inString && (char == '{' || char == '[') -> {
result.append(char)
indentLevel++
result.append("\n").append(" ".repeat(indentLevel * indent))
}
!inString && (char == '}' || char == ']') -> {
indentLevel--
result.append("\n").append(" ".repeat(indentLevel * indent))
result.append(char)
}
!inString && char == ',' -> {
result.append(char)
result.append("\n").append(" ".repeat(indentLevel * indent))
}
!inString && char == ':' -> {
result.append(char).append(" ")
}
char != ' ' || inString -> {
result.append(char)
}
}
}
return result.toString()
}
总结
关键要点
- ✅ 使用 count() 进行统计
- ✅ 使用正则表达式提取数据
- ✅ 保护字符串内容不被处理
- ✅ 使用 StringBuilder 构建结果
- ✅ KMP 能无缝编译到 JavaScript
下一步
- 实现 JSON 压缩功能
- 添加 JSON 路径查询
- 实现 JSON 转换
- 添加 JSON 差异对比
- 实现流式处理大文件
参考资源
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)