如何删除多个 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_replacepreg_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后覆盖原来的文件,最好我可以自己添加多个文件名称!

unix环境下shell脚本如何往文本文件的头部加入utf8 bom头EEBBBF?如何删除bom

使用 Perl 从字符串中删除 BOM

如何检查多个文件夹并删除具有唯一文件名的任何文件?

oracle 如何删除新生成的序列号

Delphi - TStringList保存的文件如何避免保持为UTF-8 BOM格式?