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

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

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

“Fußball”中的“ß”在我的数据库中应该是这样的:“Ÿ”。如果是“Ÿ”,则显示正确。 有时,“Fußball”中的“ß”在我的数据库中看起来像这样:“ß”。当然,这样就会显示错误。 在其他情况下,“ß”被保存为“ß”-因此没有任何变化。然后它也会被错误地显示。

我怎么做才能避免情况2和3?

我如何使所有的编码相同,最好是UTF-8?什么时候我必须使用utf8_encode(),什么时候我必须使用utf8_decode()(很清楚的效果是什么,但什么时候我必须使用函数?),什么时候我必须对输入什么都不做?

如何让所有编码都相同呢?也许使用函数mb_detect_encoding()?我能写一个函数吗?所以我的问题是:

如何找出文本使用的编码? 我如何将其转换为UTF-8 -无论旧的编码是什么?

这样的函数可行吗?

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

我已经测试过了,但是不行。有什么问题吗?


当前回答

关于mb_detect_encoding和mb_convert_encoding有趣的事情是,您建议的编码顺序确实很重要:

// $input is actually UTF-8

mb_detect_encoding($input, "UTF-8", "ISO-8859-9, UTF-8");
// ISO-8859-9 (WRONG!)

mb_detect_encoding($input, "UTF-8", "UTF-8, ISO-8859-9");
// UTF-8 (OK)

因此,在指定预期的编码时,您可能希望使用特定的顺序。不过,请记住,这并非万无一失。

其他回答

提醒一下。您说在您的数据库中“ß”应该显示为“Ÿ”。

这可能是因为你正在使用一个Latin-1字符编码的数据库,或者你的PHP-MySQL连接设置错误,也就是说,P认为你的MySQL设置为使用UTF-8,所以它发送数据为UTF-8,但你的MySQL认为PHP发送的数据编码为ISO 8859-1,所以它可能再次尝试将你发送的数据编码为UTF-8,造成这种麻烦。

看一下mysql_set_charset。它可能对你有帮助。

Ÿ是Mojibake for ß。在你的数据库中,你可能有以下十六进制值之一(使用SELECT hex (col)…)来找出):

DF如果列是"latin1", C39F如果列是utf8—OR—它是latin1,但是“双编码” C383C5B8如果被双编码为utf8列

你不应该在PHP中使用任何编码/解码函数;相反,您应该正确地设置数据库和到数据库的连接。

如果涉及MySQL,请参阅:UTF-8字符的问题;我看到的不是我储存的

从头文件中获取编码并将其转换为UTF-8。

$post_url = 'http://website.domain';

/// Get headers ///////////////////////////////////////////////
function get_headers_curl($url)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL,            $url);
    curl_setopt($ch, CURLOPT_HEADER,         true);
    curl_setopt($ch, CURLOPT_NOBODY,         true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT,        15);

    $r = curl_exec($ch);
    return $r;
}

$the_header = get_headers_curl($post_url);

/// Check for redirect ////////////////////////////////////////
if (preg_match("/Location:/i", $the_header)) {
    $arr = explode('Location:', $the_header);
    $location = $arr[1];

    $location = explode(chr(10), $location);
    $location = $location[0];

    $the_header = get_headers_curl(trim($location));
}

/// Get charset ///////////////////////////////////////////////
if (preg_match("/charset=/i", $the_header)) {
    $arr = explode('charset=', $the_header);
    $charset = $arr[1];

    $charset = explode(chr(10), $charset);
    $charset = $charset[0];
}

///////////////////////////////////////////////////////////////////
// echo $charset;

if($charset && $charset != 'UTF-8') {
    $html = iconv($charset, "UTF-8", $html);
}

我在phpQuery (ISO-8859-1而不是UTF-8)上也有同样的问题,这个hack帮助了我:

$html = '<?xml version="1.0" encoding="UTF-8" ?>' . $html;

mb_internal_encoding('UTF-8'), phpQuery::newDocumentHTML($html, 'UTF-8'), mbstring.internal_encoding和其他操作没有起任何作用。

哈帕克斯的回答对我很管用。对我来说,这就足够了:

if (isUTF8($str)) {
    echo $str;
}
else
{
    echo iconv("ISO-8859-1", "UTF-8//TRANSLIT", $str);
}