perl 로, 인코딩에 관계없이 문자열을 두 개의 문자열로 나누는 코드

raymundo의 이미지

일단 결론부터 말씀드리면, "구현은 했는데, 펄 모듈 버전이 낮은 경우에도 통하게 하고 싶다"입니다.

...

어떤 스트링이 있는데, 이 스트링은 EUC-KR로 인코딩되어 있을수도 있고 UTF-8로 인코딩되어 있을 수도 있습니다. (그 외의 다른 것일수도)

이걸 앞에서부터 원하는 갯수만큼 글자를 세어서 뽑아내는 식으로 하여서 두 개의 스트링으로 나누고 싶습니다.

$str = "안녕하세요";
($a, $b) = &split_string($str, 2);    # $a = "안녕" $b = "하세요"
$str = "Hello";
($a, $b) = &split_string($str, 2);    # $a = "He" $b = "llo"

인코딩이 뭐냐, 무슨 문자냐에 따라 문자마다 바이트 수가 달라지니까, 바이트 단위로 쪼개는 건 힘들겠다 싶었고요, perldoc 뒤지고 웹 뒤지고 테스트 코드 짜서 실행해보고 하면서 알아낸 것들을 조합하니 다음과 같이 해결책이 나오더군요.

1) 일단 스트링을 펄의 유니코드 표현 (예를 들어 "가"는 "\x{AC00}")으로 바꾼다.
2) 이렇게 바뀐 스트링은, 정규표현식에서 "."가 바이트가 아니라 문자 하나를 의미하는 걸로 취급된다.
3) 따라서 아주 쉽게 원하는 글자만큼 잘라낼 수 있다. (만세)
4) 잘라낸 두 문자열을 다시 원래의 인코딩으로 바꾼다.

그래서 아래와 같이 짰습니다.

# $str - 쪼갤 스트링
# $length - 앞에서부터의 문자 갯수
# return: (처음 length 길이의 스트링, 나머지 스트링)
sub split_string {
    my ($str, $length) = @_;
 
    # $HttpCharset 은 이 CGI 전반에 걸쳐 사용되는 인코딩입니다. "UTF-8"등이겠죠  
    $str = &convert_encode($str, "$HttpCharset", "unicode");    # 유니코드로 만들고
    my ($first, $last) = ($str =~ /^(.{1,$length})(.*)$/s);     # 분리하고
    $first = &convert_encode($first, "unicode", "$HttpCharset");# 원래 인코딩으로
    $last = &convert_encode($last, "unicode", "$HttpCharset");
 
    return ($first, $last);
}

이 때, 변환에 사용되는 convert_encode는, 웹에서 굴러다니는 걸 가져왔습니다.

# $str 의 인코딩을 $from 에서 $to 로 컨버트
sub convert_encode {
    my ($str, $from, $to) = @_;
 
    eval { require Encode; };
    unless($@) {
        $str = Encode::encode($to, Encode::decode($from, $str));
    } else {
        eval { require Text::Iconv; };
        unless($@) {
            my $converter = Text::Iconv->new($from, $to);
            $str = $converter->convert($str);
        }
    }
    return $str;
}

즉 Encode 모듈이 있으면 그걸 먼저 쓰고, 없으면 Text::Iconv 모듈을 쓰고, 그것도 없으면 못하는 거고...

이게 제가 홈페이지 돌리는 계정의 서버에서는 잘 돌아갔는데, 다른 서버에서 해보니 펄 모듈에 따라 좀 문제가 있더군요.

첫째, Encode 모듈이 버전이 낮을 때는 "unicode"라는 인코딩 명칭을 Unknown 어쩌고 하면서 죽었습니다.

둘째, Encode 모듈이 아예 없어서 Text::Iconv 를 사용할 경우 (CPAN 가장 최신 버전 1.4의 경우라도) "unicode"라는 인코딩이 없는 것인지 오동작을 하더군요. 좀 더 정확히 얘기하면, $str 을 utf-8 => unicode 로 한번 변환하고 그 결과를 바로 unicode => utf-8 로 변환시키면 제대로 utf-8로 나오는데, 중간에 쪼개고 쪼갠 걸 각각 변환할 경우 널스트링이 되어 버렸습니다.

사실 애초에 "unicode"라는 인코딩 명 자체가 좀 문제가 있지 싶은데, 첨에 혹시나 하면서 써봤더니만 잘 되길래... =.=;;;;

...

웬만하면 Encode 나 Text::Iconv 중에 하나만 있더라도, 그리고 그 버전이 (아주 낮으면 어쩔수 없겠지만) 아주 최신이 아니어도 통하게 할 만한 여지가 있을까요? (아니면 애초에 저런 컨버트 없이 문자열을 쪼갤 수 있으면 그것도 좋겠습니다만, 쪼개기 말고도 유니코드 표현을 사용해야 할 곳이 좀 있어서 저 컨버트가 제대로 되는 것이 더 기쁘겠습니다.)

aero의 이미지

코드를 보니깐요

convert_encode($str, "$HttpCharset", "unicode"); 

부분에서 목적 인코딩을 "unicode"로 지정해주셨는데
Encode 모듈에 각종 인코딩에 대한 정의가 있는 파일이
Encode/ 디렉토리 아래 Config.pm, Alias.pm, Unicode.pm 등이 있는데
저런 인코딩은 아마 perl에 정의 되어있지 않을겁니다.
에러가 나지 않았다면 버젼에 따른 예외 처리에 의해 암묵적으로 그냥 넘어가 버리거나
내부적으로 임의적으로 처리되어 버렸을 수 도 있고요...

UTF같은 가변길이 인코딩이 아닌 고정폭 유니코드 인코딩을 사용하려면
ucs-2be, ucs-2le, ucs-4be, ucs-4le 같은 인코딩을 사용하시면 될 것 같네요.
(위에서 be는 big endian, le는 little endian을 뜻합니다.)

raymundo의 이미지

ucs-2... 를 사용할까 했는데, 이건 endian 에 두개씩 있잖습니까? 이걸 서버 플랫폼에 관계없이 쓸 수 있는건지 몰라서요. (perldoc 을 읽어도 도대체 이해도 안되고 =.=;)

어차피 최종 출력은 다시 EUC-KR이나 UTF-8등으로 나올테니 상관없지 싶으면서도...

좋은 하루 되세요!

aero의 이미지

ucs 인코딩의 바이트 순서는 변환시 perl이 다 자동으로 detect해서
해줄겁니다. 위처럼 utf-8 -> ucs -> utf-8 으로 변환하는것이면
더욱더 걱정 할 필요 없겠네요. ucs 부분은 처리절차에 있어 일종의 블랙박스 이니깐요.

raymundo의 이미지

머리가 나쁘니 손발이라도 고생하자고, 일일이 다 바꿔가면서 테스트해봤습니다..

