【发布时间】:2011-12-03 17:39:11
【问题描述】:
我刚开始涉足 php,恐怕我需要一些帮助来弄清楚如何操作 utf-8 字符串。
我正在使用 ubuntu 11.10 x86,php 版本 5.3.6-13ubuntu3.2。我有一个 utf-8 编码文件(vim :set encoding 确认了这一点),然后我继续阅读它使用
$file = fopen("file.txt", "r");
while(!feof($file)){
$line = fgets($file);
//...
}
fclose($file);
- 使用
mb_detect_encoding($line)报告UTF-8 - 如果我这样做
echo $line我可以在浏览器中正确地看到该行(没有损坏的字符)- 所以我想浏览器和 apache 一切正常。虽然我确实在我的 apache 配置中搜索了 AddDefaultCharset 并尝试为字符编码添加 http 元标记(以防万一)
当我尝试使用 $arr = mb_split(';',$line) 拆分字符串时,结果数组的字段包含损坏的 utf-8 字符(mb_detect_encoding($arr[0]) 也报告 utf-8)。
所以echo $arr[0] 会产生类似这样的结果:ΑΘΗÎÎ。
我尝试设置mb_detect_order('utf-8')、mb_internal_encoding('utf-8'),但没有任何改变。我还尝试使用 this w3 perl regex 手动检测 utf-8,因为我在某处读到 mb_detect_encoding 有时会失败(神话?),但结果也是一样的。
所以我的问题是如何正确拆分字符串?沿着mb_ 路径走错了吗?我错过了什么?
感谢您的帮助!
更新:我正在添加示例字符串和 base64 等效项(感谢 @chris' 的建议)
1. original string: "ΑΘΗΝΑ;ΑΙΓΑΛΕΩ;12242;37.99452;23.6889"
2. base64 encoded: "zpHOmM6Xzp3OkTvOkc6ZzpPOkc6bzpXOqTsxMjI0MjszNy45OTQ1MjsyMy42ODg5"
3. first part (the equivalent of "ΑΘΗΝΑ") base64 encoded before splitting: "zpHOmM6Xzp3OkQ=="
4. first part ($arr[0] after splitting): "ΑΘΗÎΑ"
5. first part after splitting base64 encoded: "77u/zpHOmM6Xzp3OkQ=="
好的,所以在这样做之后,3. 和 5. 之间似乎存在 77u/ 差异,其中 according to this 是一个 utf-8 BOM 标记。那么如何避免呢?
更新 2:我今天醒来时神清气爽,考虑到您的提示,我再次尝试了。似乎$line=fgets($file) 正确读取了第一行(没有损坏的字符),并且对于后续的每一行都失败了。那么我base64_encoded 第一行和第二行,77u/ bom 出现在 base64'd 字符串第一行上。然后我在 vim 中打开了有问题的文件,并输入 :set nobomb :w 以保存没有 bom 的文件。再次启动 php 表明第一行现在也被破坏了。基于@hakre 的remove_utf8_bom 我添加了它的补充功能
function add_utf8_bom($str){
$bom= "\xEF\xBB\xBF";
return substr($str,0,3)===$bom?$str:$bom.$str;
}
并且瞧现在每一行都被正确读取了。
我不太喜欢这个解决方案,因为它看起来非常老套(我不敢相信整个框架/语言都没有提供一种处理无炸弹字符串的方法)。那么你知道另一种方法吗?否则我会继续上面的。
感谢@chris、@hakre 和@jacob 的宝贵时间!
更新 3(解决方案):毕竟这是浏览器的问题:添加 header('Content-type: text/html; charset=UTF-8') 和像 <meta http-equiv="Content-type" value="text/html; charset=UTF-8" /> 这样的元标记是不够的。它还必须正确地包含在 <html><body> 部分中,否则浏览器将无法正确理解编码。感谢@jake 的建议。
故事的士气:在尝试为浏览器编写代码之前,我应该先了解更多关于 html 的知识。感谢大家的帮助和耐心。
【问题讨论】:
-
我建议您发布示例字符串(拆分前后)供人们检查。为了保护它们的二进制安全,base64_encode() 它们,否则细节将不会通过网络浏览器和 stackoverflow 等保存......
-
@chris +1 看来使用 base64 你可能会有所收获
-
这里有些奇怪。我总是在 PHP 中使用没有 BOM 的 UTF8 字符串,它可以正常工作。你如何输出变量?你只是做
echo $line吗?您是否输出整个网页,即带有文档类型、标题等?还是你在命令行上使用 PHP? -
@jakob 我在使用 apache2 的独立网站(即没有加载 wordpress 环境等)中使用 test.php 文件,然后我使用 Firefox 浏览该文件。我只是像你说的那样 echo $line ,然后我逐渐尝试使用元标记和 header() 以及诸如此类的东西来声明 utf-8 编码,希望它是这样的,但什么都没有。我不争辩说问题出在我所做的某处,我只是不知道它是什么!
-
@bottlenecked: 我不知道你是否已经这样做了,但是尝试在你的 test.php 文件中输出有效的 HTML,即在你写
echo $line之前,写一些类似echo '<!DOCTYPE html><html><head><meta charset=utf-8><title>Test Page</title></head><body>';的东西.
标签: php utf-8 multibyte mbstring