检测编码并使所有的UTF

我从各种RSS源中读出大量文本并将它们插入到我的数据库中。

当然,Feed中使用了几种不同的字符编码,例如UTF-8和ISO-8859-1。

不幸的是,文本的编码有时会出现问题。 例:

1)“Fußball”中的“ß”在我的数据库中应该如下所示:“Ÿ”。 如果是“Ÿ”,则显示正确。

2)有时,“Fußball”中的“ß”在我的数据库中看起来像这样:“ß”。 然后,它显示错误,当然。

3)在其他情况下,“ß”被保存为“ß” - 所以没有任何改变。 然后它也显示错误。

我能做些什么来避免案例2和3?

我怎样才能使所有的编码相同,最好是UTF-8? 何时必须使用utf8_encode(),何时必须使用utf8_decode()(显然是什么效果,但是何时必须使用这些函数?)以及什么时候必须对输入不做任何处理?

你能帮助我,告诉我如何使所有的编码都一样吗? 也许用函数mb-detect-encoding()? 我可以为此写一个函数吗? 所以我的问题是:1)如何找出文本使用什么编码2)如何将其转换为UTF-8 - 无论旧编码是什么

编辑:这样的功能会工作吗?

function correct_encoding($text) {
    $current_encoding = mb_detect_encoding($text, 'auto');
    $text = iconv($current_encoding, 'UTF-8', $text);
    return $text;
}

我已经测试过,但不起作用。 它出什么问题了?


如果您将utf8_encode()应用于已有的UTF8字符串,它将返回一个乱码的UTF8输出。

我提出了解决所有这些问题的功能。 它被称为Encoding::toUTF8()

你不需要知道你的字符串的编码是什么。 它可以是Latin1(iso 8859-1),Windows-1252或UTF8,或者字符串可以混合使用。 Encoding::toUTF8()会将所有内容转换为UTF8。

我这样做是因为一个服务给了我所有混乱的数据源,在同一个字符串中混合使用UTF8和Latin1。

用法:

require_once('Encoding.php'); 
use ForceUTF8Encoding;  // It's namespaced now.

$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string);

$latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);

下载:

https://github.com/neitanod/forceutf8

更新:

我已经包含了另一个函数, Encoding::fixUFT8() ,它将修复每个看起来乱码的UTF8字符串。

用法:

require_once('Encoding.php'); 
use ForceUTF8Encoding;  // It's namespaced now.

$utf8_string = Encoding::fixUTF8($garbled_utf8_string);

例子:

echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");
echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football");
echo Encoding::fixUTF8("Fédération Camerounaise de Football");

会输出:

Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football
Fédération Camerounaise de Football

更新:我已将函数( forceUTF8 )转换为一个名为Encoding的类的静态函数族。 新函数是Encoding::toUTF8()


您首先必须检测已使用的编码。 在解析RSS提要(可能通过HTTP)时,您应该从Content-Type HTTP头字段的charset参数中读取编码。 如果它不存在,请从XML处理指令的encoding属性中读取编码。 如果缺少,则使用规范中定义的UTF-8。


编辑这里是我可能会做的事情:

我会用cURL发送和获取响应。 这允许您设置特定的头字段并获取响应头。 获取响应后,您必须解析HTTP响应并将其分解为标头和正文。 然后头部应该包含Content-Type头部字段,其中包含MIME类型和(有希望) charset参数与编码/字符集。 如果不是,我们将分析XML PI的encoding属性的存在并从那里获取编码。 如果这也没有,XML规范定义使用UTF-8作为编码。

$url = 'http://www.lr-online.de/storage/rss/rss/sport.xml';

$accept = array(
    'type' => array('application/rss+xml', 'application/xml', 'application/rdf+xml', 'text/xml'),
    'charset' => array_diff(mb_list_encodings(), array('pass', 'auto', 'wchar', 'byte2be', 'byte2le', 'byte4be', 'byte4le', 'BASE64', 'UUENCODE', 'HTML-ENTITIES', 'Quoted-Printable', '7bit', '8bit'))
);
$header = array(
    'Accept: '.implode(', ', $accept['type']),
    'Accept-Charset: '.implode(', ', $accept['charset']),
);
$encoding = null;
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
$response = curl_exec($curl);
if (!$response) {
    // error fetching the response
} else {
    $offset = strpos($response, "rnrn");
    $header = substr($response, 0, $offset);
    if (!$header || !preg_match('/^Content-Type:s+([^;]+)(?:;s*charset=(.*))?/im', $header, $match)) {
        // error parsing the response
    } else {
        if (!in_array(strtolower($match[1]), array_map('strtolower', $accept['type']))) {
            // type not accepted
        }
        $encoding = trim($match[2], '"'');
    }
    if (!$encoding) {
        $body = substr($response, $offset + 4);
        if (preg_match('/^<?xmls+version=(?:"[^"]*"|'[^']*')s+encoding=("[^"]*"|'[^']*')/s', $body, $match)) {
            $encoding = trim($match[1], '"'');
        }
    }
    if (!$encoding) {
        $encoding = 'utf-8';
    } else {
        if (!in_array($encoding, array_map('strtolower', $accept['charset']))) {
            // encoding not accepted
        }
        if ($encoding != 'utf-8') {
            $body = mb_convert_encoding($body, 'utf-8', $encoding);
        }
    }
    $simpleXML = simplexml_load_string($body, null, LIBXML_NOERROR);
    if (!$simpleXML) {
        // parse error
    } else {
        echo $simpleXML->asXML();
    }
}

检测编码很困难。

mb_detect_encoding根据你通过它的一些候选人猜测mb_detect_encoding工作。 在某些编码中,某些字节序列无效,因此它可以区分各种候选。 不幸的是,有很多编码,其中相同的字节是有效的(但不同)。 在这些情况下,无法确定编码; 您可以在这些情况下实施自己的逻辑来猜测。 例如,来自日文站点的数据可能更有可能具有日文编码。

只要您只处理西欧语言,需要考虑的三种主要编码是utf-8iso-8859-1cp-1252 。 由于这些是许多平台的默认设置,因此它们也最有可能被错误地报告。 例如。 如果人们使用不同的编码,他们可能会坦率地说,因为否则他们的软件会经常中断。 因此,一个好的策略是信任提供者,除非编码被报告为三者之一。 你仍然应该使用mb_check_encoding (请注意,有效不同于 - 相同的输入可能对许多编码有效) mb_check_encoding它确实是有效的。 如果它是其中之一,则可以使用mb_detect_encoding来区分它们。 幸运的是,这是相当确定性的; 你只需要使用正确的检测序列,即UTF-8,ISO-8859-1,WINDOWS-1252

检测到编码后,您需要将其转换为内部表示( UTF-8是唯一的理智选择)。 函数utf8_encodeISO-8859-1转换为UTF-8 ,因此它只能用于特定的输入类型。 对于其他编码,请使用mb_convert_encoding

链接地址: http://www.djcxy.com/p/94627.html

上一篇: Detect encoding and make everything UTF

下一篇: Metadata not associated with Object in aws s3