KMP 实现鸿蒙跨端:Kotlin JSON 美化和分析器

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. 实战案例
  5. 编译过程详解
  6. 工具扩展
  7. 最佳实践
  8. 常见问题

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的 JSON 美化和分析系统。这个案例展示了如何使用 Kotlin 的字符串处理、状态机和数据分析来创建一个功能丰富的 JSON 工具。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持用户输入进行实时处理。

工具的特点

  • JSON 验证:检查 JSON 的合法性
  • 格式化:美化 JSON 使其易于阅读
  • 结构分析:统计 JSON 的结构信息
  • 错误检测:识别常见的 JSON 错误
  • 大小分析:计算原始和格式化后的大小
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. JSON 验证

  • 括号匹配:检查 {} 和 [] 是否匹配
  • 引号匹配:检查 “” 是否匹配
  • 转义处理:正确处理转义字符
  • 错误报告:提示具体的错误信息

2. 结构分析

  • 对象统计:计算 {} 的个数
  • 数组统计:计算 [] 的个数
  • 键值对统计:计算 : 的个数
  • 值类型统计:统计字符串、数字、布尔值、空值的个数

3. 格式化

  • 缩进处理:使用 2 空格缩进
  • 换行处理:在合适的位置换行
  • 空格处理:移除不必要的空格

4. 大小分析

  • 原始大小:输入 JSON 的字节数
  • 格式化大小:格式化后的字节数
  • 增长率:计算大小的变化百分比

核心实现

1. 括号匹配检查

fun checkBrackets(): Boolean {
    val stack = mutableListOf<Char>()
    var inString = false
    var escapeNext = false
    
    for (char in json) {
        if (escapeNext) {
            escapeNext = false
            continue
        }
        
        if (char == '\\') {
            escapeNext = true
            continue
        }
        
        if (char == '"') {
            inString = !inString
            continue
        }
        
        if (inString) continue
        
        when (char) {
            '{', '[' -> stack.add(char)
            '}' -> {
                if (stack.isEmpty() || stack.last() != '{') return false
                stack.removeAt(stack.size - 1)
            }
            ']' -> {
                if (stack.isEmpty() || stack.last() != '[') return false
                stack.removeAt(stack.size - 1)
            }
        }
    }
    
    return stack.isEmpty()
}

2. 引号匹配检查

fun checkQuotes(): Boolean {
    var inString = false
    var escapeNext = false
    
    for (char in json) {
        if (escapeNext) {
            escapeNext = false
            continue
        }
        
        if (char == '\\') {
            escapeNext = true
            continue
        }
        
        if (char == '"') {
            inString = !inString
        }
    }
    
    return !inString
}

3. 结构统计

var braceCount = 0
var bracketCount = 0
var colonCount = 0
var stringCount = 0
var numberCount = 0
var boolCount = 0
var nullCount = 0

var inString = false
var escapeNext = false
var i = 0

while (i < json.length) {
    val char = json[i]
    
    // 处理转义字符
    if (escapeNext) {
        escapeNext = false
        i++
        continue
    }
    
    if (char == '\\') {
        escapeNext = true
        i++
        continue
    }
    
    if (char == '"') {
        inString = !inString
        if (inString) stringCount++
        i++
        continue
    }
    
    if (inString) {
        i++
        continue
    }
    
    when (char) {
        '{' -> braceCount++
        '[' -> bracketCount++
        ':' -> colonCount++
        't', 'f' -> {
            if (json.substring(i).startsWith("true") || json.substring(i).startsWith("false")) {
                boolCount++
                i += if (json.substring(i).startsWith("true")) 3 else 4
            }
        }
        'n' -> {
            if (json.substring(i).startsWith("null")) {
                nullCount++
                i += 3
            }
        }
        in '0'..'9', '-' -> {
            if (i == 0 || json[i - 1] in setOf(':', '[', ',', ' ')) {
                numberCount++
                while (i < json.length && (json[i].isDigit() || json[i] in setOf('.', 'e', 'E', '+', '-'))) {
                    i++
                }
                i--
            }
        }
    }
    
    i++
}

