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

echo mb_detect_encoding($str, "auto");

Or

echo mb_detect_encoding($str, "UTF-8, ASCII, ISO-8859-1");

我真的不知道结果是什么,但我建议您只是使用不同编码的一些提要,并尝试mb_detect_encoding是否有效。

auto是“ASCII,JIS,UTF-8,EUC-JP,SJIS”的缩写。它返回检测到的字符集,您可以使用iconv将字符串转换为UTF-8。

<?php
function convertToUTF8($str) {
    $enc = mb_detect_encoding($str);

    if ($enc && $enc != 'UTF-8') {
        return iconv($enc, 'UTF-8', $str);
    } else {
        return $str;
    }
}
?>

我还没有测试过,所以不能保证。也许有更简单的方法。

其他回答

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

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

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

对于汉字,通常采用GBK编码。此外,在测试时,投票最多的答案不成立。这里有一个简单的修复方法,让它也能正常工作:

function toUTF8($raw) {
    try{
        return mb_convert_encoding($raw, "UTF-8", "auto"); 
    }catch(\Exception $e){
        return mb_convert_encoding($raw, "UTF-8", "GBK"); 
    }
}

注:这个解决方案是在2017年编写的,应该可以修复当时PHP的问题。我还没有测试最新的PHP是否已经正确理解自动。

制定RSS提要的字符编码似乎很复杂。即使是普通的网页也经常忽略或谎报它们的编码。

因此,您可以尝试使用正确的方法来检测编码,然后退回到某种形式的自动检测(猜测)。

我在http://deer.org.ua/2009/10/06/1/:上找到了一个解决方案

class Encoding
{
    /**
     * http://deer.org.ua/2009/10/06/1/
     * @param $string
     * @return null
     */
    public static function detect_encoding($string)
    {
        static $list = ['utf-8', 'windows-1251'];

        foreach ($list as $item) {
            try {
                $sample = iconv($item, $item, $string);
            } catch (\Exception $e) {
                continue;
            }
            if (md5($sample) == md5($string)) {
                return $item;
            }
        }
        return null;
    }
}

$content = file_get_contents($file['tmp_name']);
$encoding = Encoding::detect_encoding($content);
if ($encoding != 'utf-8') {
    $result = iconv($encoding, 'utf-8', $content);
} else {
    $result = $content;
}

我认为@是一个糟糕的决定,并对deer.org.ua的解决方案做了一些更改。

此版本适用于德语,但您可以修改$CHARSETS和$TESTCHARS。

class CharsetDetector
{
    private static $CHARSETS = array(
        "ISO_8859-1",
        "ISO_8859-15",
        "CP850"
    );

    private static $TESTCHARS = array(
        "€",
        "ä",
        "Ä",
        "ö",
        "Ö",
        "ü",
        "Ü",
        "ß"
    );

    public static function convert($string)
    {
        return self::__iconv($string, self::getCharset($string));
    }

    public static function getCharset($string)
    {
        $normalized = self::__normalize($string);
        if(!strlen($normalized))
            return "UTF-8";
        $best = "UTF-8";
        $charcountbest = 0;
        foreach (self::$CHARSETS as $charset)
        {
            $str = self::__iconv($normalized, $charset);
            $charcount = 0;
            $stop = mb_strlen($str, "UTF-8");

            for($idx = 0; $idx < $stop; $idx++)
            {
                $char = mb_substr($str, $idx, 1, "UTF-8");
                foreach (self::$TESTCHARS as $testchar)
                {
                    if($char == $testchar)
                    {
                        $charcount++;
                        break;
                    }
                }
            }

            if($charcount > $charcountbest)
            {
                $charcountbest = $charcount;
                $best = $charset;
            }
            //echo $text . "<br />";
        }
        return $best;
    }

    private static function __normalize($str)
    {
        $len = strlen($str);
        $ret = "";
        for($i = 0; $i < $len; $i++)
        {
            $c = ord($str[$i]);
            if ($c > 128) {
                if (($c > 247))
                    $ret .= $str[$i];
                elseif
                    ($c > 239) $bytes = 4;
                elseif
                    ($c > 223) $bytes = 3;
                elseif
                    ($c > 191) $bytes = 2;
                else
                    $ret .= $str[$i];

                if (($i + $bytes) > $len)
                    $ret .= $str[$i];
                $ret2 = $str[$i];
                while ($bytes > 1)
                {
                    $i++;
                    $b = ord($str[$i]);
                    if ($b < 128 || $b > 191)
                    {
                        $ret .= $ret2;
                        $ret2 = "";
                        $i += $bytes-1;
                        $bytes = 1;
                        break;
                    }
                    else
                        $ret2 .= $str[$i];
                    $bytes--;
                }
            }
        }
        return $ret;
    }

    private static function __iconv($string, $charset)
    {
        return iconv ($charset, "UTF-8", $string);
    }
}