用KMP鸿蒙实现Kotlin代码行数统计器
本文介绍了一个基于Kotlin Multiplatform的跨平台代码行数统计工具,主要功能包括: 代码行分类统计:能够识别并统计代码行、注释行、空行和混合行 代码质量分析:计算代码密度、注释率和空行率等指标 复杂度评估:根据代码行数给出复杂度等级和质量评分 详细统计:包括最长/最短行、平均行长等数据 该工具核心实现包括: 使用正则表达式和字符串处理进行行类型识别 遍历统计各类代码行数量 计算各项
#
目录
概述
本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的代码行数统计器系统。代码行数统计是软件开发中的一个重要指标,用于衡量项目的规模、复杂度和开发工作量。无论是进行项目评估、代码质量分析还是开发效率统计,一个功能强大的代码行数统计器都能提供有价值的数据支持。
这个案例展示了如何使用 Kotlin 的字符串处理、正则表达式、集合操作和数据统计来创建一个功能丰富的代码分析工具。代码行数统计器需要能够识别和统计不同类型的代码行,包括代码行、注释行、空行和混合行。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持用户输入代码进行实时分析。
工具的特点
- 多行类型识别:能够识别代码行、注释行、空行和混合行
- 精确统计:准确计算各种类型的代码行数
- 详细分析:提供代码复杂度、注释率等多维度分析
- 支持多语言:可扩展支持不同编程语言的代码分析
- 实时处理:支持用户输入进行实时统计
- 跨端兼容:一份 Kotlin 代码可同时服务多个平台
工具功能
1. 代码行统计
- 总行数:统计输入代码的总行数
- 代码行:统计包含实际代码的行数
- 注释行:统计包含注释的行数
- 空行:统计完全空白的行数
- 混合行:统计既有代码又有注释的行数
2. 代码分析
- 代码密度:代码行数占总行数的比例
- 注释率:注释行数占代码行数的比例
- 空行率:空行数占总行数的比例
- 平均行长:代码行的平均字符数
3. 复杂度评估
- 代码复杂度:根据代码行数评估复杂度等级
- 注释充分度:根据注释率评估代码文档完整性
- 代码质量评分:综合评分
4. 详细统计
- 最长行:代码中最长的一行及其长度
- 最短行:代码中最短的非空行及其长度
- 平均行长:所有代码行的平均长度
核心实现
1. 行类型识别
fun classifyLine(line: String): LineType {
val trimmed = line.trim()
return when {
trimmed.isEmpty() -> LineType.EMPTY
trimmed.startsWith("//") -> LineType.COMMENT
trimmed.startsWith("/*") || trimmed.startsWith("*") -> LineType.COMMENT
trimmed.contains("//") -> LineType.MIXED
else -> LineType.CODE
}
}
代码说明:
这个函数用于识别代码行的类型。首先使用 trim() 移除行两端的空白字符,然后根据行的内容使用 when 表达式进行分类。如果行为空,则分类为 EMPTY。如果行以 “//” 或 “/*” 开头,则分类为 COMMENT。如果行包含 “//” 但不是以 “//” 开头,则分类为 MIXED(既有代码又有注释)。否则分类为 CODE。这种分类方式简洁高效,能够准确识别大多数常见的代码行类型。
2. 统计计算
var totalLines = 0
var codeLines = 0
var commentLines = 0
var emptyLines = 0
var mixedLines = 0
for (line in lines) {
totalLines++
when (classifyLine(line)) {
LineType.CODE -> codeLines++
LineType.COMMENT -> commentLines++
LineType.EMPTY -> emptyLines++
LineType.MIXED -> mixedLines++
}
}
代码说明:
这段代码展示了如何遍历所有代码行并进行统计。对于每一行,首先增加总行数计数,然后根据行的类型增加相应的计数器。这种方法简单直接,时间复杂度为 O(n),其中 n 是代码行数。通过这个统计过程,我们可以获得各种类型代码行的准确数量。
3. 比例计算
val codeDensity = if (totalLines > 0) (codeLines * 100.0 / totalLines) else 0.0
val commentRate = if (codeLines > 0) (commentLines * 100.0 / codeLines) else 0.0
val emptyRate = if (totalLines > 0) (emptyLines * 100.0 / totalLines) else 0.0
代码说明:
这段代码计算各种比例指标。代码密度是代码行数占总行数的百分比,反映了代码的紧凑程度。注释率是注释行数占代码行数的百分比,反映了代码的文档完整性。空行率是空行数占总行数的百分比,反映了代码的可读性。这些比例指标可以帮助开发者评估代码的质量和可维护性。
Kotlin 源代码
完整的代码行数统计函数
@OptIn(ExperimentalJsExport::class)
@JsExport
fun codeLineCounter(inputText: String = ""): String {
if (inputText.isEmpty()) {
return "❌ 错误: 请输入代码"
}
val lines = inputText.split("\n")
var totalLines = 0
var codeLines = 0
var commentLines = 0
var emptyLines = 0
var mixedLines = 0
var maxLineLength = 0
var minLineLength = Int.MAX_VALUE
var totalLength = 0
for (line in lines) {
totalLines++
val trimmed = line.trim()
// 分类统计
when {
trimmed.isEmpty() -> emptyLines++
trimmed.startsWith("//") -> commentLines++
trimmed.startsWith("/*") || trimmed.startsWith("*") -> commentLines++
trimmed.contains("//") -> mixedLines++
else -> codeLines++
}
// 长度统计
if (trimmed.isNotEmpty()) {
maxLineLength = maxOf(maxLineLength, line.length)
minLineLength = minOf(minLineLength, line.length)
totalLength += line.length
}
}
// 计算比例
val codeDensity = if (totalLines > 0) roundTo((codeLines * 100.0 / totalLines), 2) else 0.0
val commentRate = if (codeLines > 0) roundTo((commentLines * 100.0 / codeLines), 2) else 0.0
val emptyRate = if (totalLines > 0) roundTo((emptyLines * 100.0 / totalLines), 2) else 0.0
val averageLineLength = if (totalLines - emptyLines > 0) roundTo((totalLength * 1.0 / (totalLines - emptyLines)), 2) else 0.0
// 复杂度评估
val complexity = when {
codeLines < 100 -> "⭐ 很简单"
codeLines < 500 -> "⭐⭐ 简单"
codeLines < 1000 -> "⭐⭐⭐ 中等"
codeLines < 5000 -> "⭐⭐⭐⭐ 复杂"
else -> "⭐⭐⭐⭐⭐ 很复杂"
}
// 代码质量评分
val qualityScore = when {
commentRate >= 30 && codeDensity >= 70 -> "优秀 (A)"
commentRate >= 20 && codeDensity >= 60 -> "良好 (B)"
commentRate >= 10 && codeDensity >= 50 -> "中等 (C)"
else -> "需要改进 (D)"
}
// 代码类型判断
val codeType = when {
inputText.contains("function") || inputText.contains("def ") -> "脚本语言"
inputText.contains("class ") || inputText.contains("interface ") -> "面向对象"
inputText.contains("const ") || inputText.contains("let ") -> "JavaScript"
inputText.contains("fun ") || inputText.contains("val ") -> "Kotlin"
else -> "其他"
}
return "📊 代码行数统计器\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"1️⃣ 基础统计:\n" +
" 总行数: $totalLines\n" +
" 代码行: $codeLines\n" +
" 注释行: $commentLines\n" +
" 空行: $emptyLines\n" +
" 混合行: $mixedLines\n\n" +
"2️⃣ 比例分析:\n" +
" 代码密度: $codeDensity%\n" +
" 注释率: $commentRate%\n" +
" 空行率: $emptyRate%\n" +
" 平均行长: $averageLineLength 字符\n\n" +
"3️⃣ 长度统计:\n" +
" 最长行: $maxLineLength 字符\n" +
" 最短行: ${if (minLineLength == Int.MAX_VALUE) 0 else minLineLength} 字符\n\n" +
"4️⃣ 复杂度评估:\n" +
" 代码复杂度: $complexity\n" +
" 代码质量: $qualityScore\n" +
" 代码类型: $codeType\n\n" +
"5️⃣ 建议:\n" +
" • 代码行数: ${if (codeLines > 1000) "建议分模块重构" else "规模适中"}\n" +
" • 注释完整性: ${if (commentRate < 20) "建议增加注释" else "注释充分"}\n" +
" • 代码可读性: ${if (averageLineLength > 100) "建议缩短行长" else "行长适中"}\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 统计完成!"
}
fun roundTo(value: Double, decimals: Int): Double {
val multiplier = Math.pow(10.0, decimals.toDouble())
return (value * multiplier).toLong() / multiplier
}
Kotlin 代码说明:
这是完整的代码行数统计器的 Kotlin 实现。函数首先验证输入的有效性,然后将输入按行分割。接下来遍历每一行,根据行的内容进行分类统计,同时记录行长度信息。然后计算各种比例指标,包括代码密度、注释率和空行率。根据代码行数评估代码复杂度,根据注释率和代码密度评估代码质量。最后根据代码内容推断代码类型,并提供改进建议。这个实现展示了 Kotlin 的字符串处理、集合操作、条件判断和数据统计能力。
JavaScript 编译代码
当 Kotlin 代码编译到 JavaScript 时,会生成以下代码:
function codeLineCounter(inputText) {
if (inputText === void 0) { inputText = ""; }
if (inputText === "") {
return "❌ 错误: 请输入代码";
}
var lines = inputText.split("\n");
var totalLines = 0;
var codeLines = 0;
var commentLines = 0;
var emptyLines = 0;
var mixedLines = 0;
var maxLineLength = 0;
var minLineLength = Number.MAX_VALUE;
var totalLength = 0;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
totalLines++;
var trimmed = line.trim();
if (trimmed === "") {
emptyLines++;
} else if (trimmed.startsWith("//")) {
commentLines++;
} else if (trimmed.startsWith("/*") || trimmed.startsWith("*")) {
commentLines++;
} else if (trimmed.includes("//")) {
mixedLines++;
} else {
codeLines++;
}
if (trimmed !== "") {
maxLineLength = Math.max(maxLineLength, line.length);
minLineLength = Math.min(minLineLength, line.length);
totalLength += line.length;
}
}
var codeDensity = totalLines > 0 ? roundTo((codeLines * 100.0 / totalLines), 2) : 0.0;
var commentRate = codeLines > 0 ? roundTo((commentLines * 100.0 / codeLines), 2) : 0.0;
var emptyRate = totalLines > 0 ? roundTo((emptyLines * 100.0 / totalLines), 2) : 0.0;
var averageLineLength = (totalLines - emptyLines) > 0 ? roundTo((totalLength * 1.0 / (totalLines - emptyLines)), 2) : 0.0;
var complexity;
if (codeLines < 100) {
complexity = "⭐ 很简单";
} else if (codeLines < 500) {
complexity = "⭐⭐ 简单";
} else if (codeLines < 1000) {
complexity = "⭐⭐⭐ 中等";
} else if (codeLines < 5000) {
complexity = "⭐⭐⭐⭐ 复杂";
} else {
complexity = "⭐⭐⭐⭐⭐ 很复杂";
}
var qualityScore;
if (commentRate >= 30 && codeDensity >= 70) {
qualityScore = "优秀 (A)";
} else if (commentRate >= 20 && codeDensity >= 60) {
qualityScore = "良好 (B)";
} else if (commentRate >= 10 && codeDensity >= 50) {
qualityScore = "中等 (C)";
} else {
qualityScore = "需要改进 (D)";
}
var codeType;
if (inputText.includes("function") || inputText.includes("def ")) {
codeType = "脚本语言";
} else if (inputText.includes("class ") || inputText.includes("interface ")) {
codeType = "面向对象";
} else if (inputText.includes("const ") || inputText.includes("let ")) {
codeType = "JavaScript";
} else if (inputText.includes("fun ") || inputText.includes("val ")) {
codeType = "Kotlin";
} else {
codeType = "其他";
}
var minLine = minLineLength === Number.MAX_VALUE ? 0 : minLineLength;
return "📊 代码行数统计器\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"1️⃣ 基础统计:\n" +
" 总行数: " + totalLines + "\n" +
" 代码行: " + codeLines + "\n" +
" 注释行: " + commentLines + "\n" +
" 空行: " + emptyLines + "\n" +
" 混合行: " + mixedLines + "\n\n" +
"2️⃣ 比例分析:\n" +
" 代码密度: " + codeDensity + "%\n" +
" 注释率: " + commentRate + "%\n" +
" 空行率: " + emptyRate + "%\n" +
" 平均行长: " + averageLineLength + " 字符\n\n" +
"3️⃣ 长度统计:\n" +
" 最长行: " + maxLineLength + " 字符\n" +
" 最短行: " + minLine + " 字符\n\n" +
"4️⃣ 复杂度评估:\n" +
" 代码复杂度: " + complexity + "\n" +
" 代码质量: " + qualityScore + "\n" +
" 代码类型: " + codeType + "\n\n" +
"5️⃣ 建议:\n" +
" • 代码行数: " + (codeLines > 1000 ? "建议分模块重构" : "规模适中") + "\n" +
" • 注释完整性: " + (commentRate < 20 ? "建议增加注释" : "注释充分") + "\n" +
" • 代码可读性: " + (averageLineLength > 100 ? "建议缩短行长" : "行长适中") + "\n\n" +
"━━━━━━━━━━━━━━━━━━━━━\n" +
"✅ 统计完成!";
}
function roundTo(value, decimals) {
var multiplier = Math.pow(10, decimals);
return Math.floor(value * multiplier) / multiplier;
}
JavaScript 代码说明:
Kotlin 编译到 JavaScript 后,代码的逻辑保持不变,但语法转换为 JavaScript 风格。Kotlin 的 when 表达式转换为 JavaScript 的 if-else 链。字符串方法如 startsWith、includes 和 trim 保持不变。Math.max 和 Math.min 用于替代 Kotlin 的 maxOf 和 minOf。Number.MAX_VALUE 用于替代 Kotlin 的 Int.MAX_VALUE。字符串模板转换为字符串连接。这个转换过程是自动的,生成的 JavaScript 代码可以直接在浏览器中运行。
ArkTS 调用代码
在 OpenHarmony 应用中使用 ArkTS 调用代码行数统计器:
import { codeLineCounter } from './hellokjs';
@Entry
@Component
struct CodeLineCounter {
@State message: string = '准备就绪';
@State inputText: string = 'function hello() {\n console.log("Hello");\n}';
@State resultText: string = '';
@State isLoading: boolean = false;
aboutToAppear(): void {
this.generateNewCase();
}
generateNewCase(): void {
this.resultText = '';
this.message = '准备就绪';
const codeSamples = [
'function hello() {\n console.log("Hello");\n}',
'class User {\n constructor(name) {\n this.name = name;\n }\n}',
'const add = (a, b) => a + b;\n// Calculate sum\nconst result = add(1, 2);',
'fun main() {\n println("Hello")\n}\n// Main function',
'interface Animal {\n fun speak()\n}\nclass Dog : Animal {\n override fun speak() {}\n}'
];
const randomIndex = Math.floor(Math.random() * codeSamples.length);
this.inputText = codeSamples[randomIndex];
}
analyzeCode(): void {
this.isLoading = true;
try {
const input: string = this.inputText;
const result: string = codeLineCounter(input);
this.resultText = result;
this.message = '✓ 统计完成';
console.log(result);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
this.message = `✗ 错误: ${errorMessage}`;
} finally {
this.isLoading = false;
}
}
build() {
Column() {
// 顶部标题栏
Column() {
Text('📊 代码行数统计器')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Black)
.margin({ bottom: 4 })
Text('代码复杂度和质量分析')
.fontSize(12)
.fontColor('#333333')
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.alignItems(HorizontalAlign.Start)
.border({ width: 1, color: '#CCCCCC' })
// 主内容区域
Scroll() {
Column() {
// 输入卡片
Column() {
Row() {
Text('代码输入')
.fontSize(15)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Black)
Blank()
Text('示例')
.fontSize(11)
.fontColor('#666666')
.padding({ left: 8, right: 8, top: 4, bottom: 4 })
.backgroundColor('#F0F0F0')
.borderRadius(6)
}
.width('100%')
.margin({ bottom: 16 })
TextInput({ placeholder: '输入代码进行统计...', text: this.inputText })
.width('100%')
.height(120)
.padding(12)
.fontSize(14)
.fontColor(Color.Black)
.fontFamily('monospace')
.placeholderColor('#999999')
.border({ width: 1, color: '#CCCCCC' })
.borderRadius(8)
.backgroundColor(Color.White)
.onChange((value: string) => {
this.inputText = value;
})
.margin({ bottom: 16 })
Button(this.isLoading ? '⏳ 统计中...' : '📊 统计')
.width('100%')
.height(48)
.fontSize(15)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
.backgroundColor(this.isLoading ? '#999999' : Color.Black)
.borderRadius(8)
.onClick(() => {
if (!this.isLoading) {
this.analyzeCode();
}
})
}
.width('92%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ top: 16, bottom: 16, left: 'auto', right: 'auto' })
.border({ width: 1, color: '#CCCCCC' })
// 状态提示
if (this.message !== '准备就绪') {
Row() {
Text(this.message.startsWith('✓') ? '✅' : '⚠️')
.fontSize(18)
.margin({ right: 8 })
Text(this.message)
.fontSize(13)
.fontColor(this.message.startsWith('✓') ? '#22863A' : '#CB2431')
.layoutWeight(1)
}
.width('90%')
.padding(12)
.backgroundColor(this.message.startsWith('✓') ? '#F0FDF4' : '#FEF2F2')
.border({ width: 1, color: this.message.startsWith('✓') ? '#86EFAC' : '#FECACA' })
.borderRadius(12)
.margin({ bottom: 20, left: 'auto', right: 'auto' })
.alignItems(VerticalAlign.Center)
}
// 结果卡片
if (this.resultText) {
Column() {
Row() {
Text('统计结果')
.fontSize(15)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Black)
}
.width('100%')
.padding(12)
.backgroundColor('#F5F5F5')
.borderRadius(8)
.margin({ bottom: 12 })
.border({ width: 1, color: '#CCCCCC' })
Text(this.resultText)
.fontSize(11)
.fontFamily('monospace')
.fontColor(Color.Black)
.width('100%')
.padding(12)
.backgroundColor(Color.White)
.borderRadius(8)
.border({ width: 1, color: '#CCCCCC' })
}
.width('92%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ bottom: 16, left: 'auto', right: 'auto' })
.border({ width: 1, color: '#CCCCCC' })
}
// 底部提示
Column() {
Row() {
Text('ℹ️')
.fontSize(16)
.margin({ right: 8 })
Text('统计提示')
.fontSize(13)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Black)
}
.width('100%')
.margin({ bottom: 10 })
Text('• 支持多种编程语言\n• 统计代码行、注释行、空行\n• 分析代码复杂度和质量\n• 提供改进建议\n• 每次生成新案例都会随机选择不同的代码示例')
.fontSize(12)
.fontColor('#666666')
}
.width('92%')
.padding(14)
.backgroundColor(Color.White)
.borderRadius(8)
.margin({ bottom: 16, left: 'auto', right: 'auto' })
.border({ width: 1, color: '#CCCCCC' })
Blank()
.height(20)
}
.width('100%')
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor(Color.White)
}
}
ArkTS 调用代码说明:
这段 ArkTS 代码展示了如何在 OpenHarmony 应用中集成和使用代码行数统计器。首先导入编译后的 codeLineCounter 函数。然后创建一个 CodeLineCounter 组件,包含代码输入、结果显示和加载状态。generateNewCase 方法从预定义的代码示例中随机选择一个,用于演示工具的功能。analyzeCode 方法调用 Kotlin 编译的函数,获取统计结果,并通过 console.log 输出到控制台。UI 部分使用 ArkUI 的各种组件构建,包括 Column、Row、Text、TextInput 和 Button,实现了一个完整的用户界面。用户可以输入代码,点击"统计"按钮进行分析。
实战案例
案例 1:项目代码质量评估
场景:项目经理需要评估一个新项目的代码质量,了解代码的规模和复杂度。
需求:分析项目中的核心模块代码,统计代码行数、注释率和代码复杂度。
解决方案:使用代码行数统计器分析项目的关键代码文件,获取详细的统计数据和质量评分。
实际应用:这个案例展示了代码行数统计器在项目管理中的应用。通过分析代码的规模和复杂度,项目经理可以评估项目的开发工作量、风险等级和维护难度。代码质量评分可以帮助识别需要改进的地方,如增加注释或重构复杂代码。
案例 2:代码审查中的质量检查
场景:代码审查人员需要快速评估提交的代码是否符合质量标准。
需求:检查代码的注释完整性、代码行长度和复杂度。
解决方案:使用代码行数统计器分析提交的代码,根据统计结果和建议进行代码审查。
实际应用:这个案例展示了代码行数统计器在代码审查中的应用。通过自动化的代码分析,审查人员可以快速识别潜在的质量问题,如注释不足、行长过长或代码过于复杂。这可以提高代码审查的效率和一致性。
案例 3:开发效率统计
场景:技术主管需要统计团队的开发效率,了解每个开发者的代码产出量。
需求:统计每个开发者提交的代码行数、注释行数和代码复杂度。
解决方案:使用代码行数统计器分析每个开发者的代码提交,生成开发效率报告。
实际应用:这个案例展示了代码行数统计器在开发效率统计中的应用。通过统计代码行数和复杂度,技术主管可以评估团队成员的开发效率和代码质量。这些数据可以用于绩效评估、工作量分配和团队管理。
最佳实践
1. 准确的行类型识别
确保正确识别不同类型的代码行,包括单行注释、多行注释、混合行等。
2. 多语言支持
设计灵活的识别规则,支持不同编程语言的代码分析。
3. 详细的统计指标
提供多维度的统计指标,包括行数、比例、长度等,帮助全面评估代码质量。
4. 有意义的建议
根据统计结果提供具体的改进建议,帮助开发者改进代码质量。
5. 性能优化
对于大型代码文件,考虑优化统计算法的性能。
6. 用户友好的输出
提供清晰、易读的统计结果展示,帮助用户快速理解代码质量。
总结
代码行数统计器是一个展示 KMP 跨端开发能力的完整案例。通过一份 Kotlin 代码,我们实现了支持多种统计指标的代码分析工具,并在 OpenHarmony 应用中成功集成。这个案例不仅展示了 Kotlin 的强大功能,还演示了如何构建实用的代码分析工具。
代码行数统计在软件开发中有广泛的应用,从项目评估到代码审查,从开发效率统计到代码质量管理。通过这个工具,开发者可以获得有价值的代码质量数据,做出更好的开发决策。这个案例可以作为学习 KMP 开发、理解跨端编译、掌握 ArkUI 开发的良好起点。
代码行数统计器的设计思想也可以应用到其他代码分析工具,例如代码重复检测、代码覆盖率分析、代码性能分析等。通过灵活运用 Kotlin 的字符串处理、正则表达式和数据统计,我们可以构建各种强大的代码分析工具。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)