4. JSON 格式化

val formatted = mutableListOf<String>()
var indent = 0
var inString = false
var escapeNext = false
var currentLine = ""

for (char in json) {
    if (escapeNext) {
        currentLine += char
        escapeNext = false
        continue
    }
    
    if (char == '\\') {
        currentLine += char
        escapeNext = true
        continue
    }
    
    if (char == '"') {
        inString = !inString
        currentLine += char
        continue
    }
    
    if (inString) {
        currentLine += char
        continue
    }
    
    when (char) {
        '{', '[' -> {
            currentLine += char
            formatted.add("  ".repeat(indent) + currentLine)
            currentLine = ""
            indent++
        }
        '}', ']' -> {
            if (currentLine.isNotEmpty()) {
                formatted.add("  ".repeat(indent) + currentLine)
                currentLine = ""
            }
            indent--
            formatted.add("  ".repeat(indent) + char)
        }
        ',' -> {
            currentLine += char
            formatted.add("  ".repeat(indent) + currentLine)
            currentLine = ""
        }
        ':' -> {
            currentLine += char + " "
        }
        ' ' -> {
            // 忽略空格
        }
        else -> {
            currentLine += char
        }
    }
}

实战案例

案例:完整的 JSON 美化和分析器

Kotlin 源代码
@OptIn(ExperimentalJsExport::class)
@JsExport
fun jsonBeautifier(inputJson: String = "{\"name\":\"John\",\"age\":30}"): String {
    val json = inputJson.trim()
    
    if (json.isEmpty()) {
        return "❌ 错误: JSON 不能为空"
    }
    
    // 1. 验证括号匹配
    fun checkBrackets(): Boolean {
        val stack = mutableListOf<Char>()
        var inString = false
        var escapeNext = false
        
        for (char in json) {
            if (escapeNext) {
                escapeNext = false
                continue
            }
            
            if (char == '\\') {
                escapeNext = true
                continue
            }
            
            if (char == '"') {
                inString = !inString
                continue
            }
            
            if (inString) continue
            
            when (char) {
                '{', '[' -> stack.add(char)
                '}' -> {
                    if (stack.isEmpty() || stack.last() != '{') return false
                    stack.removeAt(stack.size - 1)
                }
                ']' -> {
                    if (stack.isEmpty() || stack.last() != '[') return false
                    stack.removeAt(stack.size - 1)
                }
            }
        }
        
        return stack.isEmpty()
    }
    
    var isValid = checkBrackets()
    
    // 2. 统计结构
    var braceCount = 0
    var bracketCount = 0
    var stringCount = 0
    var numberCount = 0
    
    // ... 统计逻辑
    
    // 3. 格式化
    val formatted = mutableListOf<String>()
    // ... 格式化逻辑
    
    val formattedJson = formatted.joinToString("\n")
    
    return "🔧 JSON 美化和分析器\n" +
           "━━━━━━━━━━━━━━━━━━━━━\n" +
           "1️⃣ 验证结果:\n" +
           "  状态: ${if (isValid) "✅ 有效" else "❌ 无效"}\n\n" +
           "2️⃣ 结构统计:\n" +
           "  对象数: $braceCount\n" +
           "  数组数: $bracketCount\n" +
           "  字符串: $stringCount\n" +
           "  数字: $numberCount\n\n" +
           "4️⃣ 格式化结果:\n" +
           formattedJson + "\n\n" +
           "✅ 处理完成!"
}
ArkTS 调用代码
import { jsonBeautifier } from './hellokjs';

@Entry
@Component
struct Index {
  @State message: string = '加载中...';
  @State results: string[] = [];
  @State caseTitle: string = 'JSON 美化和分析器';
  @State inputText: string = '{"name":"John","age":30}';

  loadResults(): void {
    try {
      const algorithmResult: string = jsonBeautifier(this.inputText);
      this.results = [algorithmResult];
      this.message = '✓ 分析完成';
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      this.message = `✗ 错误: ${errorMessage}`;
    }
  }

