重要提示:當轉換包含歐元符號的 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
編碼,而且網頁瀏覽器會將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)
如果您執行 Gentoo Linux 並遇到某些 PHP4 應用程式出現問題,顯示
呼叫未定義的函式:utf8_decode()
請嘗試重新編譯 PHP4 並啟用 'expat' 旗標。
請注意,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()。
如果您想從資料庫中檢索一些 UTF-8 資料,則不需要 utf8_decode()。
只需在任何 SELECT 之前執行以下查詢
$result = mysql_query("SET NAMES utf8");
更新 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 編碼儲存。
除了 yannikh at 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=Москва,
除了 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));
// 此輸出正確的字串,就像第一行一樣。
?>
我發現檢查某個東西是否為有效的 UTF-8 的最快方法是
<?php
if (iconv('UTF-8', 'UTF-8', $input) != $input) {
/* 它不是 UTF-8--對我來說,它可能是 CP1252,Windows
的 Latin 1 版本,帶有引號和
歐元符號。 */
}
?>.
如果 iconv() C 程式庫被告知某個字串是 UTF-8 而實際上不是,則會失敗;PHP 的則不會,它只會傳回轉換到失敗點的結果,因此您必須比較結果與輸入才能判斷轉換是否成功。
最後一個註解中的正規表示式有一些錯字。這是一個
語法上有效的表示式,但不知道它是否正確。
您必須將表示式連接成一個長行。
^(
[\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}
)*$
在陣列上使用此函式的首選方式是使用內建的 PHP 函式「array_map()」,例如
$array = array_map("utf8_decode", $array);
針對 fhoech (2005 年 9 月 22 日 11:55) 的回覆,我剛剛使用您的正規表示式、'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');
$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;
}
對我來說,使用 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 程式碼。
嘿!錯誤不在函式 '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.dev.org.tw/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 轉換為我在 LATIN2 MySQL 資料庫中使用的 ISO-8859-2。
<?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,2 位元組 unicode 的 110 前綴
$ret .= substr($str, $last, $i-$last); // 附加所有我們跳過的正規字元
$c1 &= 31; // 移除 3 位元 2 位元組前綴
$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,3 位元組 unicode 的 110 前綴
$ret .= substr($str, $last, $i-$last); // 附加所有我們跳過的正規字元
$c2 = ord($str{++$i}); // 下一個位元組
$c3 = ord($str{++$i}); // 第三個位元組
$c1 &= 15; // 移除 4 位元 3 位元組前綴
$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 使用者)的生活無縫接軌。問題是:2003 年之前的 Outlook (?) 無法正確偵測 Unicode 電子郵件。當從 MS Word 貼上「智慧引號」到 RTF 區域並以 Unicode 儲存,然後以電子郵件發送給 Outlook 使用者時,這些字元往往會錯誤地呈現為「希臘文」。
因此,以下程式碼片段會將一些策略性字元取代為 Outlook XP(可能更早版本)會如預期呈現的 HTML 實體。[程式碼基於此頁面和 htmlenties 上的先前文章中的程式碼片段]
<?php
$badwordchars=array(
"\xe2\x80\x98", // 左單引號
"\xe2\x80\x99", // 右單引號
"\xe2\x80\x9c", // 左雙引號
"\xe2\x80\x9d", // 右雙引號
"\xe2\x80\x94", // em dash
"\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;
// 解碼 3 位元組 unicode 字元
$string = preg_replace("/([\340-\357])([\200-\277])([\200-\277])/e", \
"'&#'.((ord('\\1')-224)*4096 + (ord('\\2')-128)*64 + (ord('\\3')-128)).';'", \
$string);
// 解碼 2 位元組 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: ĭ');
?>