Добавление спецификации в файлы UTF-8

Я ищу (но безуспешно) сценарий, который будет работать как командный файл и позволит мне добавить текстовый файл UTF-8 с спецификацией, если у него его нет.

Мне не важен ни язык, на котором он написан (perl, python, c, bash), ни ОС, на которой он работает. У меня есть доступ к широкому кругу компьютеров.

Я нашел много сценариев, которые делают обратное (убирают BOM), что звучит для меня как-то глупо, так как многим программам Windows будет трудно читать текстовые файлы UTF-8, если у них нет BOM.

Я пропустил очевидное?

Спасибо!

11 ответов

Самый простой способ, который я нашел для этого, это

#!/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

Я знаю, что он использует внешнюю программу (кошка)... но он легко сделает работу в Bash

Протестировано на OSX, но должно работать и на Linux

Обратите внимание, что предполагается, что файл еще не имеет спецификации (!)

Я написал этот addbom.sh, используя команду 'file' и команду 'uconv' ICU.

#!/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 и рад, что этот скрипт был таким полезным!

(Ответ основан на /questions/30265032/kak-ya-mogu-povtorno-dobavit-marker-poryadka-bajtov-yunikoda-v-linux/30265044#30265044 от yingted)

Чтобы добавить спецификации ко всем файлам, начинающимся с "foo-", вы можете использовать sed, sed имеет возможность сделать резервную копию.

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

Если вы точно знаете, что спецификации уже нет, вы можете упростить команду:

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

Убедитесь, что вам нужно установить UTF-8, потому что UTF-16 отличается (в противном случае проверьте, как я могу повторно добавить маркер порядка байтов в Юникоде в Linux?)

В качестве улучшения решения Yaron U. вы можете сделать все это в одной строке:

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

cat - немного говорит, чтобы соединить перед source.txt что передается из команды печати. Протестировано на OS X и Ubuntu.

Я нахожу это довольно простым. Предполагая, что файл всегда UTF-8(вы не определяете кодировку, вы знаете кодировку):

Прочитайте первые три символа. Сравните их с последовательностью спецификации UTF-8(в Википедии сказано, что это 0xEF,0xBB,0xBF). Если это то же самое, распечатайте их в новом файле, а затем скопируйте все остальное из исходного файла в новый файл. Если он отличается, сначала распечатайте спецификацию, затем напечатайте три символа и только затем напечатайте все остальное от исходного файла до нового файла.

В C достаточно fopen/fclose/fread/fwrite.

открыть в блокноте. нажмите «Сохранить как». в кодировке выберите «UTF-8 (BOM)» (это под обычным «UTF-8»).

В доступе 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

Я создал скрипт на основе кода Steven R. Loomis. https://github.com/Vdragon/addUTF-8bomb

Изучите https://github.com/Vdragon/C_CPP_project_template/blob/development/Tools/convertSourceCodeToUTF-8withBOM.bash.sh пример использования этого сценария.

Вот пакетный файл, который я использую для этой цели в Windows. Он должен быть сохранен в кодировке ANSI (Windows-1252) для/p=часть.

      @echo off
if [%~1]==[] goto usage
if not exist "%~1" goto notfound

setlocal
set /p AREYOUSURE="Adding UTF-8 BOM to '%~1'. Are you sure (Y/[N])? "
if /i "%AREYOUSURE%" neq "Y" goto canceled

:: Main code is here. Create a temp file containing the BOM, then append the requested file contents, and finally overwrite the original file
(echo|set /p=)>"%~1.temp"
type "%~1">>"%~1.temp"
move /y "%~1.temp" "%~1" >nul

@echo Added UTF-8 BOM to "%~1"
pause
exit /b 0

:usage
@echo Usage: %0 ^<FILE_NAME^>
goto end

:notfound
@echo File not found: "%~1"
goto end

:canceled
@echo Operation canceled.
goto end

:end
pause
exit /b 1

Вы можете сохранить файл, например, какC:\addbom.batи используйте следующие.regфайл, чтобы добавить его в контекстное меню всех файлов, вызываемое правой кнопкой мыши:

      Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\Shell\Add UTF-8 BOM]

[HKEY_CLASSES_ROOT\*\Shell\Add UTF-8 BOM\command]
@="C:\\addbom.bat \"%1\""

Я думал, что мне не нужно будет писать такие тривиальные вещи самому, но, поскольку мне также нужно было выполнить некоторое преобразование кодировки, вот оно:

#!/usr/bin/python
import os
import sys
import codecs

INPUT_ENCODING = 'utf-8'       # utf-8 without BOM
OUTPUT_ENCODING = 'utf-8-sig'  # utf-8 with BOM

if len(sys.argv) == 1:
    print 'Usage:\n\t%s <filename.txt>' % sys.argv[0]
    sys.exit(-1)

output_file = os.path.splitext(os.path.split(sys.argv[1])[-1])[0]
fin = codecs.open(sys.argv[1], 'rb', encoding=INPUT_ENCODING)
fout = codecs.open(output_file + '_utf8bom.txt', 'wb', encoding=OUTPUT_ENCODING)
fout.write(fin.read())
fin.close()
fout.close()

print 'done'

Назовите его только с оригинальным именем файла, то есть:

# utf8bom_add.py myfilename.txt

И если вы конвертируете из BOM-менее UTF-8 затем установите INPUT_ENCODING на соответствующее значение.

Если вам это нужно, вы также можете проверить, существует ли спецификация, чтобы не добавлять ее дважды.

Это однострочное решение, которое работает без каких-либо временных файлов:

МакОС:

      sed -i '' '1s/^/\xEF\xBB\xBF/' filename.txt

Другие системы Unix:

      sed -i '1s/^/\xEF\xBB\xBF/' filename.txt

Есть странность в том, как MacOS использует-iфункция внутри своей реализацииsedв том, что ему нужно предоставить имя файла резервной копии, но вы можете обойти это с помощью''параметр выше.

Примечание. В этом помог ChatGPT 4.

Другие вопросы по тегам