2010-06-27 33 views
28

Estoy buscando (sin éxito) una secuencia de comandos, que funcionaría como un archivo por lotes y me permite anteponer un archivo de texto UTF-8 con una lista de materiales si no tiene uno.Agregar BOM a archivos UTF-8

Ni el lenguaje en el que está escrito (perl, python, c, bash) ni el sistema operativo en el que trabaja me importa. Tengo acceso a una amplia gama de computadoras.

He encontrado una gran cantidad de secuencias de comandos para hacer lo contrario (pelar la lista de materiales), que me suena como una tontería, ya que muchos programas de Windows tendrán problemas para leer archivos de texto UTF-8 si no tienen una lista de materiales.

¿Echo de menos lo obvio? Gracias!

Respuesta

4

Me parece bastante simple. Suponiendo que el archivo es siempre UTF-8 (que no está detectando la codificación, que saben la codificación):

Leer los tres primeros caracteres. Compárelos con la secuencia de BOM UTF-8 (wikipedia dice que es 0xEF, 0xBB, 0xBF). Si es lo mismo, imprimirlos en el nuevo archivo y luego copiar todo lo demás desde el archivo original al nuevo. Si es diferente, primero imprima la lista de materiales, luego imprima los tres caracteres y solo luego imprima todo lo demás desde el archivo original al nuevo.

En C, fopen/fclose/fread/fwrite debería ser suficiente.

39

Escribí este addbom.sh usando el comando 'file' y el comando 'ICU' 'uconv'.

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

edición: cotizaciones Añadido alrededor de los argumentos mv. Gracias @DirkR y me alegro de que este script haya sido tan útil.

+1

¡Absolutamente perfecto! Mucho mejor de lo que vine. Muchas gracias. – Stephane

+2

"$ @" es mejor que $ * aquí. Esto mantendrá argumentos con espacios (útil en Windows + cygwin) – mcoolive

+0

@mcoolive gracias –

0

pensé que no voy a tener que escribir una cosa tan trivial a mí mismo, pero como yo también tenía que hacer alguna conversión juego de caracteres, aquí está:

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

de llamadas con el nombre del archivo original solamente , es decir:

# utf8bom_add.py myfilename.txt 

Y si va a convertir a UTF-8UTF-8 a cambiar la INPUT_ENCODING al valor correcto.

10

(respuesta basada en https://stackoverflow.com/a/9815107/1260896 por yingted)

Para añadir a las listas de materiales de todos los archivos que comienzan con "foo", puede utilizar sed. sed tiene una opción para hacer una copia de seguridad.

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

Si sabe que no hay lista de materiales ya, puede simplificar el comando:

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

Asegúrese de que es necesario establecer UTF-8, porque esto es UTF-16 es diferente (de lo contrario comprobar How can I re-add a unicode byte order marker in linux?)

+1

Para UTF-8 use '\ xef \ xbb \ xbf'; para UTF-16 little-endian use '\ xff \ xfe'; para UTF-16 big-endian use '\ xfe \ xff'. Consulte https://www.w3.org/International/questions/qa-byte-order-mark –

+0

Esto no funcionó para mí en Mac. La línea de comando 'sed -i '1s/^/\ xef \ xbb \ xbf /' temp.csv' me dio' sed: 1: "temp.csv": etiqueta indefinida 'emp.csv'' –

+0

@PerLundberg podrías intente solucionarlo .. intente 'sed '1s/asdfasdfasdf //' blah.csv' La falta de -i lo hará muy seguro porque deja el archivo de entrada sin cambios y envía el resultado a la consola. Esa línea debe mirar la línea uno, busque la cadena asdfasdfasdf y reemplácela con nada, es decir, elimine esa cadena. Luego intente hacerlo '^ adsfasdfasdf' El'^'marca el comienzo de la línea, tal vez eso está causando el problema por alguna razón. Quizás necesites usar un interruptor con sed para que use el '^' como quizás -E aunque no lo sé. – barlop

15

La forma más sencilla que encontré para esto es

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

sé que utiliza un programa externo (cat) ... pero va a hacer el trabajo fácilmente en bash

Probado en OSX, pero debería funcionar en Linux, así

NOTA que asume que el archivo no tiene ya lista de materiales (!)