【问题标题】:Adding BOM to UTF-8 files将 BOM 添加到 UTF-8 文件
【发布时间】:2011-03-08 19:58:51
【问题描述】:

我正在搜索(没有成功)一个脚本,它可以作为批处理文件使用,如果没有 BOM,我可以在 UTF-8 文本文件前面添加一个 BOM。

它所用的语言(perl、python、c、bash)和它所运行的操作系统对我来说都不重要。我可以使用各种计算机。

我发现很多脚本可以做相反的事情(剥离 BOM),这听起来有点傻,因为许多 Windows 程序如果没有物料清单。

我错过了显而易见的事情吗?

谢谢!

【问题讨论】:

    标签: utf-8 batch-file scripting byte-order-mark


    【解决方案1】:

    我使用 'file' 命令和 ICU 的 'uconv' 命令编写了这个 addbom.sh。

    #!/bin/sh
    
    if [ $# -eq 0 ]
    then
            echo usage $0 files ...
            exit 1
    fi
    
    for file in "$@"
    do
            echo "# Processing: $file" 1>&2
            if [ ! -f "$file" ]
            then
                    echo Not a file: "$file" 1>&2
                    exit 1
            fi
            TYPE=`file - < "$file" | cut -d: -f2`
            if echo "$TYPE" | grep -q '(with BOM)'
            then
                    echo "# $file already has BOM, skipping." 1>&2
            else
                    ( mv "${file}" "${file}"~ && uconv -f utf-8 -t utf-8 --add-signature < "${file}~" > "${file}" ) || ( echo Error processing "$file" 1>&2 ; exit 1)
            fi
    done
    

    编辑:mv 参数周围添加了引号。感谢@DirkR,很高兴这个脚本很有帮助!

    【讨论】:

    • 绝对完美!比我自带的好多了。非常感谢。
    • "$@" 比 $* 这里好。这将保留带空格的参数(在 windows+cygwin 上很有用)
    • mv 也需要 "" 否则它不适用于带有空格的路径名。不错的脚本,谢谢!
    • 出现了一个问题,关于如何在子目录上使用它……你可以这样使用它:find . -type f -print0 | xargs -0 addbom.sh 它将为所有子目录调用 addbom.sh 脚本。
    【解决方案2】:

    我找到的最简单的方法是

    #!/usr/bin/env bash
    
    #Add BOM to the new file
    printf '\xEF\xBB\xBF' > with_bom.txt
    
    # Append the content of the source file to the new file
    cat source_file.txt >> with_bom.txt
    

    我知道它使用外部程序 (cat)...但它会在 bash 中轻松完成这项工作

    在 osx 上测试过,但也可以在 linux 上运行

    请注意,它假定文件还没有 BOM (!)

    【讨论】:

      【解决方案3】:

      (根据 yingtedhttps://stackoverflow.com/a/9815107/1260896 回答)

      要向所有以“foo-”开头的文件添加 BOM,您可以使用sedsed 可以选择进行备份。

      sed -i '1s/^\(\xef\xbb\xbf\)\?/\xef\xbb\xbf/' foo-*
      

      如果您确定已经没有 BOM,您可以简化命令:

      sed -i '1s/^/\xef\xbb\xbf/' foo-*
      

      确保您需要设置 UTF-8,因为即 UTF-16 不同(否则检查 How can I re-add a unicode byte order marker in linux?

      【讨论】:

      • 对于 UTF-8 使用 \xef\xbb\xbf;对于 UTF-16 little-endian 使用 \xff\xfe;对于 UTF-16 大端使用 \xfe\xff。见w3.org/International/questions/qa-byte-order-mark
      • 这对我在 Mac 上不起作用。命令行sed -i '1s/^/\xef\xbb\xbf/' temp.csv给了我sed: 1: "temp.csv": undefined label 'emp.csv'
      • @PerLundberg 您可以尝试进行故障排除.. 尝试sed '1s/asdfasdfasdf//' blah.csv 缺少 -i 将使其非常安全,因为它使输入文件保持不变并将结果输出到控制台。该行应查看第一行,搜索字符串 asdfasdfasdf 并将其替换为空,即删除该字符串。然后尝试将其设置为^adsfasdfasdf ^ 标记行的开头,也许这由于某种原因导致了问题。也许你需要使用带有 sed 的开关来让它使用 ^ 就像也许 -E 虽然我不知道。
      • @PerlLundberg 我在 macOS 10.13 上遇到了同样的问题,经过大量的摆弄,我发现 sed -i '' $'1s/^/\xef\xbb\xbf/' foo-* 有效
      【解决方案4】:

      作为对 Yaron U. 解决方案的改进,您可以在一行中完成所有操作:

      printf '\xEF\xBB\xBF' | cat - source.txt > source-with-bom.txt
      

      cat - 位表示连接到 source.txt 的前面,从打印命令中输入的内容。在 OS X 和 Ubuntu 上测试。

      【讨论】:

        【解决方案5】:

        我觉得很简单。假设文件总是 UTF-8(你没有检测到编码,你知道编码):

        阅读前三个字符。将它们与 UTF-8 BOM 序列进行比较(维基百科说它是 0xEF、0xBB、0xBF)。 如果相同,请将它们打印到新文件中,然后将其他所有内容从原始文件复制到新文件中。 如果不同,请先打印 BOM,然后打印三个字符,然后再打印从原始文件到新文件的所有其他内容。

        在 C 语言中,fopen/fclose/fread/fwrite 应该足够了。

        【讨论】:

          【解决方案6】:
          【解决方案7】:

          在 VBA 访问中:

              Dim name As String
              Dim tmpName As String
              
              tmpName = "tmp1.txt"
              name = "final.txt"
          
              Dim file As Object
              Dim finalFile As Object
              Set file = CreateObject("Scripting.FileSystemObject")
          
              Set finalFile = file.CreateTextFile(name)
           
              
              'Add BOM
              finalFile.Write Chr(239)
              finalFile.Write Chr(187)
              finalFile.Write Chr(191)
              
              'transfer text from tmp to final file:
              Dim tmpFile As Object
              Set tmpFile = file.OpenTextFile(tmpName, 1)
              finalFile.Write tmpFile.ReadAll
              finalFile.Close
              tmpFile.Close
              file.DeleteFile tmpName
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-26
            • 1970-01-01
            • 1970-01-01
            • 2011-02-04
            • 2011-05-22
            相关资源
            最近更新 更多