UTF-8 HTML y CSS archivos con la lista de materiales (y de cómo eliminar de la lista de materiales con Python)

StackOverflow https://stackoverflow.com/questions/2456380

Pregunta

En primer lugar, algunos antecedentes:Estoy desarrollando una aplicación web usando Python.Todos mis archivos (de texto) son almacenados actualmente en UTF-8 con la lista de materiales.Esto incluye todas mis plantillas HTML y los archivos CSS.Estos recursos se almacenan como datos binarios (BOM y todo) en mi DB.

Cuando puedo recuperar las plantillas de la DB, me descifrar utilizando template.decode('utf-8').Cuando el HTML llega en el navegador, la lista de materiales está presente en el comienzo de la respuesta HTTP del cuerpo.Esto genera una muy interesante de error en Chrome:

Extra <html> encountered. Migrating attributes back to the original <html> element and ignoring the tag.

Chrome parece generar un <html> etiqueta automáticamente cuando se ve la lista de materiales y los errores de contenido, haciendo que el real <html> la etiqueta de un error.

Así, utilizando Python, ¿cuál es la mejor manera de quitar de la lista de materiales desde mi codificado en UTF-8 plantillas (si es que existe, no puede garantizar esto en el futuro)?

Para otros archivos basados en texto como CSS, serán los principales navegadores interpretan correctamente (o ignorar) la lista de materiales?Se envían en formato de datos binarios sin .decode('utf-8').

Nota:Estoy usando Python 2.5.

Gracias!

¿Fue útil?

Solución

Desde que el estado:

Todos mis archivos (de texto) son en la actualidad almacenado en UTF-8 con la lista de materiales

a continuación, utilice el 'utf-8-sig' códec para decodificar ellos:

>>> s = u'Hello, world!'.encode('utf-8-sig')
>>> s
'\xef\xbb\xbfHello, world!'
>>> s.decode('utf-8-sig')
u'Hello, world!'

Se elimina automáticamente de la esperada lista de materiales, y funciona correctamente si la lista de materiales no está presente.

Otros consejos

Compruebe el primer carácter después de la decodificación a ver si es la lista de materiales:

if u.startswith(u'\ufeff'):
  u = u[1:]

Previamente aceptada por la respuesta es ERRÓNEA.

u'\ufffe' no es un personaje.Si usted lo consigue en una cadena unicode alguien ha rellenado hasta poderosamente.

La lista de materiales (aka ANCHO CERO NO-BREAK ESPACIO) u'\ufeff'

>>> UNICODE_BOM = u'\N{ZERO WIDTH NO-BREAK SPACE}'
>>> UNICODE_BOM
u'\ufeff'
>>>

Leer este (Ctrl-F de búsqueda para BOM) y este y este (Ctrl-F de búsqueda para BOM).

Aquí es correcto y error tipográfico/braino resistente a la respuesta:

Decodificar su entrada en unicode_str.Luego de hacer esto:

# If I mistype the following, it's very likely to cause a SyntaxError.
UNICODE_BOM = u'\N{ZERO WIDTH NO-BREAK SPACE}'
if unicode_str and unicode_str[0] == UNICODE_BOM:
    unicode_str = unicode_str[1:]

Bono:el uso de una constante con nombre da a sus lectores un poco más de una pista de lo que está pasando, que hace una recopilación de la aparentemente arbitraria hexoglyphics.

Actualización Por desgracia, no parece adecuado denomina constante en el estándar de la biblioteca de Python.

Por desgracia, los códecs módulo proporciona sólo "una trampa y un engaño":

>>> import pprint, codecs
>>> pprint.pprint([(k, getattr(codecs, k)) for k in dir(codecs) if k.startswith('BOM')])
[('BOM', '\xff\xfe'),   #### aarrgghh!! ####
 ('BOM32_BE', '\xfe\xff'),
 ('BOM32_LE', '\xff\xfe'),
 ('BOM64_BE', '\x00\x00\xfe\xff'),
 ('BOM64_LE', '\xff\xfe\x00\x00'),
 ('BOM_BE', '\xfe\xff'),
 ('BOM_LE', '\xff\xfe'),
 ('BOM_UTF16', '\xff\xfe'),
 ('BOM_UTF16_BE', '\xfe\xff'),
 ('BOM_UTF16_LE', '\xff\xfe'),
 ('BOM_UTF32', '\xff\xfe\x00\x00'),
 ('BOM_UTF32_BE', '\x00\x00\xfe\xff'),
 ('BOM_UTF32_LE', '\xff\xfe\x00\x00'),
 ('BOM_UTF8', '\xef\xbb\xbf')]
>>>

Actualización 2 Si usted no ha decodificado su entrada, y el deseo de verificación para una lista de materiales que usted necesita para comprobar DOS diferentes Listas de materiales para UTF-16 y al menos DOS diferentes Listas de materiales para UTF-32.Si sólo había una manera de cada uno, entonces no necesita una lista de materiales, usted?

Aquí textualmente unprettified de mi propio código es mi solución a este:

def check_for_bom(s):
    bom_info = (
        ('\xFF\xFE\x00\x00', 4, 'UTF-32LE'),
        ('\x00\x00\xFE\xFF', 4, 'UTF-32BE'),
        ('\xEF\xBB\xBF',     3, 'UTF-8'),
        ('\xFF\xFE',         2, 'UTF-16LE'),
        ('\xFE\xFF',         2, 'UTF-16BE'),
        )
    for sig, siglen, enc in bom_info:
        if s.startswith(sig):
            return enc, siglen
    return None, 0

La entrada s debe ser de al menos los 4 primeros bytes de la entrada.Devuelve el tipo de codificación que puede ser utilizado para decodificar el post-BOM parte de su entrada, además de la longitud de la lista de materiales (si los hubiere).

Si usted es paranoico, podría permitir a los otros 2 (no estándar) UTF-32 órdenes, pero Python no suministro de un sistema de codificación para ellos y nunca he oído hablar de una incidencia real, así que no te molestes.

Puede utilizar algo similar para eliminar lista de materiales:

import os, codecs
def remove_bom_from_file(filename, newfilename):
    if os.path.isfile(filename):
        # open file
        f = open(filename,'rb')

        # read first 4 bytes
        header = f.read(4)

        # check if we have BOM...
        bom_len = 0
        encodings = [ ( codecs.BOM_UTF32, 4 ),
            ( codecs.BOM_UTF16, 2 ),
            ( codecs.BOM_UTF8, 3 ) ]

        # ... and remove appropriate number of bytes    
        for h, l in encodings:
            if header.startswith(h):
                bom_len = l
                break
        f.seek(0)
        f.read(bom_len)

        # copy the rest of file
        contents = f.read() 
        nf = open(newfilename)
        nf.write(contents)
        nf.close()
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top