2017-10-21 6 views
0

이것은 아마도 미세 최적화 일지 모르지만 주어진 바이트 스트림이 통과 할 때 유효한 UTF-8인지 확인하고 싶습니다. 내 응용 프로그램이지만, 결과 디코딩 된 코드 포인트를 유지하고 싶지는 않습니다. 다시 말하면, 내가 large_string.decode('utf-8')으로 전화를 걸면 인코딩이 성공했다고 가정하고 디코딩에 의해 반환 된 유니 코드 문자열을 유지하고 싶지 않으며 메모리를 낭비하지 않기를 원합니다.바이트 스트림이 유효하지 않은 경우 UTF-8 (또는 다른 인코딩)없이 복사

한 번에 몇 바이트를 읽은 다음 decode()을 시도한 다음 decode()이 성공할 때까지 더 많은 바이트를 추가합니다 (또는 한 문자의 최대 바이트 수를 초과했습니다. 인코딩). 그러나 ISTM은 기존의 디코더를 단순히 디코딩 된 유니 코드 문자를 버리고 내 자신을 굴릴 필요가없는 방식으로 사용할 수 있어야합니다. 하지만 즉시 stdlib 문서를 수색하는 것에 신경 쓰지는 않습니다.

utf8_decoder = codecs.getincrementaldecoder('utf8')() 

이것은 IncrementalDecoder() instance입니다 :

+0

유효한 멀티 바이트 trf8 인코딩 된 문자를 한 쌍으로 나누지 않는 방식으로 긴 문자열/스트림을 "청크"로 나눌 수 있습니까? – martineau

답변

2

당신은 codecs module에서 제공하는 증가 디코더를 사용할 수 있습니다. 그런 다음 순서이 디코더 데이터를 공급 및 스트림 유효성을 검사 할 수 있습니다 : (마이너스 부분 멀티 바이트 시퀀스를

# for each partial chunk of data: 
    try: 
     utf8_decoder.decode(chunk) 
    except UnicodeDecodeError: 
     # invalid data 

디코더는 데이터 지금까지 디코딩 반환을, 사람들은 당신이 해독 다음 시간 동안 상태로 유지된다 청크). 작은 문자열은 생성하고 삭제하기가 저렴합니다. 여기서 큰 문자열을 만들지는 않습니다.

UTF-8은 가변 바이트 수를 사용하기 때문에 위의 루프 부분 데이터를 입력 할 수 없습니다. 부분 청크는 처음에 유효하지 않은 데이터를 가지기 쉽습니다.

처음부터 유효하지 않으면 일 수 있습니다.은 최대 세 개의 연속 바이트로 시작됩니다. 당신 만 제거 할 수 그 첫째 :

당신은 또한 더 같은 이진 테스트를 사용하여 파이썬 코드에서 완전히 스트림을 확인할 수 있도록 지금
first_chunk = b'....' 
for _ in range(3): 
    if first_chunk[0] & 0xc0 == 0x80: 
     # remove continuation byte 
     first_chunk = first_chunk[1:] 

는, UTF-8은 충분히 구성되어 있습니다,하지만 당신은 단순히 일치하지 않을 수 있습니다 내장 디코더가 디코딩 할 수있는 속도.

+0

'utf8_decoder.decode (청크)'는 결과로 디코딩 된 객체 (여러분의 코드에서는 무시)를 디코딩하고 반환합니다. 'string.decode ('utf-8')'을 사용하고 반환 값을 무시하는 것보다 ("try/except"과정에서) 더 나은 방법은 없을까요? – martineau

+0

@martineau : 부분 데이터를 전달할 수 있기 때문에 결과를 무시합니다. 디코더는 다음 부분 블록을 처리 할 수있는 상태를 유지합니다. –

+0

@martineau : 부분 디코드가 * 작습니다. –