Encode 모듈은 제가 에라 모르겠다 하고 루트 권한으로 cpan 실행시켜서 업로드하는 바람에, 구버전 테스트는 더 못하겠고요... -_-;;;

일단, split_string 에서 중간에 정규표현식을 사용하여 쪼개는 과정을 생략하고, 단지 utf-8 -> 어떤 인코딩 -> utf-8 로 돌리는 것은 웬만하면 다 됩니다. "어떤 인코딩"이 UCS-2, UTF-16, UTF-32, 여기에 각각 BE, LE 붙여가며 해 봤는데, Encode 모듈과 Text::Iconv 모듈 다 스트링이 원래의 것으로 잘 나오더군요.

그런데 정규 표현식을 써서 쪼개기를 하려면, 제대로 쪼개지질 않더군요. 어떤 인코딩을 뭘로 지정해도...

이런 인코딩들의 경우는 정규표현식의 "."이 여전히 "1바이트"를 의미한다고 생각하고, $length 값을 2배로 곱해서 처리하게 했더니 그제서야 제대로 쪼개집니다.

아래의 표는 각각의 인코딩 이름을 두 개의 모듈을 써서, 한글 스트링, 일본어 스트링, 그리고 위키페디아에서 적당히 복사해 온 정체모를 언어 스트링을 split_string($str, 2) 를 거치게 했을 때의 결과입니다. (딱히 언어에 따라 다른 결과가 나오지는 않았습니다)

                Encode모듈        Text::Iconv모듈
UCS-2           ok                ok
UCS-2BE         ok                ok
UCS-2LE         ok                ok
UTF-16          error(주1)        error(주5)
UTF-16BE        ok                ok
UTF-16LE        ok                ok
UTF-32(주2)     error(주3)        error(주6)
UTF-32BE        ok                ok
UTF-32LE        ok                ok
UTF-8           error(주4)        error(주7)
 
* 주1) UTF-16:Unrecognised BOM b098 at /usr/lib/perl5/5.8.5/i386-linux-thread-multi/Encode.pm line 162
 
* 주2) $lengh 값을 4배 곱한 후 처리
 
* 주3) 주1과 같은 에러, 명칭만 UTF-32 로 나옴 (utf-16과 utf-32의 경우는 스트링 앞에 바이트오더를 알려주는 BOM이란 게 붙는다는 설명으로 보아, 스트링을 둘로 쪼갠 후에 뒷쪽 부분에는 그 BOM이 안 붙은 상태라서 이렇게 되는듯
 
* 주4) 문자들마다 바이트 수가 다르므로, 제대로 쪼개지지 않음.
 
* 주5) split_string 에 인자로 준 숫자보다 하나 적은 수의 문자를 세어서 쪼갬.(쪼갤 때 BOM도 두 바이트를 차지하기 때문인듯)
 
* 주6) 주5)와 동일
 
* 주7) 아예 결과가 ("", "") 으로 나옴

흐... 스무 가지 경우를 다 봤는데, 결국 UCS-2나 UTF-16BE, 또는 UTF-16LE 를 중간에 거치게 하고, (UCS-2와 UTF-16의 차이는 또 무슨 Surrogate Pair란 게 있고 없고 차이라는데 뭔 소린지 모르겠고 ㅠ,.ㅠ), 이제는 모든 글자가 2바이트란 게 보장이 되니 정규표현식이나 substr() 함수를 사용해서 "원하는 글자갯수*2"만큼 앞에서 끊으면 저 split_string()은 제대로 돌아가겠다는 생각이 듭니다.

-------------------------

여기서부터는 여담:

그런데 이 해결책에도 문제가 있는 것이, 제가 작성하는 코드 다른 곳에는 이런 게 있거든요...

# Korean
    my $i_korean =      # "가" "나" ... "하" 를 유니코드 번호로 표현
        "\x{AC00} \x{B098} \x{B2E4} \x{B77C} \x{B9C8} \x{BC14} ".
        "\x{C0AC} \x{C544} \x{C790} \x{CC28} \x{CE74} \x{D0C0} ".
        "\x{D30C} \x{D558}";
# Japanese
    my $i_japanese =    # "ぁ" "ァ"
        "\x{3041} \x{30A1}";

$i_korean 에는 "가 나 다 라 마 ... 하" 가 들어있고, 이걸 웹페이지 인코딩(EUC-KR또는 UTF-8)에 따라서 변환해서 사용(출력할 때도 쓰고, 다른 스트링이 어느 인덱스에 속할지 - 예를 들어 "홍길동"은 "하", "리눅스"는 "라" - 판단할 때도 씀)하는데, 그 변환은 오직 "unicode"->euc-kr(또는 utf-8)로밖에 안 된다는 거죠. ㅠ,.ㅠ

저 걸 억지로 UCS-2->utf-8 변환을 시켜봤자 Encode 모듈은 "Wide character in subroutine entry at ..."하는 에러를 내고, Text::Iconv 모듈은 그냥 널스트링을 반환하더군요.

펄 소스 코드 내에서 UCS-2나 UTF-16BE로 인코딩된 문자열을 하드코딩하는 방법은? 펄 소스 자체를 그 인코딩으로 작성을 하거나 -_-;; 아니면 그냥 $i_korean = "가 나 다 ... 하"라고 코딩하고 소스를 UTF-8로 인코딩해 저장한 다음, $i_korean을 utf-8 -> UCS-2 로 일단 변환해서 사용하든지 해야겠네요. 이건 이거대로 점점 더 배가 산으로 간다는 느낌이네요. OTL

그냥, "Encode 모듈 쓰세요, 서버에 없으면 개인 계정에 깔든가 서버 관리자 또는 업체에 깔아 달라고 하세요"라고 하고 그냥 "unicode"라는 인코딩 이름을 쓰는게 제일 낫지 싶기도 합니다. ㅠ,.ㅠ

좋은 하루 되세요!

raymundo의 이미지

맘 잡고 찬찬히 읽어봤습니다. 옛날에 읽을 때는 뭔 소린지 모르겠던데 이 문제 때문에 이리 저리 삽질한 후에 읽으니 좀 알겠더군요.

제가 "unicode"라는 명칭을 사용해서 변환한 것은 결국 "Perl's internal form"으로 변환한 거고, 그럼 굳이 "unicode"라는 이름을 쓰지 않더라도

use Encode;
 
$str = decode($from, $str);  # $from 은 UTF-8이나 EUC-KR

라고만 적어줘도 되겠고, 그러면 Encode의 버전이 좀 낮아도 통하지 않을까..라고 희망합니다. (그러나 어차피 저 개념이 5.6? 아니면 5.8? 부터 생긴 것 같으니, 그보다 이전 버전이라면 여전히 안 될 지도)

마찬가지로 내부 표현에서 다시 웹 페이지 출력용으로 바꿀때도

$str = encode($to, $str);

해주면 될 것 같고요.

...

