我从各种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;
}
我已经测试过了,但是不行。有什么问题吗?
我知道这是一个老问题,但我认为一个有用的答案不会有坏处。我在桌面应用程序、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){}
此版本适用于德语,但您可以修改$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);
}
}
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;
}
}
?>
我还没有测试过,所以不能保证。也许有更简单的方法。
关于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)
因此,在指定预期的编码时,您可能希望使用特定的顺序。不过,请记住,这并非万无一失。