我在另一个答案中找到了一个有用的功能,我想知道是否有人可以向我解释它在做什么以及它是否可靠。我使用的是mb_detect_encoding(),但是当从Linux操作系统上的ISO8859-1文件中读取时,它被删除了。
这个功能似乎适用于我测试的所有情况。
以下是问题:Get file encoding
这是功能:
function isUTF8($string){
return preg_match('%(?:
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)+%xs', $string);
}
这是检测UTF8字符串的可靠方法吗? 到底是做什么的? 可以变得更强大吗?
答案 0 :(得分:6)
如果您知道字符串的编码,则无法以任何精度猜测编码。这就是mb_detect_encoding
根本不起作用的原因。但是,如果你知道字符串应该的编码方式,你可以使用mb_check_encoding
检查它是否是该编码中的有效字符串。它或多或少都与你的正则表达式有关,可能更全面一些。它可以回答问题“这个字节序列在UTF-8中是否有效?”,清楚是或否。这并不一定意味着实际上 的字符串在该编码中被编码,只是它可能是。例如,使用8位来区分使用所有8位的任何单字节编码与任何其他单字节编码是不可能的。但是UTF-8 应该可以相当区分,但是你可以产生例如也恰好是有效的UTF-8字节序列的Latin-1编码字符串。
简而言之,没有办法确切知道。如果您期望UTF-8,请检查您收到的字节序列是否在UTF-8中有效,那么您可以将该字符串安全地视为UTF-8。除此之外,你几乎无能为力。
答案 1 :(得分:0)
好吧,它只检查字符串是否包含恰好与有效UTF-8代码点对应的字节序列。但是,它不会标记序列0x00-0x7F,它是UTF-8的ASCII兼容子集。
编辑:顺便说一下,我猜测mb_detect_encoding()
"没有正常工作的原因"是因为您的Latin-1编码文件仅使用ASCII兼容子集,该子集在UTF-8中也有效。毫无疑问,mb_detect_encoding()
会将其标记为UTF-8并且它是#34;正确",如果数据只是纯ASCII,则答案UTF-8与拉丁语一样好-1,或ASCII,或任何无数的扩展ASCII编码。
答案 2 :(得分:0)
这将检测字符串的一部分是否是正式有效的UTF-8序列,忽略一个代码单元编码字符(表示ASCII中的代码点)。要使该函数返回true,只要有一个字符看起来像非ASCII UTF-8编码字符就足够了。
答案 3 :(得分:0)
这可能不是您的问题的答案(也许是,请参阅下面的更新),但它可能是您的问题的答案。查看我的Encoding类,它具有将字符串转换为UTF8的方法,无论它们是否已经用Latin1,Win1252或UTF8编码,或者是它们的混合:
Encoding::toUTF8($text_or_array);
Encoding::toWin1252($text_or_array);
Encoding::toISO8859($text_or_array);
// fixes UTF8 strings converted to UTF8 repeatedly:
// "FÃÂédÃÂération" to "Fédération"
Encoding::fixUTF8($text_or_array);
https://stackoverflow.com/a/3479832/290221
该函数逐字节运行,并确定每个函数是否需要转换。
更新
稍微考虑一下,实际上这可能是你问题的答案:
require_once('Encoding.php');
function validUTF8($string){
return Encoding::toUTF8($string) == $string;
}
这是Encoding类: https://github.com/neitanod/forceutf8
答案 4 :(得分:0)
基本上没有。
mb_detect_encoding
实际上是正确的。不,使用ASCII文本作为UTF8不会有任何问题。这就是UTF8首先运作的原因。据我所知,你提供的函数不检查字符串的有效性,只是它包含一些恰好类似于UTF8的序列,因此这个函数可能会失败更糟糕。您可能希望在严格模式下同时使用此功能和 mb_detect_encoding
,并希望它们能够抵消彼此的误报。
如果文本是用非拉丁字母书写的,检测多字节编码的“智能”方法是从相同的位开始查找大小相等的字节块序列。例如,俄语单词“привет”看起来像这样:
11010000 10111111
11010001 10000000
11010000 10111000
11010000 10110010
11010000 10110101
11010001 10000010
然而,这对于基于拉丁语的字母表(可能还有中文)不起作用。
答案 5 :(得分:0)
有问题的功能(用户pilif在链接问题中发布的功能)似乎取自PHP手册中mb_detect_encoding()
页面上的this comment:
正如作者所述,该功能仅用于检查字符串是否包含 UTF-8字符"并且它只查找UTF-8范围内的"非ascii多字节序列"。因此,如果您的字符串只包含简单的ascii字符(如英文文本),则该函数返回false(实际为零),这可能不是您想要的。
他的函数基于同一页面上this previous comment中的另一个函数,实际上,它是用来检查字符串是否为UTF-8并且基于W3C某人创建的this regular expression
这是原始的,正确工作的(我已经测试过的)函数,它将告诉您字符串是否为UTF-8:
// Returns true if $string is valid UTF-8 and false otherwise.
function is_utf8($string) {
// From http://w3.org/International/questions/qa-forms-utf-8.html
return preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $string);
} // function is_utf8