문제는 Encode 모듈이 없어서 Text::Iconv 모듈을 쓰는 경우인데, 가장 최신 버전( http://search.cpan.org/dist/Text-Iconv/ )이 2004년 중순이라... 모듈을 고쳐 주지 않는 이상은 대책이 없어 보이네요.

좋은 하루 되세요!

keedi의 이미지

대충 모듈을 보았는데 Text::Iconv의 경우 시스템의 iconv 라이브러리에 대한 래핑이라 모듈을 고칠 것은 거의 없지 않나 조심스레 추측됩니다. (아닐수도 있습니다만...)

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

----
use perl;

Keedi Kim

raymundo의 이미지

keedi님 안녕하세요 ^^ 제 홈에 댓글 감사합니다.

말씀하신 것처럼 (그리고 저도 펄매니아 쪽에 적었습니다만) Text::Iconv 는 시스템의 iconv(3)와 관련이 있는 것 같더군요.

그런데 iconv(1) 프로그램을 --list 옵션으로 지원하는 코드셋을 뽑아보면 "UNICODE"란게 있는데, 이게 뭔지 알아볼 겸 해서 텍스트 파일 하나를 iconv(1) 를 사용해서 UTF-8에서 UNICODE로 변환한 후 vi로 읽었더니만 (vi는 자동 컨버팅이 되니까) 이걸 "UCS-2LE"로 인식하더군요. 아래 정리한 것과 비교하면, 정확히는 "UTF-16LE"로 변환한 것과 동일하게 저장했습니다. (앞에 BOM까지 붙인 상태)

....

아예 모든 경우의 수를 따져서 각각의 인코딩된 스트링을 파일에다가 작성하고, hexdump 로 파일을 구경해봤습니다. =.=;; 뭔가 계속 어긋나는 것 같아서...

(여기서부터는 뭐... 딱히 댓글이라기보다는, 저도 좀 정리할 필요가 있다보니... ^^; 다 읽으실 필요는 없을 듯)

use Encode;
 
$str = "\x{ac00}\x{b098}";  # "가나" in unicode
open OUT, ">out_unicode.txt"; print OUT "$str\n"; close OUT;

별도의 인코딩 없이 저 유니코드 표현을 그대로 파일에 찍으면 UTF-8로 출력하더군요.

$ hexdump out_unicode.txt
0000000 b0ea eb80 9882 000a       <- 가 %EA%B0%80 나 %EB%82%98 그런데 두 바이트씩 끊은 후 little endian 으로 저장한 듯
0000007

그 다음은, 온갖 인코딩을 바꿔가면서 파일에 저장 =.=;;

# Encode 모듈의 경우는, 저 펄의 유니코드 표현을 아래의 각 이름별로 encode에 넣은 후 출력
for $enc qw(EUC-KR UCS-2 UCS-2BE UCS-2LE UTF-16 UTF-16BE UTF-16LE UTF-32BE UTF-32LE UTF-8) {
    $str2 = encode($enc, $str);
    open OUT, ">out_$enc.txt"; print OUT "$str2\n"; close OUT;
}
 
# Text::Iconv 의 경우는, 펄의 내부 표현을 나타내는 이름이 뭔지 모르기 때문에
# 일단 utf-8 스트링을 지정한 후 그걸 아래의 각 이름별로 utf-8 -> $enc 변환
$str = "가나";
for $enc qw(EUC-KR UCS-2 UCS-2BE UCS-2LE UTF-16 UTF-16BE UTF-16LE UTF-32BE UTF-32LE UTF-8 UNICODE) {
    $converter = Text::Iconv->new("UTF-8", "$enc");
    $str2 = $converter->convert($str);
    open OUT, ">conv_$enc.txt"; print OUT "$str2\n"; close OUT;
}

결과는

Encode()를 사용하여                      Text::Iconv()를 사용하여
펄 내부 표현을 각각의 인코딩으로 변환    UTF-8 스트링을 각각의 인코딩으로 변환
 
--------------------------------------------------------------------
out_EUC-KR.txt                           conv_EUC-KR.txt
0000000 a1b0 aab3 000a                   0000000 a1b0 aab3 000a
0000005                                  0000005
(가 %B0%A1 나 %B3%AA 인데 두 바이트씩 순서가 바뀌어 저장)
 
--------------------------------------------------------------------
out_UCS-2.txt                            conv_UCS-2.txt
0000000 00ac 98b0 000a                   0000000 ac00 b098 000a
0000005                                  0000005
(둘이 다르다! Encode에서는 UCS-2BE로, Text::Iconv는 LE로 저장했음)
 
(파일이 저장되면서 두 바이트씩 바이트 순서가 바뀌어 저장되는지,
눈으로 봤을때는 좌측이 LE처럼 보임 =.=;)
 
--------------------------------------------------------------------
out_UCS-2BE.txt                          conv_UCS-2BE.txt
0000000 00ac 98b0 000a                   0000000 00ac 98b0 000a
0000005                                  0000005
 
--------------------------------------------------------------------
out_UCS-2LE.txt                          conv_UCS-2LE.txt
0000000 ac00 b098 000a                   0000000 ac00 b098 000a
0000005                                  0000005
 
--------------------------------------------------------------------
out_UTF-16.txt                           conv_UTF-16.txt
0000000 fffe 00ac 98b0 000a              0000000 feff ac00 b098 000a
0000007                                  0000007
(이것도 다르다! Encode는 UTF-16BE로, Text::Iconv는 LE로 저장했음)
 
(BOM 마크가 좀 이상하다... Encode는 BE의 BOM인 0xFeFF 를 앞에 붙이고
그게 파일로 저장되면서 순서가 바뀌었다고 볼 수 있는데, Text::Iconv가
붙인 BOM은 해석이 안 됨. BE의 BOM인 0xFeFF가 순서 바뀜 없이 저장된 거라면
그 뒤의 따라오는 "가나"가 16LE.txt와 동일하게 구성된 것과 상충하고,
LE의 BOM은 0xFFeF 이므로 순서를 바꾸면 ef ff 여야 한다. -_-???)
 
--------------------------------------------------------------------
out_UTF-16BE.txt                         conv_UTF-16BE.txt
0000000 00ac 98b0 000a                   0000000 00ac 98b0 000a
0000005                                  0000005
 
--------------------------------------------------------------------
out_UTF-16LE.txt                         conv_UTF-16LE.txt
0000000 ac00 b098 000a                   0000000 ac00 b098 000a
0000005                                  0000005
 
--------------------------------------------------------------------
out_UTF-32BE.txt                         conv_UTF-32BE.txt
0000000 0000 00ac 0000 98b0 000a         0000000 0000 00ac 0000 98b0 000a
0000009                                  0000009
 
--------------------------------------------------------------------
out_UTF-32LE.txt                         conv_UTF-32LE.txt
0000000 ac00 0000 b098 0000 000a         0000000 ac00 0000 b098 0000 000a
0000009                                  0000009
 
--------------------------------------------------------------------
out_UTF-8.txt                            conv_UTF-8.txt
0000000 b0ea eb80 9882 000a              0000000 b0ea eb80 9882 000a
0000007                                  0000007
 
--------------------------------------------------------------------
* 이건 좀 특별한 케이스
 
out_unicode.txt                          conv_UNICODE.txt
0000000 b0ea eb80 9882 000a              0000000 feff ac00 b098 000a
0000007                                  0000007
 
(Encode의 경우는 \x{ac00}\{b098}을 그대로 출력했더니 UTF-8과 동일하게
저장됐고, Text::Iconv 의 경우는 "UTF-8"을 "UNICODE"로 변환시켰더니만
UTF-16과 동일하게 저장됐음)

보는 바와 같이,

1) 엔디안까지 정확히 지정하면 상관이 없는데, 지정하지 않았을 경우 Encode의 동작과 iconv의 결과가 달라지고,

