Xử lý tiếng Việt bằng Python

Để có thể type được tiếng Việt trong môi trường lập trình Python và save thành file .py, bạn cần phải thêm 1 thông báo vào đầu chương trình :

```
# -*- coding: utf8 -*-

```

Từ bây giờ, tôi mặc định chương trình luôn có đoạn khai báo font chữ này.

## Các hàm dựng sẵn và Unicode

Lấy 1 ví dụ đơn giản sau :

```
s = "Lưu Tuấn Anh"
print s, len(s)

```

Kết quả nhận được sẽ là :

```
Lưu Tuấn Anh 15

```

Điều này khá kì quặc khi chuỗi “Lưu Tuấn Anh” chỉ có 12 chữ cái.

Ta tiếp tục thêm vào đoạn mã sau :

```
for char in s:
    print char

```

Kết quả nhận được sẽ là :

```
L
�
�
u

T
u
�
�
�
n

A
n
h

```

Như vậy ta có thể thấy chữ “ư” được biểu diễn bằng 2 byte, chữ “ấ” được biểu diễn bằng 3 byte. Lý do cho lỗi phát sinh này là sự không tương thích về định dạng giữa chuỗi s và hàm len(s). Khi chuỗi s đưa vào hàm len(), nó sẽ được mặc định là ASCII, và 1 kí tự ASCII chỉ chiếm 1 byte.

Sửa lại ví dụ trên 1 chút :

```
s = u"Lưu Tuấn Anh"
print s, len(s)

```

Kết quả sẽ được :

```
Lưu Tuấn Anh 12

```

Chữ cái ‘u’ trước chuỗi là dạng viết tắt để Python hiểu được chuỗi s sẽ được hiển thị và thao tác dưới dạng Unicode. Như thế hàm len() cũng hoạt động 1 cách chính xác.

Khi lập trình xử lý tiếng Việt, chúng ta sẽ còn gặp lại nhiều tình huống giống như thế này. Vì thế bất cứ lúc nào, bạn cũng phải xác định được mình đang thao tác với chuỗi có định dạng gì : Unicode, ASCII, hay UTF8, …

## Các toán tử với chuỗi

Ta có đoạn code sau :

```
s = "Lưu "
t = s+u"Tuấn Anh"
print t, len(t), type(t)

```

Chuỗi s không được khai báo là Unicode, vì thế trong phép cộng 2 chuỗi ở lệnh tiếp theo, ta có dạng “1 chuỗi không phải Unicode” + “1 chuỗi là Unicode”.

Kết quả sẽ được :

```
Lưu Tuấn Anh 12 <type 'unicode'>

```

Ta rút ra kết luận, Python đã tự chuyển chuỗi không phải Unicode thành Unicode rồi thực hiện phép cộng, do đó chuỗi kết quả nhận được cũng dưới dạng Unicode.

Ta sẽ thử với các hàm khác trong Python :

```
t = "Lưu Tuấn Anh"
tt = t.split(u" ")
print tt

```

Kết quả sẽ khiến bạn đau đầu :

```
[u'L\u01b0u', u'Tu\u1ea5n', u'Anh']

```

Nhưng nếu chú ý kĩ, mỗi phần tử trong tt vẫn theo định dạng Unicode. Ta sẽ thêm vào đoạn mã trên 2 dòng lệnh nữa :

```
for tp in tt:
    print tp, len (tp)

```

Kết quả lúc này sẽ nhận được :

```
Lưu 3
Tuấn 4
Anh 3

```

Như thế hàm split() vẫn đảm bảo tính chính xác của chuỗi dưới dạng unicode.

Các thao tác với chuỗi khác như join, find, … cũng tương tự : khi có 1 tham số dạng Unicode thì các tham số còn lại cũng tự động chuyển sang dạng Unicode trước khi thao tác.

Tiếp tục thử với hàm upper(). Ta có đoạn mã sau :

```
t = "Lưu Tuấn Anh"
print t.upper()

```

Kết quả nhận được sẽ là :

```
LưU TUấN ANH

```

Tức là hàm upper() không tác động được lên kí tự ‘ư’ và kí tự ‘ấ’. Ta sẽ sửa lại đoạn mã trên bằng cách khai báo t dưới dạng unicode :

```
t = u"Lưu Tuấn Anh"
print t.upper()

```

Kết quả là :

```
LƯU TUẤN ANH

```

Kết luận : khi thao tác trên tiếng Việt hay các chuỗi Unicode, để tránh những lỗi phát sinh không đáng có, hãy khai báo định dạng chuỗi là unicode ngay từ đầu.

Có 1 cách xử lý khác cho vấn đề này là khai báo từ đầu chương trình :

```
sys.stdout = codecs.getwriter('utf_8')(sys.stdout)
sys.stdin = codecs.getreader('utf_8')(sys.stdin)

```

## Vào/ra với Unicode

Với dữ liệu từ/đến bộ nhớ ngoài, bạn có thể sử dụng kỹ thuật tương tự để đảm bảo luôn luôn làm việc trên các chuỗi Unicode:

```
with codecs.getwriter('utf_8')(open(path, "w") as f:
    f.write(...)
with codecs.getreader('utf_8')(open(path, "r") as f:
    for line in f: ...

```

## Tham khảo

* Xử lý tiếng Việt bằng Python - Lưu Tuấn Anh