我从各种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;
}

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


当前回答

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

我做了一个函数来解决所有这些问题。它被称为Encoding::toUTF8()。

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

我这样做是因为一个服务给了我一个混乱的数据提要,在同一个字符串中混合了UTF-8和Latin1。

用法:

require_once('Encoding.php');
use \ForceUTF8\Encoding;  // 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(),它将修复每个看起来乱码的UTF-8字符串。

用法:

require_once('Encoding.php');
use \ForceUTF8\Encoding;  // 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

我在一个名为Encoding的类上将函数(forceeutf8)转换为一系列静态函数。新函数是Encoding::toUTF8()。

其他回答

这很简单:当您得到一些不是UTF-8的东西时,您必须将其编码为UTF-8。

因此,当你获取某个ISO 8859-1的提要时,通过utf8_encode解析它。

但是,如果您正在获取UTF-8提要,则不需要做任何事情。

我知道这是一个老问题,但我认为一个有用的答案不会有坏处。我在桌面应用程序、SQLite和GET/POST变量之间的编码有问题。有些会使用UTF-8,有些会使用ASCII,当涉及到外国字符时,基本上所有事情都会搞砸。

这是我的解决方案。在处理之前,它会在每个页面加载时擦除GET/POST/REQUEST(我省略了cookie,但如果需要可以添加它们)。它在标题中工作得很好。如果PHP不能自动检测到源编码,它将抛出警告,因此这些警告将被@'s抑制。

//Convert everything in our vars to UTF-8 for playing nice with the database...
//Use some auto detection here to help us not double-encode...
//Suppress possible warnings with @'s for when encoding cannot be detected
try
{
    $process = array(&$_GET, &$_POST, &$_REQUEST);
    while (list($key, $val) = each($process)) {
        foreach ($val as $k => $v) {
            unset($process[$key][$k]);
            if (is_array($v)) {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = $v;
                $process[] = &$process[$key][@mb_convert_encoding($k,'UTF-8','auto')];
            } else {
                $process[$key][@mb_convert_encoding($k,'UTF-8','auto')] = @mb_convert_encoding($v,'UTF-8','auto');
            }
        }
    }
    unset($process);
}
catch(Exception $ex){}

我在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和其他操作没有起任何作用。

当你试着掌握多种语言时,比如日语和韩语,你可能会遇到麻烦。

带有'auto'参数的Mb_convert_encoding不能很好地工作。设置mb_detect_order('ASCII,UTF-8,JIS,EUC- jp,SJIS,EUC- kr,UHC')没有帮助,因为它会错误地检测EUC-*。

我的结论是,只要输入字符串来自HTML,它就应该在元元素中使用“字符集”。我使用Simple HTML DOM Parser,因为它支持无效的HTML。

下面的代码片段从网页中提取title元素。如果您想转换整个页面,那么您可能需要删除一些行。

<?php
require_once 'simple_html_dom.php';

echo convert_title_to_utf8(file_get_contents($argv[1])), PHP_EOL;

function convert_title_to_utf8($contents)
{
    $dom = str_get_html($contents);
    $title = $dom->find('title', 0);
    if (empty($title)) {
        return null;
    }
    $title = $title->plaintext;
    $metas = $dom->find('meta');
    $charset = 'auto';
    foreach ($metas as $meta) {
        if (!empty($meta->charset)) { // HTML5
            $charset = $meta->charset;
        } else if (preg_match('@charset=(.+)@', $meta->content, $match)) {
            $charset = $match[1];
        }
    }
    if (!in_array(strtolower($charset), array_map('strtolower', mb_list_encodings()))) {
        $charset = 'auto';
    }
    return mb_convert_encoding($title, 'UTF-8', $charset);
}

一个实现isutf8函数的好方法可以在php.net上找到:

function isUTF8($string) {
    return (utf8_encode(utf8_decode($string)) == $string);
}