2) "unicode"라는 이름은, iconv에서는 "utf-16LE"를 의미했는데 (이건 플랫폼에 따라 BE가 될지도?), Encode에서는 펄 내부의 표현을 의미한다..

라고 생각이 됩니다.

1)번의 문제는 심각하다면 심각한게... 동일한 인코딩 이름 "UCS-2"나 "UTF-16"에 대해서, 두 모듈의 결과가 다르기 때문에...

use Encode;
use Text::Iconv;
 
# Encode 를 사용해서 UTF-8 -> UCS-2 -> UTF-8
$str = "가나다";    # 이건 UTF-8
$str2 = $str;
$str2 = encode("UCS-2", decode("UTF-8", $str2)); # UTF-8 => UCS-2
$str2 = encode("UTF-8", decode("UCS-2", $str2)); # UTF-2 => UTF-8
print (($str eq $str2)?"equal":"not");
print "[$str2]\n";
 
# Text::Iconv 를 사용해서
$str = "가나다";    # 이건 UTF-8
$str2 = $str;
$converter1 = Text::Iconv->new("UTF-8", "UCS-2");
$str2 = $converter1->convert($str2);            # UTF-8 => UCS-2
$converter2 = Text::Iconv->new("UCS-2", "UTF-8");
$str2 = $converter2->convert($str2);            # UCS-2 => UTF-8
print (($str eq $str2)?"equal":"not");
print "[$str2]\n";
 
# 이번에는 섞어서
$str = "가나다";    # 이건 UTF-8
$str2 = $str;
$str2 = encode("UCS-2", decode("UTF-8", $str2)); # UTF-8 => UCS-2
$converter2 = Text::Iconv->new("UCS-2", "UTF-8");
$str2 = $converter2->convert($str2);            # UCS-2 => UTF-8
print (($str eq $str2)?"equal":"not");
print "[$str2]\n";

위와 같이 UTf-8 => UCS-2 => UTF-8 로 변환하면 원래의 스트링이 되어야 하지만, 첫 변환과 두번째 변환을 서로 다른 모듈이 맡았다면 제대로 되지 않습니다.

equal[가나다]
equal[가나다]
not[¬颰]

으음 첩첩산중이네요. 일단 여기까지 정리를...

좋은 하루 되세요!

keedi의 이미지

raymundo님께서 많은 부분을 언급하고 계셔서, 흠...
아래 코드의 결과가 기대하신 것인지는 잘 모르겠습니다만...
다만 저도 정보 추가의 목적으로... :-)

일단 마지막 정리 부분에 대해서 말씀드리면, 엔디안 문제가 아닐까 합니다. (추측추측...)
raymundo님의 코드로 제가 테스트를 해보았는데 저는 UCS-2가 아니라 UCS-2LE, UCS-2BE
두 가지를 사용해보았습니다. 섞어서 사용해도 원하는 결과가 나왔습니다.
물론 UCS-2를 사용하니 raymundo님 말씀처럼 깨져서 나오더군요.

저는 우분투 Edgy, 로컬 설정은 UTF-8 입니다.
아래의 코드에서 보시면 Text::Iconv와 Encode를 섞어서 사용했는데 정상적으로 잘 동작합니다. :-)

#!/usr/bin/perl -w
 
use strict;
use warnings;
 
use Encode qw(encode decode);
use Text::Iconv;
 
use constant TEST_STRING => "가나다";
 
use constant ENCODE1 => "UTF-8";
use constant ENCODE2 => "UCS-2LE";
 
my $str = TEST_STRING;
my $test_str;
my $converter_enc1_enc2 = Text::Iconv->new(ENCODE1, ENCODE2);
my $converter_enc2_enc1 = Text::Iconv->new(ENCODE2, ENCODE1);
 
# Encode를 사용해서
$test_str = $str;
$test_str = encode(ENCODE2, decode(ENCODE1, $test_str));
$test_str = encode(ENCODE1, decode(ENCODE2, $test_str));
print "[$test_str]\n";
 
# Text::Iconv를 사용해서
$test_str = $str;
$test_str = $converter_enc1_enc2->convert($test_str);
$test_str = $converter_enc2_enc1->convert($test_str);
print "[$test_str]\n";
 
# Encode, Text::Iconv 섞어서
$test_str = $str;
$test_str = encode(ENCODE2, decode(ENCODE1, $test_str));
$test_str = $converter_enc2_enc1->convert($test_str);
print "[$test_str]\n";
 
# Text::Iconv, Encode 섞어서
$test_str = $str;
$test_str = $converter_enc1_enc2->convert($test_str);
$test_str = encode(ENCODE1, decode(ENCODE2, $test_str));
print "[$test_str]\n";

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

raymundo의 이미지

번번히 신경써 주셔서 감사합니다 ^^

http://search.cpan.org/~dankogai/Encode-2.18/Unicode/Unicode.pm - perldoc Encode::Unicode

위 문서에 있는 내용에 따르면
UTF-16이나 UTF-32는 뒤에 "BE"또는 "LE"를 생략하면 =>
1) decode의 경우에는 BOM이 있는 지 체크해서 BOM이 있으면 그에 따라 처리하고, 없으면 루틴이 죽는다
2) encode의 경우에는 BE로 인코딩한후 제일 앞에 BE에 해당하는 BOM을 붙인다.

단, UCS-2의 경우는 예외로, 이건 IANA 등에도 등록되어 있으며 UCS-2BE의 alias이다.

라는군요.

iconv 쪽에서는 어느 문서를 봐야 하는지 알수가 없어 못 찾았지만, 저 설명대로라면 UTF-16 이나 UTF-32 는 Encode 모듈은 제 맘대로 BE취급하고 Text::Iconv 는 LE 취급한다 싶군요. 그건 그러려니 하더라도, UCS-2 만큼은 두 모듈이 공히 BE로 처리해줘야 할 텐데 Iconv 쪽은 LE로 처리하는 것이 의아합니다.

