2016-08-24 19 views
12

Để khớp với các ranh giới từ Unicode [như được định nghĩa trong Annex #29] bằng Python, tôi đã sử dụng gói regex với cờ regex.WORD | regex.V1 (regex.UNICODE phải mặc định vì mẫu là chuỗi Unicode) theo cách sau:Khớp ranh giới từ Unicode trong Python

>>> s="here are some words" 
>>> regex.findall(r'\w(?:\B\S)*', s, flags = regex.V1 | regex.WORD) 
['here', 'are', 'some', 'words'] 

Nó hoạt động tốt trong trường hợp khá đơn giản này. Tuy nhiên, tôi đã tự hỏi hành vi mong đợi là gì trong trường hợp chuỗi đầu vào chứa dấu câu nhất định. Dường như với tôi rằng WB7 nói rằng ví dụ như dấu nháy đơn trong x'z không được coi là một ranh giới từ đó có vẻ là thực sự là trường hợp:

>>> regex.findall(r'\w(?:\B\S)*', "x'z", flags = regex.V1 | regex.WORD) 
["x'z"] 

Tuy nhiên, nếu có một nguyên âm, tình hình thay đổi:

>>> regex.findall(r'\w(?:\B\S)*', "l'avion", flags = regex.V1 | regex.WORD) 
["l'", 'avion'] 

Điều này sẽ gợi ý rằng mô-đun regex thực hiện quy tắc WB5a được đề cập trong tiêu chuẩn trong phần Ghi chú. Tuy nhiên, quy định này cũng nói rằng hành vi nên giống với \u2019 (Dấu ngoặc kép đơn bên phải) mà tôi không thể tái sản xuất:

>>> regex.findall(r'\w(?:\B\S)*', "l\u2019avion", flags = regex.V1 | regex.WORD) 
['l’avion'] 

Hơn nữa, ngay cả với dấu nháy đơn "bình thường", một dấu gạch nối (hoặc y) dường như hoạt động như một "nguyên âm không":

>>> regex.findall(r'\w(?:\B\S)*', "l'œil", flags = regex.V1 | regex.WORD) 
["l'œil"] 
>>> regex.findall(r'\w(?:\B\S)*', "J'y suis", flags = regex.V1 | regex.WORD) 
["J'y", 'suis'] 

Đây có phải là hành vi mong đợi không? (Tất cả các ví dụ trên được thực hiện với regex 2.4.106 và Python 3.5.2)

Trả lời

6

1- QUYỀN SINGLE BÁO GIÁ MARK dường như được chỉ đơn giản là bỏ lỡ trong source file:

/* Break between apostrophe and vowels (French, Italian). */ 
/* WB5a */ 
if (pos_m1 >= 0 && char_at(state->text, pos_m1) == '\'' && 
    is_unicode_vowel(char_at(state->text, text_pos))) 
    return TRUE; 

2- nguyên âm Unicode được xác định với is_unicode_vowel() chức năng mà dịch vào danh sách này:

a, à, á, â, e, è, é, ê, i, ì, í, î, o, ò, ó, ô, u, ù, ú, û 

Vì vậy, một nhân vật LATIN SMALL LIGATURE OEœ không được coi là một nguyên âm unicode:

Py_LOCAL_INLINE(BOOL) is_unicode_vowel(Py_UCS4 ch) { 
#if PY_VERSION_HEX >= 0x03030000 
    switch (Py_UNICODE_TOLOWER(ch)) { 
#else 
    switch (Py_UNICODE_TOLOWER((Py_UNICODE)ch)) { 
#endif 
    case 'a': case 0xE0: case 0xE1: case 0xE2: 
    case 'e': case 0xE8: case 0xE9: case 0xEA: 
    case 'i': case 0xEC: case 0xED: case 0xEE: 
    case 'o': case 0xF2: case 0xF3: case 0xF4: 
    case 'u': case 0xF9: case 0xFA: case 0xFB: 
     return TRUE; 
    default: 
     return FALSE; 
    } 
} 

lỗi này bây giờ là cố định trong regex 2016/08/27 sau một bug report. [_regex.c:#1668]

+2

Điểm 1 chắc chắn trông giống như một lỗi và tôi khuyên bạn nên báo cáo lỗi đó, nếu bạn chưa có. Thật khó để nói về điểm 2. Tìm kiếm "nguyên âm" trên unicode.org cung cấp một số lần truy cập cho các ngôn ngữ châu Á khác nhau, nhưng không có gì về tiếng Pháp hoặc tiếng Ý. Các ví dụ của OP chắc chắn có vẻ đúng, nhưng tôi không thể thấy rằng Phụ lục 29 đề cập cụ thể đến chúng. – saulspatz

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