2012-01-21 12 views
12

Sto scrivendo un semplice parser di espressioni regolari per l'output dell'utilità sensors su Ubuntu. Ecco un esempio di una riga di testo che sto analisi:Come analizzare passivamente il simbolo di grado (Unicode) con le espressioni regolari?

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

Ed ecco l'espressione regolare che sto usando per corrispondere a quello (in Python):

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

Questo codice funziona come previsto e le partite il testo di esempio che ho fornito sopra. Gli unici bit sono davvero interessati a sono i numeri, quindi questo bit:

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

che inizia facendo corrispondere il segno + o - e termina facendo corrispondere il °C.

La mia domanda è: perché sono necessari due caratteri (non alfanumerico) per corrispondere a ° anziché uno? Il codice si interromperà su sistemi in cui Unicode è rappresentato in modo diverso dal mio? Se sì, come posso renderlo portatile?

+2

provare il flag 're.UNICODE' – netvope

+0

Con il flag' re.UNICODE' che RE non corrisponde con '\ W \ WC' o' \ WC'. O ti ho frainteso? – snim2

+1

C'è anche "' ℃ '", che è un carattere _single_ che significa gradi centigradi. Grazie mille, Unicode Consortium! –

risposta

8

Possibile soluzione portatile:

dati di input convertire in Unicode e utilizzare re.UNICODE bandiera nelle espressioni regolari.

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

uscita

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

EDIT

@netvope giá fatto notare nei commenti per la domanda.

Aggiornamento

Note da J.F. Sebastian commenti su codifica in ingresso:

check_output() restituisce dati binari che a volte può essere testo (che dovrebbero avere una codifica dei caratteri noto in questo caso e si può convertirlo a Unicode). Comunque ord (u '°') == 176 quindi non può essere codificato usando la codifica ASCII.

Così, per decodificare i dati di input per unicode, in pratica * è necessario utilizzare la codifica dal locale sistema usando locale.getpreferredencoding() esempio:

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

Con i dati codificati in modo corretto:

si otterrà lo stesso output senza re.UNICODE in questo caso.


Perché in fondo?Perché su Win7 russo con cp1251 come preferredencoding se abbiamo per esempio script.py che decodifica il suo output a utf-8:

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

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

E necessità wee per analizzare il suo output:

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

produrrà risultati errati: 'В°' invece °.

Quindi è necessario conoscere la codifica dei dati di input, in alcuni casi.

+0

Certo, ma un esempio operativo completo per questo genere di cose è sempre una buona idea. Gestire correttamente Unicode è difficile per molti programmatori anche quando sono disponibili tutti i servizi :( –

+0

+1: per "convertire i dati di input in unicode". Btw, in questo caso otterrai lo stesso output senza 're.UNICODE'. – jfs

+0

Grazie per questo.Ho avuto un gioco con esso.Nel codice "reale" i dati in realtà provengono dall'output di una chiamata a "subprocess.check_output' che restituisce i suoi dati come ASCII, non Unicode, quindi questo non lo fa Forse c'è una cosa più sensata da passare a Python3 dove "tutto" è Unicode? Hmm. – snim2

Problemi correlati