Monday, July 24, 2006
Perl/펄] 탭으로 분리된 CSV 파일에서 특정 필드만 추출: getField.pl
CSV* 파일을 다루기 위해서는 Text::CSV 모듈을 사용하라고, 오레일리(O'Reilly)의 책들에는 나와 있었습니다. 그러나 실제로 해보니 Text::CSV 모듈이 제대로 작동하지 않았고 기능도 빈약했습니다.
* 엑셀 등의 스프레드 시트 프로그램에서, 데이터를, 콤마로 분리된 아스키 파일로 저장한 것. 여기서 다루는 것은 콤마가 아닌 탭으로 분리된 데이터 파일이기에 엄밀한 의미에서의 CSV 포맷은 아님.
Perl Cookbook 에는 정규식으로 CSV 를 처리하는 예제가 있었는데 그것마저도 작동하지 않았습니다. CSV의 콤마와 쌍따옴표 문제가 의의로 복잡하고 문제가 많다는 사실만을 알게 되었습니다. 흔히 쓰는 기호인 콤마로 필드를 구분하는 것은 역시 무리였습니다.
탭(Tab)으로 구분하는 것이 가장 이상적이었습니다. 엑셀 등에서는, 탭키를 누르면 다음 셀로 이동할 뿐, 셀 안에 탭 문자가 들어가지는 않습니다.
그래서 "탭으로 분리된 파일"에서, 옵션으로 지정해 준 특정 필드만을 출력하는 펄 스크립트를 만들었습니다.
getField.pl 이라는 것인데, 며칠 전에 포스팅한 CSV 다루는 예제를 조금 실용적으로 만든 것입니다. (▶▶ [Perl/펄] CSV / 간단한 목록 파일에서, 몇 번째 필드(Field)만 추출하기 [오피스/엑셀] 참조)
사용법은 간단합니다. 탭으로 필드들이 분리된 데이터가 만약 foo.txt 라는 이름으로 저장되어 있다면
getField.pl foo.txt
라고 하면 foo.txt의 첫번째 필드만이 명령 프롬프트 화면에 출력됩니다.
getField.pl foo.txt 2
라고 하면 두번째 필드가 나옵니다.
getField.pl 코드:
※ 아래 박스 클릭 후, 키보드 화살표 키로 좌우 스크롤 가능함
이렇게 탭문자로 구분된 데이타 파일을 0.txt 등의 이름으로 저장하고 (그런데 위의 데이타 파일을 그대로 카피해서 테스트하면 작동하지 않습니다. HTML은 탭문자를 표현할 수 없기에... 위의 예제의 공백들을 탭문자로 직접 변환해 주어야 합니다.)
getField.pl 0.txt 2
라고 치면 이렇게
2번째 필드만 추출됩니다.
아무 옵션도 지정하지 않으면 도움말이 나옵니다.
관련 게시물: ▶▶ [오피스/엑셀2003] CSV 파일을 콤마(,)가 아닌 탭(Tab)으로 분리하기: Microsoft Excel 2003
* 엑셀 등의 스프레드 시트 프로그램에서, 데이터를, 콤마로 분리된 아스키 파일로 저장한 것. 여기서 다루는 것은 콤마가 아닌 탭으로 분리된 데이터 파일이기에 엄밀한 의미에서의 CSV 포맷은 아님.
Perl Cookbook 에는 정규식으로 CSV 를 처리하는 예제가 있었는데 그것마저도 작동하지 않았습니다. CSV의 콤마와 쌍따옴표 문제가 의의로 복잡하고 문제가 많다는 사실만을 알게 되었습니다. 흔히 쓰는 기호인 콤마로 필드를 구분하는 것은 역시 무리였습니다.
탭(Tab)으로 구분하는 것이 가장 이상적이었습니다. 엑셀 등에서는, 탭키를 누르면 다음 셀로 이동할 뿐, 셀 안에 탭 문자가 들어가지는 않습니다.
그래서 "탭으로 분리된 파일"에서, 옵션으로 지정해 준 특정 필드만을 출력하는 펄 스크립트를 만들었습니다.
getField.pl 이라는 것인데, 며칠 전에 포스팅한 CSV 다루는 예제를 조금 실용적으로 만든 것입니다. (▶▶ [Perl/펄] CSV / 간단한 목록 파일에서, 몇 번째 필드(Field)만 추출하기 [오피스/엑셀] 참조)
사용법은 간단합니다. 탭으로 필드들이 분리된 데이터가 만약 foo.txt 라는 이름으로 저장되어 있다면
getField.pl foo.txt
라고 하면 foo.txt의 첫번째 필드만이 명령 프롬프트 화면에 출력됩니다.
getField.pl foo.txt 2
라고 하면 두번째 필드가 나옵니다.
getField.pl 코드:
※ 아래 박스 클릭 후, 키보드 화살표 키로 좌우 스크롤 가능함
#!/usr/bin/perl
use strict; use warnings;
&help if not defined $ARGV[0]; # 옵션이 하나도 없으면 도움말 출력
open FH, "<", $ARGV[0] or die "$!: '$ARGV[0]'\n";
my $separator = "\t"; # 분리 기호 정의
my $n = 0; # 첫 번째 필드는 1, 두 번째 필드는 2; 내부적으로는 0을 1로 간주.
# 옵션 해석
if (defined $ARGV[1] && &IsInt($ARGV[1])) {
$n = $ARGV[1] - 1;
$n = 0 if ($n <= 0 );
}
foreach (<FH>) {
next if $_ =~ /^\s+$/; # 빈줄이면 다음 줄로 통과
@_ = split /$separator/; # 분리자를 기준으로 분리하여 레코드를 배열에
chomp @_; # 요소들 끝의 행갈이 문자 제거
print $_[$n], "\n" if defined $_[$n]; # n번째 요소 출력
}
close(FH);
sub IsInt { # 10진수, 16진수 정수이면 참을 반환
($_[0] =~ /^[+-]?\d+$|^0x[\da-fA-F]+$/) ? 1 : 0;
}
sub help {
die <<TEXT;
탭으로 분리된 데이터 파일에서, N번째 필드만 추출하기
기본값은 1번째 필드
두 번째 옵션을 3으로 지정하면, 세 번째 필드
Usage : GetField.pl <file name> [Field Number]
Example : GetField.pl foo.txt
GetField.pl foo.txt 3
TEXT
}
use strict; use warnings;
&help if not defined $ARGV[0]; # 옵션이 하나도 없으면 도움말 출력
open FH, "<", $ARGV[0] or die "$!: '$ARGV[0]'\n";
my $separator = "\t"; # 분리 기호 정의
my $n = 0; # 첫 번째 필드는 1, 두 번째 필드는 2; 내부적으로는 0을 1로 간주.
# 옵션 해석
if (defined $ARGV[1] && &IsInt($ARGV[1])) {
$n = $ARGV[1] - 1;
$n = 0 if ($n <= 0 );
}
foreach (<FH>) {
next if $_ =~ /^\s+$/; # 빈줄이면 다음 줄로 통과
@_ = split /$separator/; # 분리자를 기준으로 분리하여 레코드를 배열에
chomp @_; # 요소들 끝의 행갈이 문자 제거
print $_[$n], "\n" if defined $_[$n]; # n번째 요소 출력
}
close(FH);
sub IsInt { # 10진수, 16진수 정수이면 참을 반환
($_[0] =~ /^[+-]?\d+$|^0x[\da-fA-F]+$/) ? 1 : 0;
}
sub help {
die <<TEXT;
탭으로 분리된 데이터 파일에서, N번째 필드만 추출하기
기본값은 1번째 필드
두 번째 옵션을 3으로 지정하면, 세 번째 필드
Usage : GetField.pl <file name> [Field Number]
Example : GetField.pl foo.txt
GetField.pl foo.txt 3
TEXT
}
Number Name
53350000053 물감자
6463737377754 똘똘이
535311626 레몬향기혜성
26262664264 맹구
6426464642 노가리
626264 강호동
64226422 봉천동
6868573 별사탕
464262642 이효리
8537727224 땡칠이
53653673513 백반형님
53350000053 물감자
6463737377754 똘똘이
535311626 레몬향기혜성
26262664264 맹구
6426464642 노가리
626264 강호동
64226422 봉천동
6868573 별사탕
464262642 이효리
8537727224 땡칠이
53653673513 백반형님
이렇게 탭문자로 구분된 데이타 파일을 0.txt 등의 이름으로 저장하고 (그런데 위의 데이타 파일을 그대로 카피해서 테스트하면 작동하지 않습니다. HTML은 탭문자를 표현할 수 없기에... 위의 예제의 공백들을 탭문자로 직접 변환해 주어야 합니다.)
getField.pl 0.txt 2
라고 치면 이렇게
D:\Z>getField.pl 0.txt 2
Name
물감자
똘똘이
레몬향기혜성
맹구
노가리
강호동
봉천동
별사탕
이효리
땡칠이
백반형님
Name
물감자
똘똘이
레몬향기혜성
맹구
노가리
강호동
봉천동
별사탕
이효리
땡칠이
백반형님
2번째 필드만 추출됩니다.
아무 옵션도 지정하지 않으면 도움말이 나옵니다.
관련 게시물: ▶▶ [오피스/엑셀2003] CSV 파일을 콤마(,)가 아닌 탭(Tab)으로 분리하기: Microsoft Excel 2003
tag: perl
Perl | 펄
<< Home