뭐 해결은 못해도... 일단 현재 상황은 정확히 알게 되었으니 만족해야겠고...

----

원래의 문제로 돌아와서, 그럼 "UTF-8"스트링을 "펄 내부의 유니코드표현"으로 변환하고 싶다면

즉 "가나"(UTF-8, 6바이트) => "\x{ac00}\x{b098}" (유니코드, 2캐릭터)로 바꾸고 싶다면,

Encode모듈을 쓰면 Encode::decode("UTF-8", $str) 하면 되는데,

Text::Iconv 모듈을 쓰면 Text::Iconv->new("UTF-8", "????"); # 저 물음표 자리에 뭐라고 적어주면 되는 걸까? 아니면 불가능한 걸까?

라는 것의 답만 알면 되겠습니다. 이건 아무래도 영어권 사이트에도 질문을 올려봐야지 싶은데요, 제일 확실하게 알 만한 사람(펄 언어 개발자 진영이라던가...)들이 질문을 봐 줄 만한 사이트가 어딜까요? ^^;;;

좋은 하루 되세요!

keedi의 이미지

Quote:

원래의 문제로 돌아와서, 그럼 "UTF-8"스트링을 "펄 내부의 유니코드표현"으로 변환하고 싶다면

즉 "가나"(UTF-8, 6바이트) => "\x{ac00}\x{b098}" (유니코드, 2캐릭터)로 바꾸고 싶다면,

Encode모듈을 쓰면 Encode::decode("UTF-8", $str) 하면 되는데,

Text::Iconv 모듈을 쓰면 Text::Iconv->new("UTF-8", "????"); # 저 물음표 자리에 뭐라고 적어주면 되는 걸까? 아니면 불가능한 걸까?

라는 것의 답만 알면 되겠습니다. 이건 아무래도 영어권 사이트에도 질문을 올려봐야지 싶은데요, 제일 확실하게 알 만한 사람(펄 언어 개발자 진영이라던가...)들이 질문을 봐 줄 만한 사이트가 어딜까요? ^^;;;

Raymundo님께서 너무 많은 것들을 고려하고 계셔서 답변하기가 좀 무섭군요... :-)

단편적일 수 있겠지만, 저의 경우 답은 "UTF-8" 입니다. :-)

우선 저는 우분투, Perl 5.8.8, ko_KR.UTF-8 환경에서 테스트 했습니다.
아래 코드 조각에서 보시듯이 변환에 문제가 없었고 Perl 내부에서도 문자열을 처리하는데
아무 문제가 없는 것을 확인했습니다.

 50 # Text::Iconv 두번 사용해서 perl 에서 사용해보기
 51 $test_str = $str;
 52 my $new_converter = Text::Iconv->new("UTF-8", "UTF-8");
 53 $test_str = "테스트Start $test_str 테스트End";
 54 print "[$test_str]\n";

펄도 내부적으로는 UTF-8을 사용하니까 그냥 UTF-8로 변환해주면 아무 문제가 없는 것 같습니다.
아래의 온라인 문서들이 도움이 되지 않을까 합니다. :-)

utf8
encoding

P.S.

1.
GTK2-Perl을 이용해서 프로그램을 작성하실 때 모듈 사용 전 아래의 코드를 넣어주시지 않으면
한글을 사용하는 어플리케이션에서는 깨지는 경우가 있답니다. 이런 것들도 다 위의 여러가지
것들과 맞물려서 이루어지는 것들이라고 생각하고 있습니다.

use encoding "utf-8";

2.
Encode 모듈의 경우 무겁지도 않고 꾸준히 업데이트 되고 있으며, 안정적이니까
서버에 따로 설치해서 사용하는 것도 괜찮은 방법 같습니다.
한글 및 CJK와 관련한 대부분의 모듈은 일본인 CPAN 저자들의 도움을 받네요.
좀 부끄러운 일이죠. ^^a

3.
Raymundo님 덕분에 Text::Iconv를 이제서야 제대로 사용해보네요... :-)

4.
encoding 온라인 문서를 보니까 재미있는 코드가 있네요. 호오라...
간단하게 이야기하면 euc-kr -> utf-8 또는 그 반대 코드가 한줄이면 되는 것이군요. :-)

사용법은 cat input.txt | ./simple_converter > output.txt

  # A simple utf-8 => euc-kr converter
  use encoding "utf8", STDOUT => "euc-kr";  while(<>){print};

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

raymundo의 이미지

번번히 감사드립니다.

>KLDP에 답글을 좀 아까 달았습니다만...
>결국 Text::Iconv도 Text::Iconv->new("UTF-8", "UTF-8") 을 하면 될 것 같습니다. :-)

음, UTF-8 => UTF-8 은 의미가 없겠고, 원래 스트링이 EUC-KR이라면 그 때는 new("EUC-KR",'UTF-8")이 되어서 의미가 있겠지요. 어쨌거나 타겟의 인코딩을 "UTF-8"로 바꿔주면 될 것이라는 말씀이신 거죠?

>Encode::decode의 리턴값과 펄 코드내에서 정규표현식의 "."이 한 바이트가 아닌 한 글자를
>나타내게 하는 것과는 연관이 없는 것으로 기억합니다. decode를 사용했을 경우 제대로 된
>데이터를 생성해주는 것이니 연관이 있다고 해야 하나요? 흠... 말이 좀... ^^;;

이 얘기는 잠시 미루고,

>어쨌든 펄 코드내에서 정규표현식의 "."가 바이트가 아닌 한 글자를 나타내게 하시려면
>그에 맞는 프라그마를 켜주어야 한다는 것,

솔직히 제가 펄을 완전 주먹구구식으로, 홈페이지에 쓰이는 위키를 구미에 맞게 고치기 위해서 소스 보면서 흉내내어서 고치는 수준이다보니... 사실 "프라그마"란게 정확한 의미와 용도를 모르겠습니다. "use utf8;" 을 말씀하시는 거라면, 이건 펄 프로그램 소스 자체가 UTF-8로 저장되어 있다라는 의미 이외에는 사용하지 말라는 식으로 perldoc utf8 에 나와 있어서.. 섣불리 못쓰겠던데요.

>그리고 Text::Iconv도 같은 효과를 낼 수 있다는 것,

"어떻게?"라는 질문을 드려도 될런지 ^^;; 저는 여전히 이해가 잘... 아래 적겠지만 저로서는 use utf8; 을 해야만 할 것 같더군요.

위에서 잠시 미뤘던 decode() 얘기로 돌아와서...

제가 계속 연연하고 있는,
* "Perl's internal form"
* Encode::decode()
* "\x{ac00}\x{b098}"이라고 하드코딩한 스트링
위 세 가지는 결국 다 똑같이, "UTF-8"인데, 다만 그 스트링에 대해서는 펄이 처리를 할때 "utf8 flag"를 on으로 한 상태인 걸로 생각됩니다. 이 때는 "."="한 글자"가 됩니다.

그러나 우리가 흔히 UTF-8로 저장된 스트링
* 사용자 로케일이 utf-8인 시스템에서 표준 입력으로 넣었거나
* utf-8로 저장된 텍스트 파일을 읽었거나
* utf-8인코딩된 웹페이지의 텍스트 입력폼을 통해 들어왔거나 등등
의 경우에는, 저 flag가 꺼져 있는 듯 하네요. 이 때는 "."="한 바이트"

....

그래서, 또 프라그마가 됐든 컨버전이 됐든 생각할 수 있는 모든 요소를 넣었다 뺐다 하면서 테스트했습니다. (무식하면 손발이라도 열심히! =.=;)

=====================================
실험1) 가장 단순한 경우

