2010-09-27 27 views
6

Tôi có các chuỗi đa ngôn ngữ bao gồm cả hai ngôn ngữ sử dụng khoảng trắng làm dấu phân tách từ (tiếng Anh, tiếng Pháp, v.v.) và các ngôn ngữ không (tiếng Trung, tiếng Nhật, tiếng Hàn). Với một chuỗi như vậy, tôi muốn tách phần tiếng Anh/tiếng Pháp/vv thành các từ bằng cách sử dụng khoảng trống làm dấu phân tách và tách phần Trung Quốc/Nhật Bản/Hàn Quốc thành các ký tự riêng lẻ.Python: bất kỳ cách nào để thực hiện việc chia tách "lai"() này trên các chuỗi đa ngôn ngữ (ví dụ: tiếng Trung và tiếng Anh)?

Và tôi muốn đặt tất cả các thành phần được phân tách đó vào danh sách.

Một số ví dụ có lẽ sẽ làm rõ điều này:

Trường hợp 1: Tiếng Anh chỉ chuỗi. Trường hợp này rất dễ dàng:

>>> "I love Python".split() 
['I', 'love', 'Python'] 

Trường hợp 2: Trung Quốc chỉ chuỗi:

>>> list(u"我爱蟒蛇") 
[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7'] 

Trong trường hợp này tôi có thể biến các chuỗi vào một danh sách các chữ Hán. Nhưng trong danh sách tôi nhận được các biểu diễn unicode:

[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7'] 

Làm cách nào để hiển thị ký tự thực tế thay vì mã unicode? Một cái gì đó như:

['我', '爱', '蟒', '蛇'] 

??

Trường hợp 3: Một sự pha trộn tiếng Anh & Trung Quốc:

Tôi muốn biến một chuỗi đầu vào như

"我爱Python" 

và biến nó thành một danh sách như thế này:

['我', '爱', 'Python'] 

Có thể làm điều gì đó như vậy không?

+0

Thật không may, có một misfeature trong hiện tại của Python 're' mô-đun ngăn cản' re.split() 'tách thành các kết quả có độ dài bằng không: http://stackoverflow.com/questions/2713060/why-doesnt-pythons-re-split-split-on-zero-length -match - do đó bạn không thể sử dụng các biểu thức chính quy trong Python cho điều này trực tiếp. –

+1

Hàn Quốc sử dụng khoảng trắng để tách từ. – Leovt

Trả lời

3

Tôi nghĩ tôi cũng muốn hiển thị phương pháp regex. Nó không có ý nghĩa với tôi, nhưng đó là chủ yếu bởi vì tất cả những điều kỳ quặc đặc biệt về ngôn ngữ mà tôi đã thấy làm tôi lo lắng rằng một biểu thức chính quy có thể không đủ linh hoạt cho tất cả chúng - nhưng bạn cũng có thể không cần bất kỳ về điều đó. (Nói cách khác - overdesign.)

# -*- coding: utf-8 -*- 
import re 
def group_words(s): 
    regex = [] 

    # Match a whole word: 
    regex += [ur'\w+'] 

    # Match a single CJK character: 
    regex += [ur'[\u4e00-\ufaff]'] 

    # Match one of anything else, except for spaces: 
    regex += [ur'[^\s]'] 

    regex = "|".join(regex) 
    r = re.compile(regex) 

    return r.findall(s) 

if __name__ == "__main__": 
    print group_words(u"Testing English text") 
    print group_words(u"我爱蟒蛇") 
    print group_words(u"Testing English text我爱蟒蛇") 

Thực tế, bạn có thể chỉ muốn biên dịch regex một lần, không phải trên mỗi cuộc gọi. Một lần nữa, điền vào các chi tiết của nhóm nhân vật là tùy thuộc vào bạn.

+0

@Glenn Maynard. Cảm ơn nhiều. Đây chính xác là những gì tôi cần. Bạn có thể cung cấp cho tôi gợi ý về nơi để tìm kiếm unicode "phạm vi" cho các ngôn ngữ khác nhau? – Continuation

+0

Không thực sự. Các ký tự không nhóm độc đáo theo ngôn ngữ; bạn có thể chọn ra các phạm vi chính đơn giản. –

+0

-1 @Glenn Maynard: Trong ngôn ngữ "C", điều này không thành công trên bảng chữ cái không phải ASCII không phải ASCII, ví dụ: như được tìm thấy trong tiếng Pháp [yêu cầu OP], tiếng Đức, tiếng Nga - 'u 'München'' -> '[u'M ', u' \ xfc ', u'nchen']'. Thật không may, điều này có thể được sửa bằng cách sử dụng cờ 're.UNICODE' nhưng điều đó làm cho' \ w' khớp với hầu hết các ký tự CJK (loại 'Lo'). –

2

Định dạng danh sách hiển thị repr các thành phần của nó. Nếu bạn muốn xem các chuỗi tự nhiên thay vì thoát, bạn sẽ cần tự định dạng các chuỗi đó. (repr nên không được thoát những nhân vật này; repr(u'我') nên trở "u'我'", không "u'\\u6211' Rõ ràng điều này không xảy ra trong Python 3;. Chỉ 2.x đang mắc kẹt với tiếng Anh tập trung thoát cho chuỗi Unicode.)

Một cơ bản thuật toán bạn có thể sử dụng là gán một lớp nhân vật cho mỗi ký tự, sau đó nhóm các chữ cái theo lớp. Mã khởi động bên dưới.

Tôi đã không sử dụng doctest cho điều này vì tôi đã nhấn một số vấn đề mã hóa lẻ mà tôi không muốn xem xét (ngoài phạm vi). Bạn sẽ cần phải thực hiện một chức năng nhóm chính xác.

Lưu ý rằng nếu bạn đang sử dụng tính năng này cho gói từ, thì có các cân nhắc khác về ngôn ngữ. Ví dụ, bạn không muốn phá vỡ không gian không phá vỡ; bạn muốn phá vỡ dấu gạch nối; đối với người Nhật, bạn không muốn tách rời き ゅ; và vân vân.

# -*- coding: utf-8 -*- 
import itertools, unicodedata 

def group_words(s): 
    # This is a closure for key(), encapsulated in an array to work around 
    # 2.x's lack of the nonlocal keyword. 
    sequence = [0x10000000] 

    def key(part): 
     val = ord(part) 
     if part.isspace(): 
      return 0 

     # This is incorrect, but serves this example; finding a more 
     # accurate categorization of characters is up to the user. 
     asian = unicodedata.category(part) == "Lo" 
     if asian: 
      # Never group asian characters, by returning a unique value for each one. 
      sequence[0] += 1 
      return sequence[0] 

     return 2 

    result = [] 
    for key, group in itertools.groupby(s, key): 
     # Discard groups of whitespace. 
     if key == 0: 
      continue 

     str = "".join(group) 
     result.append(str) 

    return result 

if __name__ == "__main__": 
    print group_words(u"Testing English text") 
    print group_words(u"我爱蟒蛇") 
    print group_words(u"Testing English text我爱蟒蛇") 
0

Modified giải pháp Glenn để thả các biểu tượng và làm việc cho bảng chữ cái tiếng Nga, tiếng Pháp, vv:

def rec_group_words(): 
    regex = [] 

    # Match a whole word: 
    regex += [r'[A-za-z0-9\xc0-\xff]+'] 

    # Match a single CJK character: 
    regex += [r'[\u4e00-\ufaff]'] 

    regex = "|".join(regex) 
    return re.compile(regex) 
1

Trong Python 3, nó cũng tách số nếu bạn cần.

def spliteKeyWord(str): 
    regex = r"[\u4e00-\ufaff]|[0-9]+|[a-zA-Z]+\'*[a-z]*" 
    matches = re.findall(regex, str, re.UNICODE) 
    return matches 

print(spliteKeyWord("Testing English text我爱Python123")) 

=> [ 'kiểm tra', 'Anh', 'text', '我', '爱', 'Python', '123']

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