python - convertir - cómo saber si una cadena es base64 o no
python base64 to file (6)
Recibo muchos correos electrónicos de diferentes fuentes. todos tienen archivos adjuntos, muchos de ellos tienen nombres de archivos adjuntos en chino, por lo que sus nombres se convierten a base64 por sus clientes de correo electrónico.
Cuando recibo estos correos electrónicos, deseo decodificar el nombre. pero hay otros nombres que no son base64. ¿Cómo puedo diferenciar si una cadena es base64 o no, usando el lenguaje de programación jython ?
Es decir.
Primer archivo adjunto:
------=_NextPart_000_0091_01C940CC.EF5AC860
Content-Type: application/vnd.ms-excel;
name="Copy of Book1.xls"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="Copy of Book1.xls"
segundo archivo adjunto:
------=_NextPart_000_0091_01C940CC.EF5AC860
Content-Type: application/vnd.ms-excel;
name="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
Tenga en cuenta que tanto " Content-Transfer-Encoding " tiene base64
@gnud, @edg - A menos que malinterprete, él pregunta por el nombre del archivo, no por el contenido del archivo @setori - Content-Trasfer-Encoding te dice cómo se codifica el CONTENIDO del archivo, no el "nombre de archivo".
No soy un experto, pero esta parte aquí en el nombre del archivo le está diciendo sobre los personajes que siguen:
=? gb2312? B?
Estoy buscando la documentación en las RFC ... ¡Ah! aquí está: http://tools.ietf.org/html/rfc2047
El RFC dice:
En general, una "palabra codificada" es una secuencia de caracteres ASCII imprimibles que comienza con "=?", Termina con "? =" Y tiene dos "?" S en el medio.
Otra cosa para mirar es el código en SharpMimeTools, un analizador MIME (en C #) que uso en mi aplicación de seguimiento de errores , BugTracker.NET
Bueno, analiza el encabezado del correo electrónico en un diccionario. Y luego comprueba si se ha configurado Content-Transfer-Encoding, y si es = "base64" o "base-64".
El valor del encabezado le dice esto:
=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?= "=?" introduces an encoded value "gb2312" denotes the character encoding of the original value "B" denotes that B-encoding (equal to Base64) was used (the alternative is "Q", which refers to something close to quoted-printable) "?" functions as a separator "uLG..." is the actual value, encoded using the encoding specified before "?=" ends the encoded value
Entonces, ¿dividir en "?" en realidad te consigue esto (notación JSON)
["=", "gb2312", "B", "uLGxvmhlbrixsb5nLnhscw==", "="]
En la matriz resultante, si "B" está en la posición 2, te enfrentas a una cadena codificada en base 64 en la posición 3. Una vez que la decodificaste, asegúrate de prestar atención a la codificación en la posición 1, probablemente sería mejor convertirla todo al UTF-8 usando esa información.
Tenga en cuenta que tanto
Content-Transfer-Encoding
tiene base64
No relevante en este caso, la Content-Transfer-Encoding
solo se aplica a la carga útil del cuerpo, no a los encabezados.
=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?=
Ese es un átomo de encabezado codificado RFC2047. La función stdlib para decodificarlo es email.header.decode_header
. Todavía necesita un poco de procesamiento posterior para interpretar el resultado de esa función:
import email.header
x= ''=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?=''
try:
name= u''''.join([
unicode(b, e or ''ascii'') for b, e in email.header.decode_header(x)
])
except email.Errors.HeaderParseError:
pass # leave name as it was
Sin embargo...
Content-Type: application/vnd.ms-excel;
name="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
Esto es simplemente incorrecto ¿Qué correo lo creó? La codificación RFC2047 solo puede ocurrir en átomos, y una cadena citada no es un átomo. RFC2047 §5 explícitamente niega esto:
- Una ''palabra codificada'' NO DEBE aparecer dentro de una ''cadena entre comillas''.
La forma aceptada de codificar los encabezados de los parámetros cuando la cadena larga o los caracteres Unicode están presentes es RFC2231 , que es una bolsa de daño completamente nueva. Pero deberías estar usando una biblioteca estándar de análisis de correo electrónico que hará frente a eso por ti.
Entonces, ¿podrías detectar el ''=?''
en parámetros de nombre de archivo si lo desea, e intente decodificarlo a través de RFC2047. Sin embargo, lo estrictamente correcto es hacer el envío de la palabra y llamar realmente al archivo =?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?=
!
Hay una manera mejor que el método de bobince para manejar la salida de decode_header
. Lo encontré aquí: http://mail.python.org/pipermail/email-sig/2007-March/000332.html
name = unicode(email.header.make_header(email.header.decode_header(x)))
Pregunta: "" "También realmente necesito saber qué tipo de archivo es, por ejemplo, .xls o .doc, así que necesito decodificar el nombre de archivo para procesar correctamente el archivo adjunto, pero como en el caso anterior, parece que gb2312 no es compatible con jython , ¿sabe alguna rotonda? "" "
Datos:
Content-Type: application/vnd.ms-excel;
name="=?gb2312?B?uLGxvmhlbrixsb5nLnhscw==?="
Observaciones:
(1) La primera línea indica Microsoft Excel, por lo que .xls
se ve mejor que .doc
(2)
>>> import base64
>>> base64.b64decode("uLGxvmhlbrixsb5nLnhscw==")
''/xb8/xb1/xb1/xbehen/xb8/xb1/xb1/xbeg.xls''
>>>
(a) La extensión parece ser .xls
, no es necesario un códec gb2312
(b) Si desea un nombre de archivo seguro para el sistema de archivos, podría usar la variante "-_" de base64 O podría codificar porcentualmente
(c) Por lo que vale, el nombre del archivo es XYhenXYg.xls
donde X e Y son 2 caracteres chinos que en conjunto significan "copiar" y el resto son caracteres ASCII literales.