2009년 8월 4일 화요일

[Perl] 분리된 한글 자모 합치기 스크립트

스크립트 소스:

#!/usr/bin/perl

use strict;
use warnings;
use utf8;
use Encode;

my @charset = qw/ㅇ ㅖ ㅈ ㅔ 1 ㅂ ㅓ ㄴ /; # 쓸 문자열을 지정합니다.

# %cho, %jun, %jon 은 초성, 중성, 종성의 순서를 나타냅니다.
# print "$_ : ".chr($_)."\n" foreach keys %cho;
# 같은 코드를 이용하면 확인해보실 수 있습니다.


my %cho = (
12593 => 0 , 12594 => 1 , 12596 => 2 , 12599 => 3 , 12600 => 4 , 12601 => 5 , 12609 => 6 , 12610 => 7 , 12611 => 8 , 12613 => 9 , 12614 => 10 , 12615 => 11 , 12616 => 12 , 12617 => 13 , 12618 => 14 , 12619 => 15 , 12620 => 16 , 12621 => 17 , 12622 => 18 , );
my %jun = (
12623 => 0 , 12624 => 1 , 12625 => 2 , 12626 => 3 , 12627 => 4 , 12628 => 5 , 12629 => 6 , 12630 => 7 , 12631 => 8 , 12632 => 9 , 12633 => 10 , 12634 => 11 , 12635 => 12 , 12636 => 13 , 12637 => 14 , 12638 => 15 , 12639 => 16 , 12640 => 17 , 12641 => 18 , 12642 => 19 , 12643 => 20 , );
my %jon = (
0 => 0 , 12593 => 1 , 12594 => 2 , 12595 => 3 , 12596 => 4 , 12597 => 5 , 12598 => 6 , 12599 => 7 , 12601 => 8 , 12602 => 9 , 12603 => 10 , 12604 => 11 , 12605 => 12 , 12606 => 13 , 12607 => 14 , 12608 => 15 , 12609 => 16 , 12610 => 17 , 12612 => 18 , 12613 => 19 , 12614 => 20 , 12615 => 21 , 12616 => 22 , 12618 => 23 , 12619 => 24 ,
12620 => 25 , 12621 => 26 , 12622 => 27 , );


my @numset;
#map { push @numset, ord $_ foreach (split //, $_) } @charset;
# @ARGV에서 받은 한글을 split 하니까 오류가 나서 포기했습니다.


map { push @numset, ord $_ } @charset; # 한글 문자열을 유니코드 문자세트로 바꿉니다.

my @output;
my $type=0;

while (@numset) { # 문자세트를 한 글자마다 분리시키기 위해 루프를 돌립니다.
# @$numset[0]은 초성, [1]에는 중성, [2]에는 종성을 넣도록 합니다.

my $qq = shift @numset;
if ( $qq > 12643 || $qq < 12593 ) { # 초, 중, 종성의 문자셋이 아니면 한 글자로 집어넣습니다.
$type++; push @{$output[$type]}, $qq;
next; # 지금 것은 처리가 끝났으니 다음 문자로 갑시다.
}
if (
($qq <= 12622 && $numset[0] > 12622 ) ||
( ${$output[$type]}[2] )) {
$type++; # 지금 글자에 종성까지 들어가 있거나
# 다음 문자가 모음이라면 다음 글자로 가서

}
push @{$output[$type]}, $qq; # 집어 넣습니다.
}


foreach ( @output ) {
($_=$$_[0])&&(next) unless $$_[1]; # 중성도 없다면
$_ 를 그 배열(@$_)의 첫번째 값으로 바꿉니다.

$$_[2] = $$_[2] || "0"; # null 대신 0을 넣어줍니다.
# 안 해주면, 종성이 없을 때에는 경고메세지를 출력합니다.

$_ = ($cho{$$_[0]}*21 + $jun{$$_[1]}) * 28 + $jon{$$_[2] } + 44032; # $_에 배열 대신 계산값 대입.
}
print encode('utf-8',chr($_)) foreach @output;
# 출력합니다.
# wide character 어쩌구 오류메세지를 막기 위해 인코딩을 사용했습니다.

print "\n";


출력 결과:
$ ./asdf.pl
예제1번



이 스크립트는 소정의 개인적인 목적을 위해 짜여졌으며, 내가 원하는 스크립트를 위한 중간발판 정도입니다. 때문에 저는 그냥 테스트 코드로만 작성을 해서 예외처리라든지 지저분한 점이라든지 있습니다. 태그 문제로 코드 정리도 지저분하고, 취향 때문에 사용한 몇몇 더러운 코드도 있긴 할테지만 자비롭게 봐주시면 감사합니다.
CPAN에 한국어 자모분리/합치기 모듈이 있긴 하지만 도무지 이용이 어려워 아예 스크립트를 새로 짰습니다. 그리고 딱히 자모 합치기에 대한 perl 스크립트는 보이지 않아 새로 게시를 하였습니다.

mwultong 님의 게시물에서 많은 도움을 받았습니다.

추가> 자음이나 모음만 들어간 경우를 처리하기 위해서는 좀 더 코드가 필요합니다. 중간에 while 문 안에 적당한 조건을 더 집어넣으면 되는데, 생각해보니 이프문을 두 개로 나눠놨는데 하는 짓은 똑같더군요. 예. 합쳐주면 조금이나마 더 깔끔한 코드가 될 것 같습니다.


덧.
아무래도 블로그 글 예쁘게 쓰기는 나랑 성향이 영 안 맞는 것 같다. 다음부터 대충 써야지 역시……
이 게시물 태그에 뻘짓이 있는 건, 나름 예쁘게 써보겠답시고 태그 만지고 블로그 편집기랑 싸움을 한 것 때문이다.
급 반말이 나오는 이유는, 애당초 여긴 배설 블로그였기 때문에 :P

8월 4일 16시 51분 출력 결과 수정 및 추가사항 입력. 아놔 예문 줄였으면서 그대로 올리면 어쩌자는 거지;

댓글 1개:

  1. http://search.cpan.org/~sadahiro/Lingua-KO-Hangul-Util-0.23/Util.pm

    http://search.cpan.org/~jeen/Lingua-KO-TypoCorrector-0.01/lib/Lingua/KO/TypoCorrector.pm

    관련 모듈 링크.

    답글삭제