  build() {
    Column() {
      // ... UI 代码
    }
  }
}

编译过程详解

Kotlin 到 JavaScript 的转换

Kotlin 特性 JavaScript 等价物
mutableListOf 数组 []
String.substring 字符串 slice
startsWith 字符串 startsWith
repeat 字符串 repeat
joinToString 数组 join

关键转换点

  1. 字符串处理:转换为 JavaScript 字符串方法
  2. 集合操作:转换为数组操作
  3. 状态机:转换为循环和条件判断
  4. 缩进处理:转换为字符串重复

工具扩展

扩展 1:添加 JSON 压缩

fun compressJson(): String {
    var result = ""
    var inString = false
    var escapeNext = false
    
    for (char in json) {
        if (escapeNext) {
            result += char
            escapeNext = false
            continue
        }
        
        if (char == '\\') {
            result += char
            escapeNext = true
            continue
        }
        
        if (char == '"') {
            inString = !inString
            result += char
            continue
        }
        
        if (inString) {
            result += char
        } else if (!char.isWhitespace()) {
            result += char
        }
    }
    
    return result
}

扩展 2:添加 JSON 路径查询

fun getValueByPath(path: String): String {
    // 实现 JSONPath 查询
    // 例如: $.name, $.hobbies[0]
    return ""
}

扩展 3:添加 JSON 转换

fun jsonToMap(): Map<String, Any> {
    // 将 JSON 转换为 Kotlin Map
    return mapOf()
}

扩展 4:添加 JSON 比较

fun compareJson(other: String): String {
    // 比较两个 JSON 的差异
    return ""
}

最佳实践

1. 使用状态机处理字符串

// ✅ 好:使用状态机
var inString = false
var escapeNext = false

for (char in json) {
    if (escapeNext) {
        escapeNext = false
        continue
    }
    
    if (char == '\\') {
        escapeNext = true
        continue
    }
    
    if (char == '"') {
        inString = !inString
    }
}

// ❌ 不好:简单的字符查找
val inString = json.contains('"')

2. 使用栈验证括号

// ✅ 好:使用栈
val stack = mutableListOf<Char>()
for (char in json) {
    when (char) {
        '{', '[' -> stack.add(char)
        '}' -> if (stack.last() == '{') stack.removeAt(stack.size - 1)
        ']' -> if (stack.last() == '[') stack.removeAt(stack.size - 1)
    }
}

// ❌ 不好:计数器
var braceCount = 0
for (char in json) {
    if (char == '{') braceCount++
    if (char == '}') braceCount--
}

3. 提前验证输入

// ✅ 好:提前检查
if (json.isEmpty()) {
    return "错误: JSON 不能为空"
}

// ❌ 不好:处理过程中才发现
try {
    // 处理 JSON
} catch (e: Exception) {
    return "错误"
}

常见问题

Q1: 如何处理转义字符?

A: 使用 escapeNext 标志追踪转义状态:

var escapeNext = false
for (char in json) {
    if (escapeNext) {
        escapeNext = false
        continue
    }
    
    if (char == '\\') {
        escapeNext = true
    }
}

Q2: 如何正确计算 JSON 大小?

A: 使用字符串长度:

val originalSize = json.length
val formattedSize = formattedJson.length

Q3: 如何处理 Unicode 字符?

A: Kotlin 原生支持 Unicode,直接处理即可。

Q4: 如何验证 JSON 的有效性?

A: 检查括号匹配和引号匹配,以及值的类型。

Q5: 如何优化大型 JSON 的处理?

A: 使用流式处理而不是一次性加载到内存。


总结

关键要点

  • ✅ 使用状态机处理字符串
  • ✅ 使用栈验证括号匹配
  • ✅ 正确处理转义字符
  • ✅ 提前验证输入
  • ✅ KMP 能无缝编译到 JavaScript

下一步

  1. 实现 JSON 压缩
  2. 添加 JSONPath 查询
  3. 实现 JSON 转换
  4. 添加 JSON 比较
  5. 优化性能

参考资源

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