2016-03-03 13 views
5

Tôi đang cố gắng để phù hợp với một nhân vật và tất cả các biến thể có thể có của nó (aka accent-insensitive) với một biểu thức chính quy. Những gì tôi có thể làm tất nhiên là:Regex - phù hợp với một nhân vật và tất cả các biến thể của nó (còn gọi là không nhạy cảm)

re.match(r"^[eēéěèȅêęëėẹẽĕȇȩę̋ḕḗḙḛḝė̄]$", "é") 

nhưng đó không phải là giải pháp chung. Nếu tôi sử dụng các danh mục unicode như \pL Tôi không thể giảm đối sánh thành một ký tự cụ thể, trong trường hợp này là e.

+0

Python regex có hỗ trợ * tương tự ký tự POSIX * khớp không? Điều này đơn giản như '[= e =]' - nhưng nó cũng khớp với các giá trị vốn hóa tương đương, có thể quá nhiều trong trường hợp của bạn. Điều này có thể được làm việc xung quanh bằng cách sử dụng '(?! \ U)', mặc dù điều này lần lượt cần regex của bạn để hỗ trợ chữ hoa cho tất cả các ký tự Unicode là tốt. – usr2564301

Trả lời

12

Một cách giải quyết để đạt được mục tiêu mong muốn sẽ được sử dụng unidecode để thoát khỏi tất cả các dấu đầu tiên, và sau đó chỉ cần phù hợp với agains thường xuyên e

re.match(r"^e$", unidecode("é")) 

Hoặc trong trường hợp đơn giản này

unidecode("é") == "e" 

Một giải pháp khác không phụ thuộc vào thư viện unidecode, bảo toàn unicode và cho phép kiểm soát nhiều hơn bằng cách xóa thủ công diacri tics như sau:

Sử dụng unicodedata.normalize() để biến chuỗi đầu vào của bạn vào mẫu bình thường D (đối với phân hủy), làm cho nhân vật chắc chắn composit như é được biến thành dạng phức dụng e\u301 (e + Kết hợp CẤP TÍNH ACCENT)

>>> input = "Héllô" 
>>> input 
'Héllô' 
>>> normalized = unicodedata.normalize("NFKD", input) 
>>> normalized 
'He\u0301llo\u0302' 

Sau đó, xóa tất cả các điểm mã nằm trong danh mục Mark, Nonspacing (ngắn Mn). Đó là tất cả các nhân vật không có chiều rộng và chỉ trang trí cho nhân vật trước đó. Sử dụng unicodedata.category() để xác định danh mục.

>>> stripped = "".join(c for c in normalized if unicodedata.category(c) != "Mn") 
>>> stripped 
'Hello' 

Kết quả có thể được sử dụng làm nguồn cho đối sánh regex, giống như trong ví dụ unidecode ở trên. Đây là toàn bộ chức năng dưới dạng hàm:

def remove_diacritics(text): 
    """ 
    Returns a string with all diacritics (aka non-spacing marks) removed. 
    For example "Héllô" will become "Hello". 
    Useful for comparing strings in an accent-insensitive fashion. 
    """ 
    normalized = unicodedata.normalize("NFKD", text) 
    return "".join(c for c in normalized if unicodedata.category(c) != "Mn") 
Các vấn đề liên quan