Ale*_*ysh 7 language-agnostic unicode utf-8
我需要处理一大串短字符串(大多数是俄语,但任何其他语言都是可能的,包括来自猫在键盘上行走的随机垃圾).
其中一些字符串将以UTF-8编码两次.
我需要可靠地检测给定的字符串是否是双重编码的,并修复它.我应该在不使用任何外部库的情况下执行此操作,只需检查字节即可.检测应尽可能快.
问题是:如何检测给定字符串是否以UTF-8编码两次?
更新:
原始字符串为UTF-8.这是执行第二次编码的AS3代码(遗憾的是我无法控制客户端代码,所以我无法修复此问题):
private function toUTF8(s : String) : String {
var byteArray : ByteArray = new ByteArray();
byteArray.writeUTFBytes(s);
byteArray.position = 0;
var res : String = "";
while(byteArray.bytesAvailable){
res += String.fromCharCode(byteArray.readUnsignedByte());
}
return res;
}
myString = toUTF8(("" + myString).toLowerCase().substr(0, 64));
Run Code Online (Sandbox Code Playgroud)
注意toLowerCase()电话.也许这可能有帮助吗?
原则上你不能,特别是允许猫垃圾.
在UTF-8编码一次或两次之前,您没有说明数据的原始字符编码是什么.我假设CP1251,(或至少CP1251是其中一种可能性)因为它是一个非常棘手的案例.
采用非ASCII字符.UTF-8编码.你得到一些字节,所有这些字节都是CP1251中的有效字符,除非其中一个碰巧是0x98,这是CP1251中唯一的漏洞.
因此,如果将这些字节从CP1251转换为UTF-8,结果与正确UTF-8编码由这些俄语字符组成的CP1251字符串完全相同.没有办法判断结果是由于错误地对一个字符进行双重编码,还是正确地单个编码2个字符.
如果您可以控制原始数据,则可以在其开头放置BOM.然后,当它返回给您时,检查初始字节以查看您是否具有UTF-8 BOM,或者错误地对BOM进行双重编码的结果.但我想你可能对原始文本没有那种控制权.
在实践中你可以猜测 - UTF-8解码它然后:
(a)查看字符频率,字符对频率,不可打印字符的数量.这可能允许您暂时声明它是无意义的,因此可能是双重编码的.有了足够的不可打印的字符,它可能是如此荒谬,以至于你甚至不能通过在键盘上进行混搭来实际输入它,除非你的ALT键被卡住了.
(b)尝试第二次解码.也就是说,从通过解码UTF-8数据获得的Unicode代码点开始,首先将其编码为CP1251(或其他),然后从UTF-8解码结果.如果任一步骤失败(由于无效的字节序列),那么它肯定不是双重编码,至少不使用CP1251作为错误解释.
如果您有一些可能是UTF-8或可能是CP1251的字节,这或多或少都是您所做的,而您不知道哪个.
对于双编码数据无法区分的单编码cat-garbage,你会得到一些误报,对于双重编码的数据可能只有很少的误报,但是在第一次编码之后仍然看起来像俄语.
如果您的原始编码中有比CP1251更多的漏洞,那么您的漏报就会更少.
字符编码很难.
这是一个对我有用的 PHP 算法。
最好修复你的数据,但如果你不能,这里有一个技巧:
if ( mb_detect_encoding( utf8_decode( $value ) ) === 'UTF-8' ) {
// Double encoded, or bad encoding
$value = utf8_decode( $value );
}
$value = \ForceUTF8\Encoding::toUTF8( $value );
Run Code Online (Sandbox Code Playgroud)
我正在使用的库是: https: //github.com/neitanod/forceutf8/
| 归档时间: |
|
| 查看次数: |
8527 次 |
| 最近记录: |