2013-03-04 2 views
2

여러 종류의 이진 데이터가 들어있는 파일이 있는데이 파일을 처리 할 모듈을 작성하고 있습니다. 2 바이트 빅 엔디안하고 문자열 (I는 struct.unpack()를 파싱하여) stringLength :이진 파일에서 UTF-8 문자열 읽기

다른 사이에, 다음과 같은 형식 UTF-8 인코딩 된 스트링을 포함한다. UTF-8이기 때문에 문자열의 바이트 길이가 stringLength 이상일 수 있으며 문자열에 멀티 바이트 문자가 포함되어 있으면 read (stringLength)가 짧아집니다. (다른 모든 데이터를 파일).

은 어떻게 UTF-8의 멀티 바이트의 특성을 인식하고, 파일에서 N UTF-8 문자 (N 바이트 구별)를 읽을 수 있습니까? 나는 30 분 동안 인터넷 검색을했는데 내가 찾은 모든 결과는 관련이 없거나 내가 할 수없는 가정을합니다.

+0

당신이 stringLength 문자가 아닌 바이트 확신이 있습니까? –

+0

와우, 정말 끔찍한 * 형식이 될 것입니다. 데이터를 이미 문자열이나 일종의 목록으로 읽었습니까? UTF-8 바이트는 문자를 만들기 위해 따라야 할 바이트 수를 결정하기에 충분히 쉽게 검사 할 수 있지만 이러한 문자 별 문자를 처리해야합니다. –

+0

@GrahamBorland 100 %? 아니요. 실제로 멀티 바이트 문자를 사용하는 파일을 아직 찾지 못했습니다. 그러나이 경우에 대한 스펙을 해석하는 것이 좋습니다. – Surma

답변

4

는 파일 객체를 감안할 때, 문자의 수는, 당신은 사용할 수 있습니다 테스트의

# build a table mapping lead byte to expected follow-byte count 
# bytes 00-BF have 0 follow bytes, F5-FF is not legal UTF8 
# C0-DF: 1, E0-EF: 2 and F0-F4: 3 follow bytes. 
# leave F5-FF set to 0 to minimize reading broken data. 
_lead_byte_to_count = [] 
for i in range(256): 
    _lead_byte_to_count.append(
     1 + (i >= 0xe0) + (i >= 0xf0) if 0xbf < i < 0xf5 else 0) 

def readUTF8(f, count): 
    """Read `count` UTF-8 bytes from file `f`, return as unicode""" 
    # Assumes UTF-8 data is valid; leaves it up to the `.decode()` call to validate 
    res = [] 
    while count: 
     count -= 1 
     lead = f.read(1) 
     res.append(lead) 
     readcount = _lead_byte_to_count[ord(lead)] 
     if readcount: 
      res.append(f.read(readcount)) 
    return (''.join(res)).decode('utf8') 

결과 :

>>> test = StringIO(u'This is a test containing Unicode data: \ua000'.encode('utf8')) 
>>> readUTF8(test, 41) 
u'This is a test containing Unicode data: \ua000' 
+0

이것은 * 정확하게 * 찾고있는 것입니다. 받아 들여지고 upvoted. StackOverflow 프로필을 링크 할 때 해당 섹션의 속성을 설명하면 충분합니까? – Surma

+0

@Surma : 물론입니다; 이 사이트의 모든 컨텐츠는 CC-wiki (오른쪽 하단 참조)로 라이센스되었지만 readcount 'function'은 [간단한 C 매크로] (http://www.icu-project.org/apiref/icu4c/utf8_8h_source)에서 채택되었습니다. html), 그래서 너무 재사용했다. :-) 당신이 기본 바이트 형식을 이해하면 이것은 모두 간단한 일입니다. –

+0

@Surma : 'readcount'값을 결정하는 더 많은 방법이 있습니다. 심지어 내가 여기 사용한 것보다 더 빠를 수도 있습니다. 이것은 바이트 당 2와 4 (단순) 테스트를 사용합니다. –

0

UTF-8의 한 문자는 1byte, 2bytes, 3byte3 일 수 있습니다.

바이트 단위로 파일을 읽어야하는 경우 UTF-8 인코딩 규칙을 따라야합니다. http://en.wikipedia.org/wiki/UTF-8

대부분의 경우 인코딩을 utf-8로 설정하고 입력 스트림을 읽을 수 있습니다.

읽은 바이트 수를 신경 쓸 필요가 없습니다.

+0

나는 입력 스트림 인코딩을 설정하고,'codecs' 모듈에서 문서를 얻었습니다. 이것이 올바르게 이해되면 다음과 같이 할 수 있습니다 : 'strLen = struct.unpack ('> h, f.read (2)) utfStream = codecs.open (f,'r ','utf-8 ') string = utfStream.read (strLen)' 하나의 질문 : 파일 기술자에서 포인터를 앞으로 이동 시켜서'f'의 후속'read()'가 문자열 * 뒤에 * 바이트를 반환하도록 할 것인가? 그냥 읽은거야? 편집 : 코드 예제의 개행은 어디로 갔습니까? – Surma