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
相关产品推荐
相关产品推荐