# 이 스크립트 자체는 UTF-8로 저장됐습니다.
$str = "가1나2다3";           # 따라서 하드코딩된 이 문자열도 UTF-8
 
for $i (0..9) {
    my ($first, $last) = ($str =~ /^(.{0,$i})(.*)$/);   # 문자열을 $i개만큼의 문자와 나머지로 쪼갬
    print "$i : [$first][$last]\n";
}

출력은

0 : [][가1나2다3]
1 : [▒][▒▒1나2다3]
2 : [▒][▒1나2다3]
3 : [가][1나2다3]          <-- 한글은 3바이트째 읽어야만 한 글자
4 : [가1][나2다3]          <-- 숫자는 1바이트
5 : [가1▒][▒▒2다3]
6 : [가1▒][▒2다3]
7 : [가1나][2다3]
8 : [가1나2][다3]
9 : [가1나2▒][▒▒3]

=====================================
실험2) use utf8; 추가

스크립트 서두에 "use utf8;"을 넣었고 나머지는 동일

Wide character in print at ./test.pl line 14.
0 : [][가1나2다3]
Wide character in print at ./test.pl line 14.
1 : [가][1나2다3]          <-- "."이 한 글자를 의미
Wide character in print at ./test.pl line 14.
2 : [가1][나2다3]
Wide character in print at ./test.pl line 14.
3 : [가1나][2다3]
Wide character in print at ./test.pl line 14.
4 : [가1나2][다3]
Wide character in print at ./test.pl line 14.
5 : [가1나2다][3]
Wide character in print at ./test.pl line 14.
6 : [가1나2다3][]
Wide character in print at ./test.pl line 14.
7 : [가1나2다3][]
Wide character in print at ./test.pl line 14.
8 : [가1나2다3][]
Wide character in print at ./test.pl line 14.
9 : [가1나2다3][]

프라그마를 넣으니 원하는대로 "."이 한 글자를 의미하네요. 즉 UTF-8로 되어 있으면 굳이 Encode::decode()를 쓰지 않아도 되는군요. 그런데 Wide character를 출력한다는 경고가 주루룩 나와서, 저 경고를 안 보려면 "no warnings;"를 넣어주니 되긴 합니다만...

그리고 이건 스크립트 자체가 UTF-8로 저장되어 있으니 되는거고, 만일 스크립트를 EUC-KR로 저장했으면 (당연하겠지만?)

Malformed UTF-8 character (unexpected continuation byte 0xb0, with no preceding start byte) at ./test.pl line 6.

이 에러가 주루룩.

=====================================
실험3)

"use utf8;"대신에 "Encode::_utf8_on()"을 사용

$str = "가1나2다3";
Encode::_utf8_on($str);

이러면 저 $str 변수에 대해 "utf8 flag"가 켜지고, 그러면 실험2) 처럼 "."="한글자"로 처리가 됩니다. 물론 경고도 나오죠.

for $i (0..9) {
    my ($first, $last) = ($str =~ /^(.{0,$i})(.*)$/);
 
Encode::_utf8_off($first);
Encode::_utf8_off($last);
    print "$i : [$first][$last]\n";
}

이렇게 출력하기 전에 $first와 $last에 대해 flag를 꺼 주면 경고없이 출력

0 : [][가1나2다3]
1 : [가][1나2다3]
2 : [가1][나2다3]
3 : [가1나][2다3]

이게 제가 원하는 제일 좋은 출력인데, Encode 모듈의 힘을 또 빌려야 하는군요.

=====================================
실험4)

이번에는 실험1)의 상황에서 Text::Iconv 만 사용해서...

$str = "가1나2다3";
 
$converter = Text::Iconv->new("UTF-8", "UTF-8");
$str = $converter->convert($str);

이것은 결과도 실험1)처럼, "."이 바이트로 처리됩니다.

결국 Text::Iconv 가 그나마 도움이 되는 경우는 $str의 원래 인코딩이 UTF-8이 아닌 경우, (EUC-KR 이겠죠) 일단 UTF-8형태로 만들어 놓고 그 다음 과정을 진행할 때이지 싶습니다.

=====================================

정리하면,

"."가 "한 글자"를 의미하기 위해서는, 피연산자 스트링이 "utf8 flag"가 on이 되어 있어야 하는데, 그러기 위해서

(1) use utf8; 프라그마를 넣는 경우 = 이게... 사실 제 스스로가 아직 저 프라그마의 영향을 정확히 파악하지 못해서 섣불리 넣기가 그렇습니다. 애초에 제가 짠 게 아니라 외국에서 만들어진 위키 프로그램을 고치는 것이다보니, (UseModWiki) 8천 라인이 넘는 프로그램에 수없이 많은 스트링 관련 연산(매칭, 치환 등을 비롯하여)이 있는데 그것들이 다 영향을 받고도 괜찮을지 의문이고요... 방금 슬쩍 넣어봤더니만, 텍스트 파일에서 읽은 데이타에는 여전히 flag가 켜져 있지 않은 겐지 역시나 다른 곳에서 문제가 생기네요.

(2) 필요한 곳에서 Encode::decode()를 쓴 후 연산하고 출력할 때는 다시 encode() 해주는 것

(3) UTF-8로 변환하고 (이 변환은 Text::Iconv를 써서도 할 수 있겠죠), 플래그를 켜기 위해서 Encode::_utf8_on()을 다시 써 주는 것

등의 방법이 있는 것 같네요. 결국 저로서는 Encode 모듈을 쓰든지, 아예 "."="한 글자"라는 희망사항을 포기하고, UCS-2LE 등 "한글 영문 공히 2바이트"인 인코딩으로 변환한후 ".."="2바이트"="한글자"로 취급하여 처리하고 되돌리는 식을 쓰든지 해야겠다는 생각입니다.

...

혹시나 싶어서 comp.lang.perl.misc 뉴스그룹에도 질문을 올려 봤는데요,

http://groups.google.co.kr/group/comp.lang.perl.misc/browse_thread/thread/d2539cff417f1fc4?hl=ko

