Как портативно разобрать символ степени (Unicode) с регулярными выражениями? - PullRequest
13 голосов
/ 21 января 2012

Я пишу простой парсер регулярных выражений для вывода утилиты sensors в Ubuntu.Вот пример строки текста, которую я анализирую:

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

И вот регулярное выражение, которое я использую для сопоставления (в Python):

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

Этот код работаеткак ожидалось и соответствует тексту примера, который я дал выше.Единственные биты, которые меня действительно интересуют - это числа, поэтому этот бит:

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

, который начинается с совпадения со знаком + или - и заканчивается совпадением с °C.

Мой вопрос: почему для сопоставления ° вместо одного требуется два \W (не алфавитно-цифровых) символа?Будет ли код ломаться в системах, где Unicode представлен иначе, чем мой?Если так, как я могу сделать это портативным?

1 Ответ

8 голосов
/ 21 января 2012

Возможное портативное решение:

Преобразование входных данных в Unicode и использование флага re.UNICODE в регулярных выражениях.

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

Вывод

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

EDIT

@ netvope уже указал это в комментариях к вопросу.

Обновление

Примечания от JF Sebastian комментарии о кодировке ввода:

check_output() возвращает двоичные данные, которые иногда могут быть текстовыми (в этом случае они должны иметь известную кодировку символов, и вы можете преобразовать их в Unicode).В любом случае ord (u '°') == 176, поэтому его нельзя кодировать с использованием кодировки ASCII.

Итак, чтобы декодировать входные данные в unicode, в основном * вам следует использовать кодирование из языкового стандарта системыиспользуя locale.getpreferredencoding() например:

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

С данными, закодированными правильно:

в этом случае вы получите тот же результат без re.UNICODE.


Почему в основном?Потому что на русском Win7 с cp1251 как preferredencoding, если у нас есть, например, script.py, который декодирует его вывод в utf-8:

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

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

И нам нужно проанализировать его вывод:

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

приведет к неправильным результатам: 'В°' вместо °.

Поэтому в некоторых случаях вам необходимо знать кодировку входных данных.

...