Добавление спецификации в файлы 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.