댓글이 두 개 올라왔는데, "Encode는 웬만한 펄 설치본에는 다 있을거다"와 "5.8로 업글해라"군요... 제가 애초에 이 질문이 생긴 이유가, 제 홈의 소스를 가져가서 쓰시는 다른 분이 utf-8 버전이 잘 안 된다 그래서 그 서버 접속해서 살펴봤더니만 펄5.6에 Encode모듈없는 서버더라고요... 그 분의 문제는 어찌 해결했냐 하면, 업체에 Encode 모듈 설치를 요청했더니만 펄 버전이 낮은 곳이라 안 된다며 아예 다른 머신으로 이전을 해줬더군요. ㅋ~

5.6 이하 버전에서 제가 원하는 걸 하려면 결국 UCS-2LE를 쓰든가 해야 할 듯 합니다.

이거 참 제가 단편적인 지식만 있는 채로 자꾸 질문하고 귀찮게 해드려 죄송했습니다 ^^ 좋은 하루 되세요.

좋은 하루 되세요!

aero의 이미지

실험정신이 대단하십니다.
perl관련 쓰레드가 이렇게 활발한거 보니 보기 좋네요.
저도 이번을 계기로 perl unicode 관련 문서들을 다시 한번 살펴봤는데
조만간에 나름대로 정리해서 올리도록 하겠습니다.

그럼~

keedi의 이미지

역시 유니코드를 제대로 사용하기 위해서는 Perl 5.8 버전대를 사용하는 것은 맞는 것 같습니다. :-) ChangeLog를 봐도 5.7 개발 버전부터 시작해서 유니코드에 대한 지원을 집중적으로 하다가 5.8에 반영이 된 것 같기도 하구요.

Quote:

그러나 우리가 흔히 UTF-8로 저장된 스트링
* 사용자 로케일이 utf-8인 시스템에서 표준 입력으로 넣었거나
* utf-8로 저장된 텍스트 파일을 읽었거나
* utf-8인코딩된 웹페이지의 텍스트 입력폼을 통해 들어왔거나 등등
의 경우에는, 저 flag가 꺼져 있는 듯 하네요. 이 때는 "."="한 바이트"

일단 제가 아는대로 하나씩이라도 정보를 추가해보겠습니다. 위에서 말씀해주신 세가지 부분 중, 적어도 두 가지 부분에 대해서는 확실히 처리해 줄 수 있을 것 같습니다. :-) 먼저 사용자 로케일이 utf-8인 시스템에서 표준 입력으로 넣었거나... utf-8로 저장된 텍스트 파일을 읽을때와 같은 두 경우는 일단 파일 핸들과 표준 입력 파일 핸들을 명시적으로, 그리고 강제로 utf-8로 지정하면 됩니다.

# 이제 열어야 할 파일 핸들은 이렇게...
# lt부등호는 작다 꺽쇠로 넣어주세요. bbcode가 깨지네요.
open(FH, "lt부등호:utf8", "file")
 
# 이미 열어버린 파일 핸들은 이렇게...
binmode(STDIN, ":utf8");

그리고 저도 찾다 보니 또 몰랐던, 그렇지만 유용한 문서를 알게되었습니다. perlunicode와 더불어 perluniintro 문서가 정리가 참 잘되어 있는 것 같습니다. 일단 한번 참조 해보세요~ :-)

그래서 저도 perlunicode를 읽어보았는데 아래와 같은 내용도 있네요. 영어가 짧아서 정말 대충 이야기하면 5.6 대에서는 5.6.1에서 유니코드를 어느정도 제대로 지원을 하지만 정규표현식에서 처리(.이 한 바이트가 아니라 한 글자에 처리하는 것과 같은 문제를 이야기 하는 것이겠죠?)는 완전하지 않다는군요. 하지만 5.8에서는 제대로 지원을 하고 있고 더이상 use utf8 프라그마는 필요 없다는군요(호오!). 하지만 다음과 같은 경우에는 명시적으로 use utf8을 써주면 된다고 합니다. use utf8을 써주면 변수명과 문자열, 정규표현식 문자를 UTF-8 문자로 사용할 수 있다는군요. 하지만 legacy 8비트 데이터가 깨질 수도 있고... 흠...

그래서 바로 use utf8; 을 사용해서 테스트 했는데... 한글 변수명을 사용할 수 있군요... -_-;;; 몰랐습니다.

Quote:

Perl's Unicode Support

Starting from Perl 5.6.0, Perl has had the capacity to handle Unicode natively. Perl 5.8.0, however, is the first recommended release for serious Unicode work. The maintenance release 5.6.1 fixed many of the problems of the initial Unicode implementation, but for example regular expressions still do not work with Unicode in 5.6.1.

Starting from Perl 5.8.0, the use of use utf8 is no longer necessary. In earlier releases the utf8 pragma was used to declare that operations in the current block or file would be Unicode-aware. This model was found to be wrong, or at least clumsy: the "Unicodeness" is now carried with the data, instead of being attached to the operations. Only one case remains where an explicit use utf8 is needed: if your Perl script itself is encoded in UTF-8, you can use UTF-8 in your identifier names, and in string and regular expression literals, by saying use utf8. This is not the default because scripts with legacy 8-bit data in them would break. See utf8.

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

raymundo의 이미지

파일 핸들에 그게... UTF-8, EUC-KR 등 파일의 인코딩을 명시하는가보다라고만 생각했는데, 그 말이 곧 읽어들일때는 펄 내부 유니코드 (utf8이라고 부르죠)로 바꿔준다는 소리네요. 왜 그생각은 못 했을까 =.=;

역시 실험을 아니할 수가 없지요 ㅎㅎ

utf-8.txt, euc-kr.txt, utf-16be.txt 파일 세 개 준비. 내용은 셋 다 "가나다"라는 한 줄.

이걸 읽고 hex 값을 출력시키는 코드는

use Encode;
 
open (FH, "<$file");       # 이 라인을 바꿔 가며 실험
$str = <FH>;
close (FH);
# $str의 hex 값 출력
foreach (split //, $str) {
    printf "%%%04x ", ord($_);
}
print "\n";
# utf8인지 검사
print ((Encode::is_utf8($str))?"utf8":"not utf8");
print "\n";

1. utf-8.txt 를 대상으로

1)

open (FH, "<$file");
 
출력:
%00ea %00b0 %0080 %00eb %0082 %0098 %00eb %008b %00a4 %000a
not utf8

뭐 당연하다면 당연하게... 읽은 그대로 출력

2)

open (FH, "<:utf8", "$file");
 
출력:
%ac00 %b098 %b2e4 %000a
utf8

오호, utf8로 변환이 되었네요.

3)

open (FH, "<:encoding(UTF-8)", "$file");
 
출력:
%ac00 %b098 %b2e4 %000a
utf8

결과는 2)와 같고... 그럼 ":utf8"이라고 쓰는 건 원본이 UTF-8일때만 가능한게 아닐까...라고 생각해 봅니다. (지금 테스트하면서 바로 글 쓰는 거라)

