다국어 프로그래밍에서 흔히 범하는 실수

특히나 영/미권에서 제작된 프로그램에서 자주 보이는 실수인데 – 그렇다고 다국어 프로그래밍을 좀 해야되는 한국의 프로그래머들이 범하지 않는 것도 아니다 – ASCII나  Latin1 인코딩이 아닌 이상 글자 수 ≠ 바이트 수 라는 것.

wp_utf8 캡쳐된 화면은 WordPress.com 에서 제공해주는 통계 기능 중 일부인데, 마지막 행의 title 항목을 보면 좀 이상한 것을 찾아 볼 수 있다.

Title 항목의 경우 원래 포스팅 제목부분이 일정 길이보다 길면 적당히 잘라서 출력되는데, 마지막 행의 경우 잘린 부분이 이상한 곳이었다. (원본의 문자열은 “게임을 만든다는 것, 문화를 만든다는 것”임)

즉 단순히 strlen 같이 바이트 수를 세는 함수로 문자열 길이를 구하고 한 문자의 중간에서 잘라버리면 저렇게 알 수 없는 문자가 마지막에 출력되게 된다. 마지막 문자나 잘라붙인 (다국어문자인) 중간 문자가 이상하게 보이면 일단 이걸 의심하자.

WordPress.com 에서 제공해주는 통계 기능인 관계로 (그럼에도 불구하고 설치형 WordPress에서 사용 가능하다), 버그를 재현할 수 없으니 잡을 수 없지 않은가 :D 그런 의미에서 PHP로 재현을 해보자 (WP가 PHP기반).

<?php
header( “Content-Type: text/plain; charset=UTF-8” );
$str = “게임을 만든다는 것, 문화를 만든다는 것”;
echo “원본: “.$str.”\r\n”;
for( $i = 38; $i < 43; ++$i )
    echo “substr[0:$i] => “.substr( $str, 0, $i ).”\r\n”;
?>

대충 40bytes 로 자르는 것 같지만, 일단 테스트(…) 해보니 40 bytes가 맞다. 대충 화면 출력은 이런 식으로 나왔다.

원본: 게임을 만든다는 것, 문화를 만든다는 것
substr[0:38] => 게임을 만든다는 것, 문화를
substr[0:39] => 게임을 만든다는 것, 문화를 �
substr[0:40] => 게임을 만든다는 것, 문화를 �
substr[0:41] => 게임을 만든다는 것, 문화를 만
substr[0:42] => 게임을 만든다는 것, 문화를 만�

( � 가 깨진 문자임 )

이걸 어떻게 수정하면 될까? (물론 반영은 못하지만 :D ) 원래 저런 류의 제한을 가하는 목적은 2가지인데, 하나가 요약된 항목 저장을 위해서 용량을 제한하는 것이고, 다른 하나는 화면 출력 길이를 조절하기 위해서 폭을 제한하는 것이다. 일단 첫번째를 가정하고 수정하려면, PHP의 인코딩을 알고 문자열을 자르는 함수인 mb_strcut을 쓰면 된다. WP의 인코딩인 UTF-8을 넣어서 사용하면 다음과 같이 잘린다.

echo mb_strcut( $str, 0, 40 );

결과: 게임을 만든다는 것, 문화를

물론 PHP처럼 이런 함수가 어디에나 있는 것은 아니니 함수를 새로 짜보면 이런 구조가 될 것이다. UTF-8의 경우 각 문자의 첫번째 바이트가 아니면 비트 패턴이 항상 10으로 시작을 한다. 이걸 이용해서 비트 패턴이 10이 아닐 때까지 앞으로 가게하면,

function utf8cut( $s, $len )
{
    assert( strlen($s) > $len ); // 길이 문제는 신경 안쓰기로
    $pos = $len – 1;
    while( (ord($s[$pos]) & 0xc0 ) == 0x80 ) // 맨 앞 두 비트만 잘라내서 10 으로 시작하나 확인
        $pos -= 1;
    return substr( $s, 0, $pos );
}

이런 형태의 함수가 나온다. 약간 고치면 C/C++에서도 사용할 수 있다. 약간 방식을 바꾸면 길이 구하는데도 활용할 수 있다. 답을 아는 사람은 댓글을 달아도 :)

ps. 출력 폭을 의미하는 경우에는 다음 기회에  포스팅을 하기로 한다(…)

Published by

rein

나는 ...

One thought on “다국어 프로그래밍에서 흔히 범하는 실수”

Leave a Reply