2008-10-13 40 views
9

Tôi không chắc chắn làm thế nào để đặt câu hỏi này thực sự, và tôi không có nơi gần tìm câu trả lời, vì vậy tôi hy vọng ai đó có thể giúp tôi.Xử lý chuỗi có chứa nhiều mã hóa ký tự

Tôi đang viết một ứng dụng Python kết nối với máy chủ từ xa và nhận lại dữ liệu byte, mà tôi giải nén bằng cách sử dụng mô-đun cấu trúc dựng sẵn của Python. Vấn đề của tôi là với các chuỗi, vì chúng bao gồm nhiều mã hóa ký tự. Dưới đây là một ví dụ về một chuỗi ví dụ:

"^ LThis là một ví dụ^G-string với nhiều^mã hóa Jcharacter"

Trường hợp bắt đầu mã hóa khác nhau và kết thúc được đánh dấu bằng ký tự thoát đặc biệt:

  • ^L - latin1
  • ^E - Trung Âu
  • ^T - Thổ Nhĩ Kỳ
  • ^B - Baltic
  • ^J - Nhật
  • ^C - Cyrillic
  • ^G - Hy Lạp

Và vân vân ... Tôi cần một cách để chuyển đổi loại này của chuỗi thành Unicode, nhưng tôi thực sự không chắc chắn làm thế nào để làm điều đó. Tôi đã đọc trên các codec của Python và string.encode/decode, nhưng tôi không thực sự là người khôn ngoan. Tôi nên đề cập đến là tốt, rằng tôi không có quyền kiểm soát cách dây được xuất bởi máy chủ.

Tôi hy vọng ai đó có thể giúp tôi với cách bắt đầu.

+0

Trình phân tích cú pháp của bạn có bất kỳ lỗi nào hoặc bạn còn lại bằng chuỗi Python hợp lệ, nhưng với mã hóa không sử dụng được không? Nếu vậy, mọi thứ có thể được sửa. Vui lòng cung cấp một chuỗi ví dụ. – DzinX

+0

Tôi có nghĩa là ví dụ khác so với ở trên, như ví dụ trên chỉ có các ký tự ASCII. – DzinX

Trả lời

4

Không có chức năng tích hợp để giải mã chuỗi như thế này, vì nó thực sự là codec tùy chỉnh của riêng nó. Bạn chỉ cần chia nhỏ chuỗi ký tự trên các ký tự điều khiển đó và giải mã nó cho phù hợp.

Dưới đây là một (rất chậm) ví dụ về một hàm như vậy để xử lý latin1 và shift-JIS:

latin1 = "latin-1" 
japanese = "Shift-JIS" 

control_l = "\x0c" 
control_j = "\n" 

encodingMap = { 
    control_l: latin1, 
    control_j: japanese} 

def funkyDecode(s, initialCodec=latin1): 
    output = u"" 
    accum = "" 
    currentCodec = initialCodec 
    for ch in s: 
     if ch in encodingMap: 
      output += accum.decode(currentCodec) 
      currentCodec = encodingMap[ch] 
      accum = "" 
     else: 
      accum += ch 
    output += accum.decode(currentCodec) 
    return output 

Một phiên bản nhanh hơn có thể sử dụng str.split, hoặc biểu thức thông thường.

(Ngoài ra, như bạn có thể thấy trong ví dụ này, "^ J" là ký tự điều khiển cho "xuống dòng", do đó dữ liệu đầu vào của bạn sẽ có một số hạn chế thú vị.)

3

Tôi sẽ viết một codec từng bước quét chuỗi và giải mã các byte khi chúng xuất hiện. Về cơ bản, bạn sẽ phải tách các chuỗi thành các khối bằng mã hóa nhất quán và giải mã các chuỗi đó và nối chúng vào các chuỗi theo sau chúng.

1

Tôi không giả bạn có cách nào thuyết phục người chủ máy khác chuyển sang unicode không?

Đây là một trong những lý do Unicode được phát minh.

+0

Như tôi đã nói, tôi không kiểm soát được bản thân máy chủ. Các máy chủ thực sự là một trò chơi máy tính mà ứng dụng của tôi kết nối với, và tôi tin rằng đây là cách nó xử lý văn bản của nó rendering trong nội bộ. –

2

Bạn chắc chắn phải chia chuỗi đầu tiên thành các phần mã hóa với các mã hóa khác nhau và giải mã từng mã một riêng biệt.Chỉ để cho vui, sự bắt buộc "một dòng" phiên bản:

import re 

encs = { 
    'L': 'latin1', 
    'G': 'iso8859-7', 
    ... 
} 

decoded = ''.join(substr[2:].decode(encs[substr[1]]) 
      for substr in re.findall('\^[%s][^^]*' % ''.join(encs.keys()), st)) 

(không kiểm tra lỗi, và cũng có thể bạn sẽ muốn quyết định làm thế nào để xử lý '^' nhân vật trong chuỗi con)

+0

Bạn đã thực hiện chính xác cùng một sai lầm như tôi! –

7

Dưới đây là một tương đối ví dụ đơn giản về cách thực hiện ...

# -*- coding: utf-8 -*- 
import re 

# Test Data 
ENCODING_RAW_DATA = (
    ('latin_1', 'L', u'Hello'),  # Latin 1 
    ('iso8859_2', 'E', u'dobrý večer'), # Central Europe 
    ('iso8859_9', 'T', u'İyi akşamlar'), # Turkish 
    ('iso8859_13', 'B', u'Į sveikatą!'), # Baltic 
    ('shift_jis', 'J', u'今日は'),  # Japanese 
    ('iso8859_5', 'C', u'Здравствуйте'), # Cyrillic 
    ('iso8859_7', 'G', u'Γειά σου'), # Greek 
) 

CODE_TO_ENCODING = dict([(chr(ord(code)-64), encoding) for encoding, code, text in ENCODING_RAW_DATA]) 
EXPECTED_RESULT = u''.join([line[2] for line in ENCODING_RAW_DATA]) 
ENCODED_DATA = ''.join([chr(ord(code)-64) + text.encode(encoding) for encoding, code, text in ENCODING_RAW_DATA]) 

FIND_RE = re.compile('[\x00-\x1A][^\x00-\x1A]*') 

def decode_single(bytes): 
    return bytes[1:].decode(CODE_TO_ENCODING[bytes[0]]) 

result = u''.join([decode_single(bytes) for bytes in FIND_RE.findall(ENCODED_DATA)]) 

assert result==EXPECTED_RESULT, u"Expected %s, but got %s" % (EXPECTED_RESULT, result) 
Các vấn đề liên quan