如何删除多个 UTF-8 BOM 序列
Posted
技术标签:
【中文标题】如何删除多个 UTF-8 BOM 序列【英文标题】:How to remove multiple UTF-8 BOM sequences 【发布时间】:2012-05-04 16:08:58 【问题描述】:使用 php5 (cgi) 从文件系统输出模板文件并在输出原始 html 时遇到问题。
private function fetch($name)
$path = $this->j->config['template_path'] . $name . '.html';
if (!file_exists($path))
dbgerror('Could not find the template "' . $name . '" in ' . $path);
$f = fopen($path, 'r');
$t = fread($f, filesize($path));
fclose($f);
if (substr($t, 0, 3) == b'\xef\xbb\xbf')
$t = substr($t, 3);
return $t;
即使我添加了 BOM 修复程序,Firefox 接受它时仍然存在问题。您可以在此处查看实时副本:http://ircb.in/jisti/(以及我在http://ircb.in/jisti/home.html 发送的模板文件,如果您想查看)
知道如何解决这个问题吗? o_o
【问题讨论】:
utf8 文件不应该有 BOM,如果你的编辑器把它们放进去,应该有一个配置来省略那些,如果你的编辑器不允许你不放 BOM,更换你的编辑器. 是的。我用n++,我试过没有BOM 【参考方案1】:您将使用以下代码删除 utf8 bom
//Remove UTF8 Bom
function remove_utf8_bom($text)
$bom = pack('H*','EFBBBF');
$text = preg_replace("/^$bom/", '', $text);
return $text;
【讨论】:
由于某种原因在 Google+ API 中,这个 BOM 显示在内容变量的末尾,所以我需要调整它以将其从字符串的末尾删除。 有人能解释一下这里是如何使用pack函数的吗?我知道它将字符串转换为二进制表示,但很难理解这如何有助于识别 BOM Unicode 字符。 这非常适合我从 s-s-rS 读取 CSV 输出并附加到更大文件的要求。 终于有一个真正有效的 BOM 转义技术了,谢谢! @fsociety BOM 是三个字节 -0xef 0xbb 0xbf
。所以 pack 正在使用 H* 格式,这意味着将字符串中的所有值解释为十六进制字节。我更喜欢 o1max 的答案(虽然分数较低),它只使用带有转义字符的字符串:"\xEF\xBB\xBF"
【参考方案2】:
试试:
// -------- read the file-content ----
$str = file_get_contents($source_file);
// -------- remove the utf-8 BOM ----
$str = str_replace("\xEF\xBB\xBF",'',$str);
// -------- get the Object from JSON ----
$obj = json_decode($str);
:)
【讨论】:
【参考方案3】:另一种删除BOM的方法,即Unicode代码点U+FEFF
$str = preg_replace('/\xFEFF/u', '', $file);
【讨论】:
【参考方案4】:b'\xef\xbb\xbf'
代表文字字符串“\xef\xbb\xbf”。如果要检查BOM,则需要使用双引号,因此\x
序列实际上被解释为字节:
"\xef\xbb\xbf"
您的文件似乎还包含比单个前导 BOM 更多的垃圾:
$ curl http://ircb.in/jisti/ | xxd
0000000: efbb bfef bbbf efbb bfef bbbf efbb bfef ................
0000010: bbbf efbb bf3c 2144 4f43 5459 5045 2068 .....<!DOCTYPE h
0000020: 746d 6c3e 0a3c 6874 6d6c 3e0a 3c68 6561 tml>.<html>.<hea
...
【讨论】:
如果我使用的是 n++,为什么会导致这种情况?它保存为 unix/utf8 -bom 将其保存为 UTF-8 NO BOM(或 N++ 中的任何名称)。 我做到了,但我仍然得到相同的结果。我卷曲了直接文件(卷曲ircb.in/jisti/home.html | xxd)并且没有前导字符,但是卷曲PHP脚本在前面添加了多余的数据,而我使用的只是打印输出数据。跨度> 【参考方案5】:此全局函数解析为 UTF-8 系统基本字符集。坦克!
function prepareCharset($str)
// set default encode
mb_internal_encoding('UTF-8');
// pre filter
if (empty($str))
return $str;
// get charset
$charset = mb_detect_encoding($str, array('ISO-8859-1', 'UTF-8', 'ASCII'));
if (stristr($charset, 'utf') || stristr($charset, 'iso'))
$str = iconv('ISO-8859-1', 'UTF-8//TRANSLIT', utf8_decode($str));
else
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
// remove BOM
$str = urldecode(str_replace("%C2%81", '', urlencode($str)));
// prepare string
return $str;
【讨论】:
【参考方案6】:如果有人使用 csv 导入,那么下面的代码很有用
$header = fgetcsv($handle);
foreach($header as $key=> $val)
$bom = pack('H*','EFBBBF');
$val = preg_replace("/^$bom/", '', $val);
$header[$key] = $val;
【讨论】:
【参考方案7】:没有pack
函数的解决方案:
$a = "1";
var_dump($a); // string(4) "1"
function deleteBom($text)
return preg_replace("/^\xEF\xBB\xBF/", '', $text);
var_dump(deleteBom($a)); // string(1) "1"
【讨论】:
如果它们可以多次出现,您可能需要使用"/^(\xEF\xBB\xBF)+/"【参考方案8】:做同样工作的额外方法:
function remove_utf8_bom_head($text)
if(substr(bin2hex($text), 0, 6) === 'efbbbf')
$text = substr($text, 3);
return $text;
我发现的其他方法不适用于我的情况。
希望它在某些特殊情况下有所帮助。
【讨论】:
【参考方案9】:如果您正在使用file_get_contents
读取某些API,并从json_decode
得到一个莫名其妙的NULL
,请检查json_last_error()
的值:有时从file_get_contents
返回的值会有一个几乎不可见的无关BOM当您检查字符串时,但会使json_last_error()
返回JSON_ERROR_SYNTAX
(4)。
>>> $json = file_get_contents("http://api-guiaserv.seade.gov.br/v1/orgao/all");
=> "\t"orgao":["Nome":"Tribunal de Justi\u00e7a","ID_Orgao":"59","Condicao":"1", ...]"
>>> json_decode($json);
=> null
>>>
在这种情况下,检查前 3 个字节 - 回显它们不是很有用,因为 BOM 在大多数设置中是不可见的:
>>> substr($json, 0, 3)
=> " "
>>> substr($json, 0, 3) == pack('H*','EFBBBF');
=> true
>>>
如果上面的行为您返回 TRUE,那么一个简单的测试可能会解决问题:
>>> json_decode($json[0] == "" ? $json : substr($json, 3))
=> #204
+"orgao": [
#203
+"Nome": "Tribunal de Justiça",
+"ID_Orgao": "59",
+"Condicao": "1",
,
],
...
【讨论】:
【参考方案10】:我不太喜欢在简单的任务中使用preg_replace
或preg_match
。这种检测和删除 BOM 的替代方法怎么样?
function remove_utf8_bom(string $text): string
$bomStart = mb_substr($text, 0, 1);
return ($bomStart == pack('H*','EFBBBF')) ?
mb_substr($text, 1) :
$text;
【讨论】:
【参考方案11】:当使用有缺陷的软件时,BOM 部分会随着每次节省而成倍增加。
所以我用这个来摆脱它。
function remove_utf8_bom($text)
$bom = pack('H*','EFBBBF');
while (preg_match("/^$bom/", $text))
$text = preg_replace("/^$bom/", '', $text);
return $text;
【讨论】:
以上是关于如何删除多个 UTF-8 BOM 序列的主要内容,如果未能解决你的问题,请参考以下文章
求个给UTF-8文件批量去UTF-8 BOM头的批处理,去掉BOM后覆盖原来的文件,最好我可以自己添加多个文件名称!