重要提示:转换包含欧元符号的 UTF8 数据时,请不要使用 utf_decode 函数。
utf_decode 将数据转换为 ISO-8859-1 字符集。但 ISO-8859-1 字符集不包含欧元符号,因此欧元符号将被转换为问号字符“?”。
要正确转换包含欧元符号的 UTF8 数据,您必须使用
iconv("UTF-8", "CP1252", $data)
(PHP 4, PHP 5, PHP 7, PHP 8)
utf8_decode — 将字符串从 UTF-8 转换为 ISO-8859-1,替换无效或无法表示的字符
此函数已从 PHP 8.2.0 开始 *弃用*。强烈建议不要依赖此函数。
此函数将字符串 string
从 UTF-8
编码转换为 ISO-8859-1
。字符串中的无效 UTF-8
字节,以及 ISO-8859-1
中不存在的 UTF-8
字符(即代码点高于 U+00FF
)将被替换为 ?
。
注意:
许多标记为使用
ISO-8859-1
字符编码的网页实际上使用类似的Windows-1252
编码,并且 Web 浏览器会将ISO-8859-1
网页解释为Windows-1252
。Windows-1252
包含额外的可打印字符,例如欧元符号 (€
) 和弯引号 (“
”
),而不是某些ISO-8859-1
控制字符。此函数不会正确转换此类Windows-1252
字符。如果需要Windows-1252
转换,请使用其他函数。
string
一个 UTF-8 编码的字符串。
返回 string
的 ISO-8859-1 翻译。
版本 | 说明 |
---|---|
8.2.0 | 此函数已被弃用。 |
7.2.0 | 此函数已从 XML 扩展迁移到 PHP 核心。在以前的版本中,它只有在安装了 XML 扩展时才可用。 |
示例 #1 基本示例
<?php
// 将字符串 'Zoë' 从 UTF-8 转换为 ISO 8859-1
$utf8_string = "\x5A\x6F\xC3\xAB";
$iso8859_1_string = utf8_decode($utf8_string);
echo bin2hex($iso8859_1_string), "\n";
// 无效的 UTF-8 序列被替换为 '?'
$invalid_utf8_string = "\xC3";
$iso8859_1_string = utf8_decode($invalid_utf8_string);
var_dump($iso8859_1_string);
// 不存在于 ISO 8859-1 中的字符,例如
// '€' (欧元符号) 也被替换为 '?'
$utf8_string = "\xE2\x82\xAC";
$iso8859_1_string = utf8_decode($utf8_string);
var_dump($iso8859_1_string);
?>
上面的示例将输出
5a6feb string(1) "?" string(1) "?"
注意: 弃用和替代方案
此函数从 PHP 8.2.0 开始 *弃用*,并且将在未来的版本中移除。应该检查现有的用法并用适当的替代方案替换。
可以使用 mb_convert_encoding() 实现类似的功能,它支持 ISO-8859-1 和许多其他字符编码。
<?php
$utf8_string = "\xC3\xAB"; // 'ë' (带分音符的 e) 在 UTF-8 中
$iso8859_1_string = mb_convert_encoding($utf8_string, 'ISO-8859-1', 'UTF-8');
echo bin2hex($iso8859_1_string), "\n";
$utf8_string = "\xCE\xBB"; // 'λ' (希腊小写 lambda) 在 UTF-8 中
$iso8859_7_string = mb_convert_encoding($utf8_string, 'ISO-8859-7', 'UTF-8');
echo bin2hex($iso8859_7_string), "\n";
$utf8_string = "\xE2\x82\xAC"; // '€' (欧元符号) 在 UTF-8 中 (ISO-8859-1 中不存在)
$windows_1252_string = mb_convert_encoding($utf8_string, 'Windows-1252', 'UTF-8');
echo bin2hex($windows_1252_string), "\n";
?>上面的示例将输出
eb eb 80其他可能可用的选项取决于已安装的扩展,包括 UConverter::transcode() 和 iconv().
以下所有方法都给出相同的结果
将<?php
$utf8_string = "\x5A\x6F\xC3\xAB"; // 'Zoë' 在 UTF-8 中
$iso8859_1_string = utf8_decode($utf8_string);
echo bin2hex($iso8859_1_string), "\n";
$iso8859_1_string = mb_convert_encoding($utf8_string, 'ISO-8859-1', 'UTF-8');
echo bin2hex($iso8859_1_string), "\n";
$iso8859_1_string = iconv('UTF-8', 'ISO-8859-1', $utf8_string);
echo bin2hex($iso8859_1_string), "\n";
$iso8859_1_string = UConverter::transcode($utf8_string, 'ISO-8859-1', 'UTF8');
echo bin2hex($iso8859_1_string), "\n";
?>上面的示例将输出
5a6feb 5a6feb 5a6feb 5a6feb'?'
指定为 UConverter::transcode() 的'to_subst'
选项,对于无效或无法在 ISO 8859-1 中表示的字符串,会给出与 utf8_decode() 相同的结果。<?php
$utf8_string = "\xE2\x82\xAC"; // € (欧元符号) 在 ISO 8859-1 中不存在
$iso8859_1_string = UConverter::transcode(
$utf8_string, 'ISO-8859-1', 'UTF-8', ['to_subst' => '?']
);
var_dump($iso8859_1_string);
?>上面的示例将输出
sring(1) "?"
重要提示:转换包含欧元符号的 UTF8 数据时,请不要使用 utf_decode 函数。
utf_decode 将数据转换为 ISO-8859-1 字符集。但 ISO-8859-1 字符集不包含欧元符号,因此欧元符号将被转换为问号字符“?”。
要正确转换包含欧元符号的 UTF8 数据,您必须使用
iconv("UTF-8", "CP1252", $data)
请注意,utf8_decode 只是将以 UTF-8 编码的字符串转换为 ISO-8859-1。更合适的名称应该是 utf8_to_iso88591。如果您的文本已使用 ISO-8859-1 编码,则不需要此函数。如果您不想使用 ISO-8859-1,则不需要此函数。
请注意,UTF-8 可以表示比 ISO-8859-1 更多的字符。尝试将包含无法在 ISO-8859-1 中表示的字符的 UTF-8 字符串转换为 ISO-8859-1 将会使您的文本乱码或丢失字符。尝试使用此函数转换未以 UTF-8 编码的文本很可能会导致文本乱码。
如果您需要将任何文本从任何编码转换为任何其他编码,请查看 iconv()。
如果您运行 Gentoo Linux 并遇到某些 PHP4 应用程序出现以下错误:
Call to undefined function: utf8_decode()
尝试使用启用了“expat”标志重新合并 PHP4。
如果您想从数据库中检索一些 UTF-8 数据,则不需要 utf8_decode()。
只需在任何 SELECT 之前执行以下查询:
$result = mysql_query("SET NAMES utf8");
除了 yannikh 在 gmeil dot com 的注释之外,另一种方法是使用类似于以下内容的 unix 控制台解码包含非拉丁字符的字符串:
C=RU, L=\xD0\x9C\xD0\xBE\xD1\x81\xD0\xBA\xD0\xB2\xD0\xB0,
<?php preg_replace_callback('/\\\\x([0-9A-F]{2})/', function($a){ return pack('H*', $a[1]); }, $str); ?>
上面的代码将输出
C=RU, L=Москва,
我发现检查某事物是否为有效 UTF-8 的最快方法是
<?php
if (iconv('UTF-8', 'UTF-8', $input) != $input) {
/* 它不是 UTF-8--对我来说,它可能是 CP1252,Windows 版本的 Latin 1,包含定向引号和欧元符号。 */
}
?>.
如果 iconv() C 库被告知字符串是 UTF-8 但实际上不是,它就会失败;PHP 库不会失败,它只会返回转换到失败点的结果,因此您必须将结果与输入进行比较,才能确定转换是否成功。
除了 yannikh 的注释之外,要转换十六进制 utf8 字符串:
<?php
echo utf8_decode("\x61\xc3\xb6\x61");
// 按预期工作
$abc="61c3b661";
$newstr = "";
$l = strlen($abc);
for ($i=0;$i<$l;$i+=2){
$newstr .= "\x".$abc[$i].$abc[$i+1];
}
echo utf8_decode($newstr);
// 或 "\x" 的变体:"\\x" 等不会输出您想要的内容
echo utf8_decode(pack('H*',$abc));
// 这会输出正确的字符串,就像第一行一样。
?>
更新 MARC13 函数 utf2iso()
我正在使用它来处理 AJAX POST 调用。
尽管使用了
http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'; charset='utf-8');
它仍然使用 UTF-16 编码波兰字母
这只针对波兰字母
<?php
function utf16_2_utf8 ($nowytekst) {
$nowytekst = str_replace('%u0104','Ą',$nowytekst); //Ą
$nowytekst = str_replace('%u0106','Ć',$nowytekst); //Ć
$nowytekst = str_replace('%u0118','Ę',$nowytekst); //Ę
$nowytekst = str_replace('%u0141','Ł',$nowytekst); //Ł
$nowytekst = str_replace('%u0143','Ń',$nowytekst); //Ń
$nowytekst = str_replace('%u00D3','Ó',$nowytekst); //Ó
$nowytekst = str_replace('%u015A','Ś',$nowytekst); //Ś
$nowytekst = str_replace('%u0179','Ź',$nowytekst); //Ź
$nowytekst = str_replace('%u017B','Ż',$nowytekst); //Ż
$nowytekst = str_replace('%u0105','ą',$nowytekst); //ą
$nowytekst = str_replace('%u0107','ć',$nowytekst); //ć
$nowytekst = str_replace('%u0119','ę',$nowytekst); //ę
$nowytekst = str_replace('%u0142','ł',$nowytekst); //ł
$nowytekst = str_replace('%u0144','ń',$nowytekst); //ń
$nowytekst = str_replace('%u00F3','ó',$nowytekst); //ó
$nowytekst = str_replace('%u015B','ś',$nowytekst); //ś
$nowytekst = str_replace('%u017A','ź',$nowytekst); //ź
$nowytekst = str_replace('%u017C','ż',$nowytekst); //ż
return ($nowytekst);
}
?>
一切顺利,但它没有改变“%u00D3”,“Ó”和“%u00F3”,“ó”。我不知道该如何处理这个问题。
记住!文件必须以 UTF-8 编码保存。
在数组上使用此功能的首选方法是使用 PHP 内置函数“array_map()”,例如
$array = array_map("utf8_decode", $array);
最后一条评论中的正则表达式有一些拼写错误。这是一个
语法有效的,不知道它是否正确。
您必须将表达式连接在一行中。
^(
[\x00-\x7f]|
[\xc2-\xdf][\x80-\xbf]|
[\xe0][\xa0-\xbf][\x80-\xbf]|
[\xe1-\xec][\x80-\xbf]{2}|
[\xed][\x80-\x9f][\x80-\xbf]|
[\xee-\xef][\x80-\xbf]{2}|
[\xf0][\x90-\xbf][\x80-\xbf]{2}|
[\xf1-\xf3][\x80-\xbf]{3}|
[\xf4][\x80-\x8f][\x80-\xbf]{2}
)*$
$string = "Bjørn Johansen";
echo mb_convert_encoding($string, 'ISO-8859-1', 'UTF-8');
----
输出:"Bjørn Johansen"
// 这最终帮助我完成了工作,感谢 Blackbit,我不得不修改过时的 ereg
// 原始评论:"Squirrelmail 在源代码中包含一个很好的函数来将 unicode 转换为实体:"
function charset_decode_utf_8 ($string) {
/* 仅当存在 8 位字符时才执行缓慢的转换 */
/* 避免在 ereg 范围内使用 0xA0 (\240)。RH73 不喜欢那样 */
if (!preg_match("/[\200-\237]/", $string)
&& !preg_match("/[\241-\377]/", $string)
) {
return $string;
}
// 解码三个字节的 unicode 字符
$string = preg_replace("/([\340-\357])([\200-\277])([\200-\277])/e",
"'&#'.((ord('\\1')-224)*4096 + (ord('\\2')-128)*64 + (ord('\\3')-128)).';'",
$string
);
// 解码两个字节的 unicode 字符
$string = preg_replace("/([\300-\337])([\200-\277])/e",
"'&#'.((ord('\\1')-192)*64+(ord('\\2')-128)).';'",
$string
);
return $string;
}
为了回应 fhoech(2005 年 9 月 22 日 11:55),我刚使用您的正则表达式对文件 UTF-8-test.txt 进行了同步测试,'j dot dittmer'(2005 年 9 月 20 日 06:30)正则表达式(消息 #56962),`php-note-2005`(2005 年 2 月 17 日 08:57)正则表达式在他的关于 `mb-detect-encoding` 页面上的消息中 (http://us3.php.net/manual/en/function.mb-detect-encoding.php#50087) 使用了来自 W3C 的正则表达式 (http://w3.org/International/questions/qa-forms-utf-8.html),以及 PHP `mb_detect_encoding` 函数。
以下是结果的总结
使用 phpnote 正则表达式,201 行是有效的 UTF8 字符串
使用 j.dittmer 正则表达式,203 行是有效的 UTF8 字符串
使用 fhoech 正则表达式,200 行是有效的 UTF8 字符串
使用 `mb_detect_encoding`,239 行是有效的 UTF8 字符串
以下是差异行(从左到右,phpnote、j.dittmer 和 fhoech)
第 70 行:不是 UTF8|是 UTF8!|是 UTF8!:2.1.1 1 字节 (U-00000000):""
第 79 行:不是 UTF8|是 UTF8!|是 UTF8!:2.2.1 1 字节 (U-0000007F):""
第 81 行:是 UTF8!|是 UTF8!|不是 UTF8:2.2.3 3 字节 (U-0000FFFF):"" |
第 267 行:是 UTF8!|是 UTF8!|不是 UTF8:5.3.1 U+FFFE = ef bf be = "" |
第 268 行:是 UTF8!|是 UTF8!|不是 UTF8:5.3.2 U+FFFF = ef bf bf = "" |
有趣的是,你说你的正则表达式修正了 j.dittmer 正则表达式,它在 5.3 部分失败了,但在我的测试中,我得到了相反的结果?!
我在 Windows XP 上运行了这个测试,使用 PHP 4.3.11dev。也许这些差异来自操作系统或 PHP 版本。
对于 `mb_detect_encoding`,我使用了以下命令
mb_detect_encoding($line, 'UTF-8, ISO-8859-1, ASCII');
使用 `utf8_decode` 对我来说还不够,因为我从另一个网站获取页面内容。问题出现在与标准拉丁字母不同的字母中。例如,一些字符(对应于 HTML 代码 „、 等)被转换为 "?" 或 "xA0"(十六进制值)。您需要在执行 `utf8_decode` 之前进行一些转换。而且您不能简单地替换它们,因为它们可能是字符的 2 字节代码的一部分(UTF-8 使用 2 个字节)。以下内容适用于西里尔字母,但对于其他字母来说应该非常接近。
function convertMethod($text){
// 问题是 `utf8_decode` 将 „ 等 HTML 字符转换为 ? 或 转换为 \xA0。而且您不能替换它们,因为它们在某些字符字节中,您会破坏西里尔字母(或其他字母)字符。
$problem_enc=array(
'euro',
'sbquo',
'bdquo',
'hellip',
'dagger',
'Dagger',
'permil',
'lsaquo',
'lsquo',
'rsquo',
'ldquo',
'rdquo',
'bull',
'ndash',
'mdash',
'trade',
'rsquo',
'brvbar',
'copy',
'laquo',
'reg',
'plusmn',
'micro',
'para',
'middot',
'raquo',
'nbsp'
);
$text=mb_convert_encoding($text,'HTML-ENTITIES','UTF-8');
$text=preg_replace('#(?<!\Ð)\&('.implode('|',$problem_enc).');#s','--amp{$1}',$text);
$text=mb_convert_encoding($text,'UTF-8','HTML-ENTITIES');
$text=utf8_decode($text);
$text=mb_convert_encoding($text,'HTML-ENTITIES','UTF-8');
$text=preg_replace('#\-\-amp\{([^\}]+)\}#su','&$1;',$text);
$text=mb_convert_encoding($text,'UTF-8','HTML-ENTITIES');
return $text;
}
如果这不起作用,尝试在某些地方设置 "die($text);" 来查看发生了什么。最好用长文本进行测试。很可能破坏其他字母字符。在这种情况下,您字母集的 "Ð" 很可能不正确。您需要在该 `preg_replace` 之后设置 "die($text);" 并查看设置 "--amp" 之前字符的 HTML 代码。
EY!错误不在 `utf8_decode` 函数中。错误在 `mb_detect_encoding` 函数中。如果您在结尾处放置一个带有特殊字符的单词,例如 "accentué",这会导致错误的结果 (UTF-8),但如果您在结尾处放置另一个字符,例如 "accentuée",您将得到正确的结果。因此,您应该始终为该检查添加一个 ISO-8859-1 字符到您的字符串中。我的建议是使用空格。
我试过,它可以工作!
function ISO_convert($array)
{
$array_temp = array();
foreach($array as $name => $value)
{
if(is_array($value))
$array_temp[(mb_detect_encoding($name." ",'UTF-8,ISO-8859-1') == 'UTF-8' ? utf8_decode($name) : $name )] = ISO_convert($value);
else
$array_temp[(mb_detect_encoding($name." ",'UTF-8,ISO-8859-1') == 'UTF-8' ? utf8_decode($name) : $name )] = (mb_detect_encoding($value." ",'UTF-8,ISO-8859-1') == 'UTF-8' ? utf8_decode($value) : $value );
}
return $array_temp;
}
更好的转换方法是使用 iconv,请参阅 https://php.net/iconv -- 示例
<?php
$myUnicodeString = "Åäö";
echo iconv("UTF-8", "ISO-8859-1", $myUnicodeString);
?>
上面的代码将以 ISO-8859-1 编码输出给定变量,您可以将其替换为您喜欢的任何编码。
解决显示错误字形问题的另一种方法是简单地将文档发送为 UTF-8,当然还要发送 UTF-8 数据
<?php
# 将 text/html 替换为您喜欢的任何 MIME 类型。
header("Content-Type: text/html; charset=utf-8");
?>
我创建了这个函数来将来自 AJAX 调用的数据转换为插入我的数据库。
它将 `XMLHttpRequest()` 中的 UTF-8 转换为 ISO-8859-2,我在 LATIN2 MySQL 数据库中使用该编码。
<?php
function utf2iso($tekst)
{
$nowytekst = str_replace("%u0104","\xA1",$tekst); //Ą
$nowytekst = str_replace("%u0106","\xC6",$nowytekst); //Ć
$nowytekst = str_replace("%u0118","\xCA",$nowytekst); //Ę
$nowytekst = str_replace("%u0141","\xA3",$nowytekst); //Ł
$nowytekst = str_replace("%u0143","\xD1",$nowytekst); //Ń
$nowytekst = str_replace("%u00D3","\xD3",$nowytekst); //Ó
$nowytekst = str_replace("%u015A","\xA6",$nowytekst); //Ś
$nowytekst = str_replace("%u0179","\xAC",$nowytekst); //Ź
$nowytekst = str_replace("%u017B","\xAF",$nowytekst); //Ż
$nowytekst = str_replace("%u0105","\xB1",$nowytekst); //ą
$nowytekst = str_replace("%u0107","\xE6",$nowytekst); //ć
$nowytekst = str_replace("%u0119","\xEA",$nowytekst); //ę
$nowytekst = str_replace("%u0142","\xB3",$nowytekst); //ł
$nowytekst = str_replace("%u0144","\xF1",$nowytekst); //ń
$nowytekst = str_replace("%u00D4","\xF3",$nowytekst); //ó
$nowytekst = str_replace("%u015B","\xB6",$nowytekst); //ś
$nowytekst = str_replace("%u017A","\xBC",$nowytekst); //ź
$nowytekst = str_replace("%u017C","\xBF",$nowytekst); //ż
return ($nowytekst);
}
?>
在我的情况下,处理 AJAX 调用的代码文件也必须使用 UTF-8 编码。
简单的 UTF-8 到 HTML 转换
function utf8_to_html ($data)
{
return preg_replace("/([\\xC0-\\xF7]{1,1}[\\x80-\\xBF]+)/e", '_utf8_to_html("\\1")', $data);
}
function _utf8_to_html ($data)
{
$ret = 0;
foreach((str_split(strrev(chr((ord($data{0}) % 252 % 248 % 240 % 224 % 192) + 128) . substr($data, 1)))) as $k => $v)
$ret += (ord($v) % 128) * pow(64, $k);
return "&#$ret;";
}
示例
echo utf8_to_html("a b č ć ž こ に ち わ ()[]{}!#$?*");
输出
a b č ć ž こ に ち わ ()[]{}!#$?*
对将 utf82iso88592 和 iso88592tutf8 互相转换的函数的修正。
Janusz 忘记了 "ń",并且 "ż" 偶尔被错误地替换为 "ź"。
GTo
function utf82iso88592($tekscik) {
$tekscik = str_replace("\xC4\x85", "ą", $tekscik);
$tekscik = str_replace("\xC4\x84", 'Ą', $tekscik);
$tekscik = str_replace("\xC4\x87", 'ć', $tekscik);
$tekscik = str_replace("\xC4\x86", 'Ć', $tekscik);
$tekscik = str_replace("\xC4\x99", 'ę', $tekscik);
$tekscik = str_replace("\xC4\x98", 'Ę', $tekscik);
$tekscik = str_replace("\xC5\x82", 'ł', $tekscik);
$tekscik = str_replace("\xC5\x81", 'Ł', $tekscik);
$tekscik = str_replace("\xC5\x84", 'ń', $tekscik);
$tekscik = str_replace("\xC5\x83", 'Ń', $tekscik);
$tekscik = str_replace("\xC3\xB3", '?', $tekscik);
$tekscik = str_replace("\xC3\x93", '?', $tekscik);
$tekscik = str_replace("\xC5\x9B", 'ś', $tekscik);
$tekscik = str_replace("\xC5\x9A", 'Ś', $tekscik);
$tekscik = str_replace("\xC5\xBC", 'ż', $tekscik);
$tekscik = str_replace("\xC5\xBB", 'Ż', $tekscik);
$tekscik = str_replace("\xC5\xBA", 'ź', $tekscik);
$tekscik = str_replace("\xC5\xB9", 'Ź', $tekscik);
return $tekscik;
} // utf82iso88592
function iso885922utf8($tekscik) {
$tekscik = str_replace("ą", "\xC4\x85", $tekscik);
$tekscik = str_replace('Ą', "\xC4\x84", $tekscik);
$tekscik = str_replace('ć', "\xC4\x87", $tekscik);
$tekscik = str_replace('Ć', "\xC4\x86", $tekscik);
$tekscik = str_replace('ę', "\xC4\x99", $tekscik);
$tekscik = str_replace('Ę', "\xC4\x98", $tekscik);
$tekscik = str_replace('ł', "\xC5\x82", $tekscik);
$tekscik = str_replace('Ł', "\xC5\x81", $tekscik);
$tekscik = str_replace('ń', "\xC5\x84", $tekscik);
$tekscik = str_replace('Ń',"\xC5\x83", $tekscik);
$tekscik = str_replace('?', "\xC3\xB3", $tekscik);
$tekscik = str_replace('?', "\xC3\x93", $tekscik);
$tekscik = str_replace('ś', "\xC5\x9B", $tekscik);
$tekscik = str_replace('Ś', "\xC5\x9A", $tekscik);
$tekscik = str_replace('ż', "\xC5\xBC", $tekscik);
$tekscik = str_replace('Ż', "\xC5\xBB", $tekscik);
$tekscik = str_replace('ź', "\xC5\xBA", $tekscik);
$tekscik = str_replace('Ź', "\xC5\xB9", $tekscik);
return $tekscik;
} // iso885922utf8
更新 okx dot oliver dot koenig at gmail dot com 提供的 PHP 5.6 答案,因为 e/ 修饰符已过时
// 这最终帮助我完成了工作,感谢 Blackbit,我不得不修改过时的 ereg
// 原始评论:"Squirrelmail 在源代码中包含一个很好的函数来将 unicode 转换为实体:"
function charset_decode_utf_8($string)
{
/* 仅当存在 8 位字符时才执行缓慢的转换 */
if ( !preg_match("/[\200-\237]/", $string) && !preg_match("/[\241-\377]/", $string) )
return $string;
// 解码三个字节的 unicode 字符
$string = preg_replace_callback("/([\340-\357])([\200-\277])([\200-\277])/",
create_function ('$matches', 'return \'&#\'.((ord($matches[1])-224)*4096+(ord($matches[2])-128)*64+(ord($matches[3])-128)).\';\';'),
$string);
// 解码两个字节的 unicode 字符
$string = preg_replace_callback("/([\300-\337])([\200-\277])/",
create_function ('$matches', 'return \'&#\'.((ord($matches[1])-192)*64+(ord($matches[2])-128)).\';\';'),
$string);
return $string;
}
享受
以下代码帮助我处理混合编码(UTF8+ISO-8859-1(x))。在这种情况下,我拥有由设计师制作和维护的模板文件,他们不关心编码,并且 MySQL 数据在 utf8_binary_ci 编码的表中。
<?php
class Helper
{
function strSplit($text, $split = 1)
{
if (!is_string($text)) return false;
if (!is_numeric($split) && $split < 1) return false;
$len = strlen($text);
$array = array();
$i = 0;
while ($i < $len)
{
$key = NULL;
for ($j = 0; $j < $split; $j += 1)
{
$key .= $text{$i};
$i += 1;
}
$array[] = $key;
}
return $array;
}
function UTF8ToHTML($str)
{
$search = array();
$search[] = "/([\\xC0-\\xF7]{1,1}[\\x80-\\xBF]+)/e";
$search[] = "/ä/";
$search[] = "/ö/";
$search[] = "/ü/";
$search[] = "/Ä/";
$search[] = "/Ö/";
$search[] = "/Ü/";
$search[] = "/ß/";
$replace = array();
$replace[] = 'Helper::_UTF8ToHTML("\\1")';
$replace[] = "ä";
$replace[] = "ö";
$replace[] = "ü";
$replace[] = "Ä";
$replace[] = "Ö";
$replace[] = "ü";
$replace[] = "ß";
$str = preg_replace($search, $replace, $str);
return $str;
}
function _UTF8ToHTML($str)
{
$ret = 0;
foreach((Helper::strSplit(strrev(chr((ord($str{0}) % 252 % 248 % 240 % 224 % 192) + 128).substr($str, 1)))) as $k => $v)
$ret += (ord($v) % 128) * pow(64, $k);
return "&#".$ret.";";
}
}
// Usage example:
$tpl = file_get_contents("template.tpl");
/* ... */
$row = mysql_fetch_assoc($result);
print(Helper::UTF8ToHTML(str_replace("{VAR}", $row['var'], $tpl)));
?>
我注意到下面的 utf-8 到 html 函数只适用于 2 字节长的代码。 我想要 3 字节支持(抱歉,没有做 4、5 或 6)。 我还注意到字符代码的连接没有十六进制前缀 0x,因此在大型 2 字节代码中失败了。)
<?
public function utf2html (&$str) {
$ret = "";
$max = strlen($str);
$last = 0; // 保持最后一个常规字符的索引
for ($i=0; $i<$max; $i++) {
$c = $str{$i};
$c1 = ord($c);
if ($c1>>5 == 6) { // 110x xxxx,110 是 2 字节 unicode 的前缀
$ret .= substr($str, $last, $i-$last); // 追加我们已经传递的所有常规字符
$c1 &= 31; // 删除 3 位两个字节前缀
$c2 = ord($str{++$i}); // 下一个字节
$c2 &= 63; // 删除 2 位尾随字节前缀
$c2 |= (($c1 & 3) << 6); // c1 的最后 2 位成为 c2 的前 2 位
$c1 >>= 2; // c1 向右移位 2 位
$ret .= "&#" . ($c1 * 0x100 + $c2) . ";"; // 这是最快的字符串连接
$last = $i+1;
}
elseif ($c1>>4 == 14) { // 1110 xxxx,110 是 3 字节 unicode 的前缀
$ret .= substr($str, $last, $i-$last); // 追加我们已经传递的所有常规字符
$c2 = ord($str{++$i}); // 下一个字节
$c3 = ord($str{++$i}); // 第三个字节
$c1 &= 15; // 删除 4 位三个字节前缀
$c2 &= 63; // 删除 2 位尾随字节前缀
$c3 &= 63; // 删除 2 位尾随字节前缀
$c3 |= (($c2 & 3) << 6); // c2 的最后 2 位成为 c3 的前 2 位
$c2 >>=2; //c2 向右移位 2 位
$c2 |= (($c1 & 15) << 4); // c1 的最后 4 位成为 c2 的前 4 位
$c1 >>= 4; // c1 向右移位 4 位
$ret .= '&#' . (($c1 * 0x10000) + ($c2 * 0x100) + $c3) . ';'; // 这是最快的字符串连接
$last = $i+1;
}
}
$str=$ret . substr($str, $last, $i); // 追加最后一批常规字符
}
?>
我刚刚创建了这个代码片段来改进我的一个网站发送的用户可自定义电子邮件。
目标是使用 UTF-8(Unicode),以便非英语用户能够享受到所有 Unicode 的优势,但同时也要让英语(或更具体地说,英语 MS-Outlook 用户)能够无缝使用。 问题在于:Outlook 2003 之前的版本无法正确检测 unicode 电子邮件。 当将来自 MS Word 的“智能引号”粘贴到富文本区域并以 Unicode 形式保存,然后通过电子邮件发送给 Outlook 用户时,这些字符通常被错误地渲染为“希腊语”。
因此,以下代码片段将一些关键字符替换为 HTML 实体,Outlook XP(以及可能更早的版本)将按预期渲染这些实体。[代码基于此页面和 htmlenties 页面上以前帖子的部分代码]
<?php
$badwordchars=array(
"\xe2\x80\x98", // 左单引号
"\xe2\x80\x99", // 右单引号
"\xe2\x80\x9c", // 左双引号
"\xe2\x80\x9d", // 右双引号
"\xe2\x80\x94", // em 破折号
"\xe2\x80\xa6" // 省略号
);
$fixedwordchars=array(
"‘",
"’",
'“',
'”',
'—',
'…'
);
$html=str_replace($badwordchars,$fixedwordchars,$html);
?>
Squirrelmail 在源代码中包含一个很好的函数,用于将 unicode 转换为实体
<?php
function charset_decode_utf_8 ($string) {
/* 只有在存在 8 位字符时才进行缓慢的转换 */
/* 避免在 ereg 范围内使用 0xA0 (\240)。 RH73 不喜欢这样 */
if (! ereg("[\200-\237]", $string) and ! ereg("[\241-\377]", $string))
return $string;
// 解码三字节 unicode 字符
$string = preg_replace("/([\340-\357])([\200-\277])([\200-\277])/e", \
"'&#'.((ord('\\1')-224)*4096 + (ord('\\2')-128)*64 + (ord('\\3')-128)).';'", \
$string);
// 解码两个字节 unicode 字符
$string = preg_replace("/([\300-\337])([\200-\277])/e", \
"'&#'.((ord('\\1')-192)*64+(ord('\\2')-128)).';'", \
$string);
return $string;
}
?>
再次谈论波兰语字母。如果您使用 fananf 的解决方案,请确保 PHP 文件使用 cp1250 编码,否则它将无法正常工作。这非常明显,但我在最终弄清楚之前花了些时间,所以我认为应该在这里发布一下。
如果您没有安装多字节扩展,这里有一个函数用于解码 UTF-16 编码的字符串。它支持带 BOM 和不带 BOM 的字符串(大端和小端字节序)。
<?php
/**
* 解码 UTF-16 编码的字符串。
*
* 可以处理带 BOM 和不带 BOM 的数据。
* 如果没有 BOM,则假设为大端字节序。
*
* @param string $str 要解码的 UTF-16 编码数据。
* @return string UTF-8 / ISO 编码数据。
* @access public
* @version 0.1 / 2005-01-19
* @author Rasmus Andersson {@link http://rasmusandersson.se/}
* @package Groupies
*/
function utf16_decode( $str ) {
if( strlen($str) < 2 ) return $str;
$bom_be = true;
$c0 = ord($str{0});
$c1 = ord($str{1});
if( $c0 == 0xfe && $c1 == 0xff ) { $str = substr($str,2); }
elseif( $c0 == 0xff && $c1 == 0xfe ) { $str = substr($str,2); $bom_be = false; }
$len = strlen($str);
$newstr = '';
for($i=0;$i<$len;$i+=2) {
if( $bom_be ) { $val = ord($str{$i}) << 4; $val += ord($str{$i+1}); }
else { $val = ord($str{$i+1}) << 4; $val += ord($str{$i}); }
$newstr .= ($val == 0x228) ? "\n" : chr($val);
}
return $newstr;
}
?>
波兰语解码的小升级
function utf82iso88592($text) {
$text = str_replace("\xC4\x85", 'ą', $text);
$text = str_replace("\xC4\x84", 'Ą', $text);
$text = str_replace("\xC4\x87", 'ć', $text);
$text = str_replace("\xC4\x86", 'Ć', $text);
$text = str_replace("\xC4\x99", 'ę', $text);
$text = str_replace("\xC4\x98", 'Ę', $text);
$text = str_replace("\xC5\x82", 'ł', $text);
$text = str_replace("\xC5\x81", 'Ł', $text);
$text = str_replace("\xC3\xB3", 'ó', $text);
$text = str_replace("\xC3\x93", 'Ó', $text);
$text = str_replace("\xC5\x9B", 'ś', $text);
$text = str_replace("\xC5\x9A", 'Ś', $text);
$text = str_replace("\xC5\xBC", 'ż', $text);
$text = str_replace("\xC5\xBB", 'Ż', $text);
$text = str_replace("\xC5\xBA", 'ż', $text);
$text = str_replace("\xC5\xB9", 'Ż', $text);
$text = str_replace("\xc5\x84", 'ń', $text);
$text = str_replace("\xc5\x83", 'Ń', $text);
return $text;
} // utf82iso88592
大家好,
我喜欢使用 COOL(漂亮)的 URI,例如:http://example.com/try-something
我使用 UTF8 作为输入,所以我必须编写一个 UTF8toASCII 函数来获得漂亮的 URI。这是我的想法
<?php
function urlize($url) {
$search = array('/[^a-z0-9]/', '/--+/', '/^-+/', '/-+$/' );
$replace = array( '-', '-', '', '');
return preg_replace($search, $replace, utf2ascii($url));
}
function utf2ascii($string) {
$iso88591 = "\\xE0\\xE1\\xE2\\xE3\\xE4\\xE5\\xE6\\xE7";
$iso88591 .= "\\xE8\\xE9\\xEA\\xEB\\xEC\\xED\\xEE\\xEF";
$iso88591 .= "\\xF0\\xF1\\xF2\\xF3\\xF4\\xF5\\xF6\\xF7";
$iso88591 .= "\\xF8\\xF9\\xFA\\xFB\\xFC\\xFD\\xFE\\xFF";
$ascii = "aaaaaaaceeeeiiiidnooooooouuuuyyy";
return strtr(mb_strtolower(utf8_decode($string), 'ISO-8859-1'),$iso88591,$ascii);
}
echo urlize("Fucking ?m?l");
?>
我希望这对某些人有所帮助。
如果您不确定您的字符串被编码了多少次,可以使用此函数
<?php
function _utf8_decode($string)
{
$tmp = $string;
$count = 0;
while (mb_detect_encoding($tmp)=="UTF-8")
{
$tmp = utf8_decode($tmp);
$count++;
}
for ($i = 0; $i < $count-1 ; $i++)
{
$string = utf8_decode($string);
}
return $string;
}
?>
我不得不解决一个非常有趣的问题
我想用其字母替换文本中的所有 \xXX。不幸的是 XX 是 ASCII 而不是 utf8。我用这种方法解决了我的问题
<?php preg_replace ('/\\\\x([0-9a-fA-F]{2})/e', "pack('H*',utf8_decode('\\1'))",$v); ?>
对不起,我的上一条评论中有一个错误。已更正正则表达式
^([\\x00-\\x7f]|
[\\xc2-\\xdf][\\x80-\\xbf]|
\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|
[\\xe1-\\xec][\\x80-\\xbf]{2}|
\\xed[\\x80-\\x9f][\\x80-\\xbf]|
\\xef[\\x80-\\xbf][\\x80-\\xbd]|
\\xee[\\x80-\\xbf]{2}|
\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|
[\\xf1-\\xf3][\\x80-\\xbf]{3}|
\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})*$
将 uft8-html 标记 ĭ 转换为 uft8
<?
function uft8html2utf8( $s ) {
if ( !function_exists('uft8html2utf8_callback') ) {
function uft8html2utf8_callback($t) {
$dec = $t[1];
if ($dec < 128) {
$utf = chr($dec);
} else if ($dec < 2048) {
$utf = chr(192 + (($dec - ($dec % 64)) / 64));
$utf .= chr(128 + ($dec % 64));
} else {
$utf = chr(224 + (($dec - ($dec % 4096)) / 4096));
$utf .= chr(128 + ((($dec % 4096) - ($dec % 64)) / 64));
$utf .= chr(128 + ($dec % 64));
}
return $utf;
}
}
return preg_replace_callback('|&#([0-9]{1,});|', 'uft8html2utf8_callback', $s );
}
echo uft8html2utf8('test: ĭ');
?>
JF Sebastian 的正则表达式几乎完美,就我而言。我发现了一个错误(它无法通过 http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt 中的第 5.3 节“其他非法代码位置”),我已经更正如下
^([\\x00-\\x7f]|
[\\xc2-\\xdf][\\x80-\\xbf]|
\\xe0[\\xa0-\\xbf][\\x80-\\xbf]|
[\\xe1-\\xec][\\x80-\\xbf]{2}|
\\xed[\\x80-\\x9f][\\x80-\\xbf]|
\\xef[\\x80-\\xbf][\\x80-\\xbc]|
\\xee[\\x80-\\xbf]{2}|
\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2}|
[\\xf1-\\xf3][\\x80-\\xbf]{3}|
\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})*$
(再次,将它们连接到一行以使其生效)