Подтвердить что ты не робот

Как переносить синтаксический символ (Unicode) с регулярными выражениями?

Я пишу простой анализатор регулярных выражений для вывода утилиты 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 представлен по-разному для моего? Если да, то как я могу сделать его переносимым?

4b9b3361

Ответ 1

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

Преобразование входных данных в 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')]

ИЗМЕНИТЬ

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

Обновление

Заметки из J.F. Себастьян комментарий о кодировке ввода:

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())

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

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