2. euc-kr.txt 를 대상으로

1)

open (FH, "<$file");
 
출력:
%00b0 %00a1 %00b3 %00aa %00b4 %00d9 %000a
not utf8

EUC-KR 바이트 그대로 들어가 있군요. (4자리씩 출력하게 해서 그렇지 사실 %00b0이 한 바이트 %b0)

2)

open (FH, "<:utf8", "$file");
 
출력:
Malformed UTF-8 character (unexpected continuation byte 0xb0, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0xa1, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0xb3, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0xaa, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0xb4, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected non-continuation byte 0x0a, immediately after start byte 0xd9) in ord at ./test.pl line 13.
%0000 %0000 %0000 %0000 %0000 %0000
utf8

에러가 "ord"에서 나고 있습니다. 다음 3)과 비교해서 얘기해보면...

3)

open (FH, "<:encoding(UTF-8)", "$file");
 
출력:
utf8 "\xB0" does not map to Unicode at ./test.pl line 9.
utf8 "\xA1" does not map to Unicode at ./test.pl line 9.
utf8 "\xB3" does not map to Unicode at ./test.pl line 9.
utf8 "\xAA" does not map to Unicode at ./test.pl line 9.
utf8 "\xB4" does not map to Unicode at ./test.pl line 9.
utf8 "\xD9" does not map to Unicode at ./test.pl line 9.
%005c %0078 %0042 %0030 %005c %0078 %0041 %0031 %005c %0078 %0042 %0033 %005c %0078 %0041 %0041 %005c %0078 %0042 %0034 %005c %0078 %0044 %0039 %000a
utf8

어라, 이번에는 9번 줄, 파일 핸들에서 $str 값을 읽어들일 때 매핑이 안 된다고 에러를 내는군요.

그 말인즉슨... ":utf8"은 단지 "utf8 flag"를 on으로 켜주는 역할만 하나보네요. utf-8.txt를 읽었을때는 UTF-8로 된 스트링에 저 flag가 on이니까 그게 곧 utf8 형태가 되어 있는 것이고, euc-kr.txt는 EUC-KR로 된 스트링에 flag만 켰더니만 ord쪽에서 글자 단위로 읽으려고 하다가 낭패를 당한 거라고 생각됩니다.

반면에 ":encoding(UTF-8)"이라고 적으면 이건 원본이 UTF-8이라고 명시를 한 거지만, 막상 읽을때는 UTF-8이 아니니 변환에 실패..

4)

open (FH, "<:encoding(EUC-KR)", "$file");
 
출력:
%ac00 %b098 %b2e4 %000a
utf8

명시적으로 ":encoding(EUC-KR)"이라고 주면, 그 때는 읽는 순간에 EUC-KR을 utf8형태로 변환하는군요. 그 말은 EUC-KR=>UTF-8변환과 flag를 on으로 바꾸는 두 가지 일을 한번에 한다는 얘기겠죠.

3. utf-16be.txt

1)

open (FH, "<$file");
 
%00ac %0000 %00b0 %0098 %00b2 %00e4 %0000 %000a
not utf8

바이트는 ac 00 b0 98... 로 가고 있지만 이것은 결국 바이트 시퀀스일 뿐 utf8은 아님

2)

open (FH, "<:utf8", "$file");
 
출력:
Malformed UTF-8 character (unexpected continuation byte 0xac, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0xb0, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0x98, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected continuation byte 0xb2, with no preceding start byte) in ord at ./test.pl line 13.
Malformed UTF-8 character (unexpected non-continuation byte 0x00, immediately after start byte 0xe4) in ord at ./test.pl line 13.
%0000 %0000 %0000 %0000 %0000 %0000
utf8

flag를 on한 것 만으로는 결국 utf8이 아니라서 ord에서 에러

3)

open (FH, "<:encoding(UTF-8)", "$file");
 
출력:
uutf8 "\xAC" does not map to Unicode at ./test.pl line 9.
utf8 "\xB0" does not map to Unicode at ./test.pl line 9.
utf8 "\x98" does not map to Unicode at ./test.pl line 9.
utf8 "\xB2" does not map to Unicode at ./test.pl line 9.
utf8 "\xE4" does not map to Unicode at ./test.pl line 9.
%005c %0078 %0041 %0043 %0000 %005c %0078 %0042 %0030 %005c %0078 %0039 %0038 %005c %0078 %0042 %0032 %005c %0078 %0045 %0034 %0000 %000a
utf8

역시 변환 실패

4)

open (FH, "<:encoding(UTF-16LE)", "$file");
 
출력:
%ac00 %b098 %b2e4 %000a
utf8

이건 예상대로 성공

---------------------------
여담으로,

is_utf8()을 쓰기 위해서 use Encode; 를 명시하긴 했습니다만, open() 에서 ":utf8"이나 ":encoding(UTF-8)"등을 쓸 때는 Encode 모듈이 없어도 되더군요. 그렇지만 use Encode;를 안 적어도 된다는 얘기지 Perl5.6에서는 안 될 거라고 생각해요 ^^; 암튼 5.8은 필수구먼요.

여담2.

bbcode 에서 제공하는 "대괄호code대괄호" 태그 말고, 그냥 html 태그 형식의 "부등호code부등호"를 쓰시면 부등호가 중간에 있어도 괜찮군요. :-)

좋은 하루 되세요!

keedi의 이미지

여담2.

bbcode 에서 제공하는 "대괄호code대괄호" 태그 말고, 그냥 html 태그 형식의 "부등호code부등호"를 쓰시면 부등호가 중간에 있어도 괜찮군요. :-)

그렇군요~ 감사합니다~ bbcode에 익숙하지 않아서 한참 헤맸어요. :-)

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Kim Do-Hyoung Keedi

----
use perl;

Keedi Kim

keedi의 이미지

쓰레드가 올라온지 벌써 1년이나 흘렀군요.

얼마전 펄매니아 스터디에서 aero님께서 유니코드 관련 발표를 하셨었는데,
http://aero.springnote.com/pages/1053508 페이지에 그 내용이 남아있습니다.

perl 과 유니코드 관련해서 관심이 있으신 분은 참조해보세요~ :-)

---------------------------
Smashing Watermelons~!!
Whatever Nevermind~!!

Keedi Kim

----
use perl;

Keedi Kim

ai의 이미지

좋은 글 소개해 주셔서 감사합니다. 명확하지 않던 부분이 잘 정리되어 이해할 수 있게 되었습니다.
일전 DBD::Oracle 를 사용하며 겪었던 문제가 어떤 이유에서 발생한 것인지도 설명이 가능하겠네요.
자료를 작성해 주신 aero 님께도 감사의 말씀을 드립니다. ^~^

--
War doesnt determine whos right, just whos left.

War doesnt determine whos right, just whos left.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.