You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中检测字符串西里尔符号并计数,及二维码解析编码兼容问题求助

Kotlin中检测字符串西里尔符号并计数,及二维码解析编码兼容问题求助

嗨,针对你遇到的二维码编码兼容问题,以及西里尔符号检测、计数的需求,我整理了几个实用的解决方案和优化思路,希望能帮到你:

一、检测字符串是否包含至少一个西里尔符号

你之前的正则是匹配全西里尔字符的字符串,要实现“只要有一个就行”的逻辑,只需要调整正则表达式,让它允许前后有任意其他字符:

fun containsCyrillic(string: String): Boolean {
    // 正则匹配:任意字符 + 至少一个西里尔符号 + 任意字符
    return string.matches(".*[а-яёА-ЯЁ].*".toRegex())
}

// 测试示例
fun main() {
    val string1 = "Name=Филиал" // 包含西里尔符号
    val string2 = "Name=СчеС" // 包含乱码的西里尔符号
    val string3 = "Hello World" // 无西里尔符号
    println(containsCyrillic(string1)) // true
    println(containsCyrillic(string2)) // true
    println(containsCyrillic(string3)) // false
}

另外,也可以通过遍历字符直接判断,这种方式更直观,也能自定义判断范围:

fun containsCyrillic(string: String): Boolean {
    return string.any { char ->
        // 判断字符是否属于西里尔字母范围(包括大小写和ё)
        char in 'а'..'я' || char in 'А'..'Я' || char == 'ё' || char == 'Ё'
    }
}

二、统计字符串中西里尔符号的数量

要统计数量很简单,只需要遍历字符串的每个字符,符合西里尔范围就累加计数:

fun countCyrillicCharacters(string: String): Int {
    return string.count { char ->
        char in 'а'..'я' || char in 'А'..'Я' || char == 'ё' || char == 'Ё'
    }
}

// 测试示例
fun main() {
    val string1 = "Name=Филиал"
    val string2 = "СчеС"
    println(countCyrillicCharacters(string1)) // 6(Ф、и、л、и、а、л)
    println(countCyrillicCharacters(string2)) // 5
}

三、二维码编码兼容的优化思路

你提到的问题是:QR码标记的编码是w1251/KOI8-R,但实际内容是UTF-8,导致解码后出现乱码(比如"СчеС"这种)。仅靠西里尔符号的存在/计数可能不够准确,因为乱码本身也会包含西里尔字符。这里有几个更靠谱的优化方向:

1. 乱码特征判断

当按标记编码解码后,出现的乱码通常是“单个西里尔符号夹杂无意义字符”,或者大量重复的Р、С这类符号(这是UTF-8转w1251常见的乱码表现)。可以结合以下逻辑:

  • 统计西里尔符号的比例:如果西里尔符号占比过高(比如超过80%),且都是类似Р、С、Т这类高频乱码字符,大概率是编码错误;
  • 检测是否存在“无法组成正常俄语词汇”的字符组合,比如连续的РС、СР等。

2. 双重解码验证

当编码标记为1或3时,同时尝试两种解码方式:

  • 按标记的编码(w1251/KOI8-R)解码;
  • 直接按UTF-8解码。
    然后对比两个结果,选择更“合理”的那个:
  • 如果其中一个结果包含正常的俄语词汇(可以用简单的词库匹配,或者检测是否有连续的有效西里尔词汇),就选这个;
  • 如果其中一个结果的乱码特征更明显,就排除它。

比如修改你的checkEncoding函数:

private fun checkEncoding(encoding: String, rawBytes: ByteArray): String {
    return when (encoding) {
        "1", "3" -> {
            val charset = if (encoding == "1") Charset.forName("windows-1251") else Charset.forName("KOI8-R")
            val decodedByMarkedCharset = String(rawBytes, charset)
            val decodedByUtf8 = String(rawBytes, Charsets.UTF_8)
            
            // 判断哪个结果更合理:比如包含有效西里尔词汇,或者乱码更少
            if (isValidRussianString(decodedByUtf8)) {
                decodedByUtf8
            } else {
                decodedByMarkedCharset
            }
        }
        "2" -> String(rawBytes, Charsets.UTF_8)
        else -> throw ErrorsBuilder.UNKNOWN_ENCODING_ERROR.unknownEncodingException(String(rawBytes))
    }
}

// 简单的有效性判断示例:包含至少一个长度≥2的西里尔词汇,且乱码类西里尔字符占比不超过50%
private fun isValidRussianString(string: String): Boolean {
    val cyrillicWordRegex = "[а-яёА-ЯЁ]{2,}".toRegex()
    val hasValidWords = cyrillicWordRegex.containsMatchIn(string)
    val garbageCyrillicRatio = countCyrillicCharacters(string).toDouble() / string.length
    // 比如有效词汇存在,且乱码类西里尔字符占比不超过50%
    return hasValidWords && garbageCyrillicRatio <= 0.5
}

3. 容错性解码顺序

如果无法准确判断,也可以优先尝试UTF-8解码,再回退到标记的编码:

  • 先按UTF-8解码,检查结果是否包含可识别的内容(比如业务字段,如"Name="后面的内容是否正常);
  • 如果结果明显是乱码,再按标记的编码解码。

备注:内容来源于stack exchange,提问作者VOVDOGG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 15:32:26