2010-06-27 13 views
28

Szukam (bez powodzenia) skryptu, który działałby jako plik wsadowy i pozwoliłby na zapisanie pliku tekstowego UTF-8 za pomocą LMU, jeśli go nie ma.Dodawanie pliku BOM do UTF-8

Ani język, w którym jest napisany (perl, python, c, bash), ani system operacyjny działa na mnie. Mam dostęp do szerokiej gamy komputerów.

Znalazłem wiele scenariuszy do odwrotnego działania (znoszę BOM), co brzmi dla mnie głupio, ponieważ wiele programów Windows będzie miało problemy z odczytaniem plików tekstowych UTF-8, jeśli nie mają BOM.

Czy tęsknię za oczywistością? Dzięki!

Odpowiedz

4

Uważam, że to całkiem proste. Zakładając, że plik jest zawsze UTF-8 (nie jesteś wykrywanie kodowania, to wiedzieć kodowanie):

Przeczytaj pierwsze trzy znaki. Porównaj je z sekwencją BOM UTF-8 (wikipedia mówi, że jest to 0xEF, 0xBB, 0xBF). Jeśli jest taka sama, wydrukuj je w nowym pliku, a następnie skopiuj wszystkie pozostałe dane z oryginalnego pliku do nowego pliku. Jeśli jest inaczej, najpierw wydrukuj zestawienie komponentów, a następnie wydrukuj trzy znaki i dopiero wtedy wydrukuj wszystko inne, od oryginalnego pliku do nowego pliku.

W C, fopen/fclose/fread/fwrite powinny wystarczyć.

39

Napisałem ten plik addbom.sh za pomocą polecenia "plik" i polecenia "uconv" ICU.

#!/bin/sh 

if [ $# -eq 0 ] 
then 
     echo usage $0 files ... 
     exit 1 
fi 

for file in "[email protected]" 
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 

edit: Dodano cudzysłowie mv argumentów. Dzięki @DirkR i cieszę się, że ten skrypt był bardzo pomocny!

+1

Absolutnie doskonały! O wiele lepiej niż to, z czym przyjechałem. Wielkie dzięki. – Stephane

+2

"$ @" jest tutaj lepsze niż $ *. Spowoduje to zachowanie argumentów ze spacjami (przydatne w oknach + cygwin) – mcoolive

+0

@mcoolive dzięki –

0

Myślałem, że nie będą musieli pisać takie trywialne rzeczą siebie, ale ponieważ ja również potrzebne, aby zrobić kilka konwersji charset, tutaj jest:

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

INPUT_ENCODING = codecs.BOM_UTF16_LE # 'utf_16_le' 
OUTPUT_ENCODING = 'utf-8-sig'   # is there a constant for this?? 

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' 

połączenia go z oryginalnej nazwy pliku tylko , tj:

# utf8bom_add.py myfilename.txt 

A jeśli konwersja UTF-8UTF-8 aby je zmienić INPUT_ENCODING do prawidłowej wartości.

10

(Odpowiedź na podstawie https://stackoverflow.com/a/9815107/1260896 przez yingted)

Aby dodać LM do wszystkich plików, które zaczynają się od „foo-”, można użyć sed. sed ma opcję utworzenia kopii zapasowej.

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

Jeśli wiesz na pewno nie ma już BOM, można uprościć polecenia:

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

Upewnij się, trzeba ustawić UTF-8, bo to znaczy UTF-16 jest inny (inaczej sprawdzić How can I re-add a unicode byte order marker in linux?)

+1

Dla UTF-8 użyj '\ xef \ xbb \ xbf'; dla UTF-16 mało-endianowego użycia '\ xff \ xfe'; dla UTF-16 big-endian użyj '\ xfe \ xff'. Zobacz https://www.w3.org/International/questions/qa-byte-order-mark –

+0

Nie działa to dla mnie na Macu. Wiersz poleceń 'sed -i '1s/^/\ xef \ xbb \ xbf /' temp.csv' dał mi' sed: 1: "temp.csv": niezdefiniowana etykieta 'emp.csv'' –

+0

@PerLundberg mogłeś spróbuj rozwiązać ... spróbuj 'sed '1s/asdfasdfasdf //' blah.csv' Brak -i sprawi, że będzie on bardzo bezpieczny, ponieważ pozostawi plik wejściowy niezmieniony i wyświetli wynik konsoli. Linia ta powinna wyglądać na linii pierwszej, wyszukać ciąg asdfasdfasdf i zastąpić go nic, tj. Usunąć ten ciąg. Następnie spróbuj zrobić '^ adsfasdfasdf''^'oznacza początek linii, być może to powoduje problem z jakiegoś powodu. Być może musisz użyć przełącznika z sed, aby go użyć '^' jak może -E choć nie wiem. – barlop

15

Najprostszym sposobem znalazłem za to

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

znam go używa zewnętrznego programu (CAT) ... ale to będzie wykonać zadanie łatwe w bash

Przetestowane na OSX, ale powinien działać na Linuksie, jak również

pamiętać, że zakłada się, że plik nie jest już LM (!)