2012-01-21 10 views
12

Estoy escribiendo un analizador simple de expresiones regulares para la salida de la utilidad sensors en Ubuntu. Aquí está un ejemplo de una línea de texto que estoy de análisis:¿Cómo analizar de forma portátil el símbolo de grado (Unicode) con expresiones regulares?

temp1:  +31.0°C (crit = +107.0°C) 

Y aquí está la expresión regular que estoy usando para que coincida (en Python):

temp_re = re.compile(r'(temp1:)\s+(\+|-)(\d+\.\d+)\W\WC\s+' 
        r'\(crit\s+=\s+(\+|-)(\d+\.\d+)\W\WC\).*') 

Este código funciona como se espera y partidos el texto de ejemplo que he dado arriba. Los únicos bits de las que estoy muy interesado en son los números, por lo que este bit:

(\+|-)(\d+\.\d+)\W\WC 

que comienza haciendo coincidir el signo + o - y termina haciendo coincidir el °C.

Mi pregunta es, ¿por qué se necesitan dos caracteres \W (no alfanuméricos) para que coincida con ° en lugar de uno? ¿Se romperá el código en los sistemas donde Unicode se representa de manera diferente a la mía? Si es así, ¿cómo puedo hacer que sea portátil?

+2

prueba la bandera 're.UNICODE' – netvope

+0

Con la bandera' re.UNICODE' que RE no concuerda con '\ W \ WC' o' \ WC'. O, ¿te he entendido mal? – snim2

+1

También hay "' ℃ '", que es un carácter simple que significa grados celsius. Muchas gracias, Consorcio Unicode! –

Respuesta

8

Posible solución portátil:

datos de entrada Convertir a Unicode, y utilizar re.UNICODE bandera en las expresiones regulares.

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
import re 


data = u'temp1:  +31.0°C (crit = +107.0°C)' 
temp_re = re.compile(ur'(temp1:)\s+(\+|-)(\d+\.\d+)°C\s+' 
        ur'\(crit\s+=\s+(\+|-)(\d+\.\d+)°C\).*', flags=re.UNICODE) 

print temp_re.findall(data) 

salida

[(u'temp1:', u'+', u'31.0', u'+', u'107.0')] 

EDITAR

@netvope allready señalado esto en los comentarios sobre la pregunta.

Actualizar

Notas de J.F. Sebastian comentarios acerca de codificación de entrada:

check_output() retornos de datos binarios que a veces puede ser texto (que deben tener una conocida codificación de caracteres en este caso y se puede convertir a Unicode). De todos modos ord (u '°') == 176 por lo que no se puede codificar utilizando codificación ASCII.

Así, para decodificar los datos de entrada a unicode, básicamente * se debe utilizar la codificación de la configuración regional del sistema usando locale.getpreferredencoding() por ejemplo:

data = subprocess.check_output(...).decode(locale.getpreferredencoding()) 

Con los datos codificados correctamente:

obtendrá el mismo resultado sin re.UNICODE en este caso.


Por qué básicamente?Debido a que en Win7 rusa con cp1251 como preferredencoding si tenemos por ejemplo script.py que decodifica su salida a utf-8:

#!/usr/bin/env python 
# -*- coding: utf8 -*- 

print u'temp1: +31.0°C (crit = +107.0°C)'.encode('utf-8') 

Y necesidad wee para analizar su salida:

subprocess.check_output(['python', 
         'script.py']).decode(locale.getpreferredencoding()) 

producirá resultados erróneos: 'В°' vez °.

Por lo tanto, necesita conocer la codificación de los datos de entrada, en algunos casos.

+0

Claro, pero un ejemplo completo de trabajo para este tipo de cosas siempre es una buena idea. Manejar Unicode correctamente es difícil para muchos programadores, incluso cuando hay todas las instalaciones disponibles :( –

+0

+1: para "convertir datos de entrada a Unicode". Por cierto, obtendrás el mismo resultado sin 're.UNICODE' en este caso. – jfs

+0

Gracias por esto. He tenido un juego con él. En el código "real" los datos provienen de la salida de una llamada a 'subprocess.check_output' que devuelve sus datos como ASCII, no como Unicode, así que esto no Trabajar allí. Quizás una cosa más sensata sería pasar a Python3 donde "todo" es Unicode? Hmm. – snim2

Cuestiones relacionadas