2012-01-21 29 views
12

Tôi đang viết một trình phân tích biểu thức chính quy đơn giản cho đầu ra của tiện ích sensors trên Ubuntu. Dưới đây là một ví dụ về một dòng văn bản Tôi đang phân tích cú pháp:Làm cách nào để phân tích cú pháp biểu tượng độ (Unicode) có thể phân tách bằng biểu thức chính quy?

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

Và đây là regex Tôi đang sử dụng để phù hợp với (bằng Python):

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

Mã này hoạt động như mong đợi và các trận đấu văn bản ví dụ tôi đã đưa ra ở trên. Các bit duy nhất tôi thực sự quan tâm là những con số, vì vậy bit này:

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

mà bắt đầu bằng cách kết hợp các dấu hiệu + hoặc - và kết thúc bằng cách kết hợp các °C.

Câu hỏi của tôi là, tại sao phải mất hai ký tự \W (không phải chữ số) để khớp với ° thay vì một? Mã có bị phá vỡ trên các hệ thống mà Unicode được biểu diễn khác với tôi không? Nếu vậy, làm thế nào tôi có thể làm cho nó di động?

+2

thử cờ 're.UNICODE' – netvope

+0

Với cờ' re.UNICODE' mà RE không khớp với '\ W \ WC' hoặc' \ WC'. Hoặc, tôi đã hiểu lầm bạn? – snim2

+1

Ngoài ra còn có "' ℃ ", là một ký tự _single_ có nghĩa là độ celsius. Cảm ơn một nhóm, Unicode Consortium! –

Trả lời

8

giải pháp di động có thể xảy ra:

dữ liệu Chuyển đổi đầu vào cho unicode, và sử dụng re.UNICODE cờ trong biểu thức thông thường.

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

Output

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

EDIT

@netvope allready chỉ ra điều này trong ý kiến ​​cho câu hỏi.

Cập nhật

Ghi chú từ J.F. Sebastian ý kiến ​​về mã hoá đầu vào:

check_output() trả về dữ liệu nhị phân mà đôi khi có thể là văn bản (mà nên có một mã hóa ký tự được biết đến trong trường hợp này và bạn có thể chuyển đổi nó sang Unicode). Anyway ord (u '°') == 176 để nó không thể được mã hóa bằng cách sử dụng mã hóa ASCII.

Vì vậy, để giải mã dữ liệu đầu vào để unicode, về cơ bản * bạn nên sử dụng mã hóa từ hệ thống locale sử dụng locale.getpreferredencoding() ví dụ:

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

Với dữ liệu được mã hóa một cách chính xác:

bạn sẽ nhận được cùng một đầu ra không có re.UNICODE trong trường hợp này.


Tại sao về cơ bản?Bởi vì trên Win7 Nga với cp1251 như preferredencoding nếu chúng ta có ví dụ script.py mà giải mã nó ra để utf-8:

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

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

Và cần wee để phân tích nó ra:

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

sẽ tạo ra kết quả sai: 'В°' thay °.

Vì vậy, bạn cần phải biết mã hóa dữ liệu đầu vào, trong một số trường hợp.

+0

Chắc chắn, nhưng một ví dụ làm việc đầy đủ cho loại điều này luôn luôn là một ý tưởng tốt. Xử lý Unicode đúng là rất khó đối với nhiều lập trình viên ngay cả khi có đầy đủ các tiện ích: ( –

+0

+1: cho "chuyển đổi dữ liệu đầu vào thành unicode" .btw, bạn sẽ nhận được cùng một đầu ra không có 're.UNICODE' trong trường hợp này. – jfs

+0

Cảm ơn vì điều này.Tôi đã chơi với nó.Trong mã "thực", dữ liệu thực sự xuất phát từ đầu ra của lệnh gọi tới 'subprocess.check_output' trả về dữ liệu của nó dưới dạng ASCII, không phải Unicode, do đó, điều này không ' Có lẽ một điều hợp lý hơn là chuyển sang Python3 trong đó "mọi thứ" là Unicode? Hmm. – snim2

Các vấn đề liên quan