컴퓨터 엑셀 워드 포토숍 구글어스 WINDOWS JAVASCRIPT JAVA C++

 
Previous Post grep 명령] 찾은 문자열/단어 개수 출력, 행의 개수 출력: Count of Strin...Perl/펄] 파일 속의 문자열, 단어 개수 세기; Count All (grep 확장 스크...리눅스/유닉스에서 파일 찾는 방법; 디렉토리 찾는 법; File Find Command L...HTML] 아랍어, 오른쪽에서 왼쪽 방향으로 쓰기, 언어 속성 지정; Arabic Dire...HTML] 아랍어 인코딩; 아라비아어 웹페이지; Arabic Encoding charset...Java/자바] 배열 사이즈 구하기; 배열 크기 얻는 함수는? Array Size; siz...VIM (VI, GVIM) 텍스트 입력 시작, 편집(Edit) 명령어; 빔 에디터 기초 사...C언어] 문자 대소문자 변환; 대문자로 소문자로; char, int to Uppercase...해왕성 천문 사진 (보이저 촬영): Neptune Photo NASAC언어] 문자열 대소문자 변환, 대문자로 소문자로; String to Uppercase L...

Perl/펄] 파일의 중복된 행 지우기; 같은 줄, 동일 값 제거, Remove Duplicate Lines Text File

Wednesday, November 29, 2006

텍스트 파일에서, 같은 내용의 줄이 여러 번 중복되어 있는 경우에, 그 중복된 줄을 모두 지우고 하나씩만 남기는 방법입니다.

즉 파일의 데이터를 정돈하는 스크립트입니다.

delDupLine.pl test.txt
이렇게 명령행 옵션으로 텍스트 파일을 지정해 주면, test.txt 에서 중복된 줄을 모두 지우고 유일한 줄만 화면에 출력합니다.


화면 출력을 다시 텍스트 파일로 저장하려면, 즉 "새 이름으로 저장(Save As)" 하려면
delDupLine.pl test.txt > out.txt
이렇게 재지향(Redirection)을 사용하면 됩니다.


텍스트 파일의, 중복 라인(데이터) 삭제 프로그램


파일명: delDupLine.pl
#!/usr/bin/perl
use strict; use warnings;

  foreach (<>) {
    chomp;
    print "$_\n" unless $_{$_}++;
  }



테스트용으로 사용할 텍스트 파일: test.txt
foo
foo
foo
bar

0
0
0
1
1
1
0
0
0

맹구는 복숭아를 먹었습니다.
맹구는 복숭아를 먹었습니다.
맹구는 복숭아를 먹었습니다.

1twyw
2yeyeye
3tuteute
4646464
557575
6yeyt
7ryryre
8ytrwyrw
968486
065yrhdhd

2yeyeye
6yeyt
2yeyeye

AAAAAAAAAAAAAA
BBBBBBBBBBBB
CCCCCCCCCC
EEEEEEEEEE
EEEEEEEEEE
FFFFFFFF
GGGGGG
HHHHHHH
IIII
JJJJJJ
KKKKKKK
LLLLLLL
MMMMMMM
NNNNNNN


AAAAAAAAAAAAAA
GGGGGG
HHHHHHH
IIII
JJJJJJ

자장면
자장면
자장면
탕수육
탕수육
자장면
탕수육
짬뽕
맹구는 복숭아를 먹었습니다.


GGGGGG
GGGGGG
GGGGGG
GGGGGG



실행 결과:
(윈도우에 액티브펄(ActivePerl)을 설치한 후, 실행한 결과임)
D:\Z>delDupLine.pl test.txt
foo
bar

0
1
맹구는 복숭아를 먹었습니다.
1twyw
2yeyeye
3tuteute
4646464
557575
6yeyt
7ryryre
8ytrwyrw
968486
065yrhdhd
AAAAAAAAAAAAAA
BBBBBBBBBBBB
CCCCCCCCCC
EEEEEEEEEE
FFFFFFFF
GGGGGG
HHHHHHH
IIII
JJJJJJ
KKKKKKK
LLLLLLL
MMMMMMM
NNNNNNN
자장면
탕수육
짬뽕

D:\Z>


중복된 줄이 말끔히 지워지고, 유일한 줄만 남았습니다.



코드 설명


  foreach (<>) {
    chomp;
    print "$_\n" unless $_{$_}++;
  }


소스 자체는 어처구니 없을 정도로 짧고 간단한데, 알고리즘이랄까 내용은 좀 복잡합니다.

foreach (<>) {...
명령행 옵션으로 입력해 준, 텍스트 파일을 1행씩 읽어, 기본 변수인 $_에 차례로 담습니다.

chomp;
라는 것은, 라인 끝의 개행문자를 제거합니다. 개행문자(줄바꿈 문자)를 제거하지 않으면, 줄 끝의 개행문자의 유무에 따라, 같은 문자열도 다른 문자열로 간주되는 문제가 생깁니다. chomp 뒤에 아무것도 적어 주지 않으면, 기본 변수인 $_ 의 끝에서 개행문자를 지웁니다.


print "$_\n" unless $_{$_}++;

unless 라는 것은 if문의 반대입니다. 조건에 맞지 않으면 뭘 하라는 뜻인데, 여기서는 $_{$_}++ 라는 조건이 거짓(undef; 초기화되지 않은 값)이라면 print문을 실행하라는 뜻입니다. 플러스 플러스(++)로 1 이상이 되면, 아까 처리했던 줄이니 출력하지 말라는 것입니다.



더 자세한 설명은 다음과 같습니다:


기본 디폴트 해쉬인 %_ 의 변수적 표현인 $_{} 이곳에
$_{현재 행}
이렇게 현재 행을 통째로 키(key)로 삼아 집어 넣고, 해쉬의 그 요소의 값(value)을 +1 하여 증가시킵니다. (뭘 계산하기 위해서 증가시키는 것이 아니고, 참/거짓의 논리값을 얻기 위한 트릭입니다.)

만약 처음 마주친 줄이라면, 그 해쉬 요소의 값은 초기화되지 않은 undef 즉 null 이기에 논리값이 거짓(false)입니다. 거짓이면 그 줄이 print 됩니다. (unless 는 if의 정반대이기에)

만약 아까 보았던 줄이라면, 즉 "중복된 줄"이라면, 그 해쉬의 값이 ++ 에 의해 undef 에 1이 더해져서 1이나 1이상의 값이 되어 있을 것입니다.

해쉬의 값이 1이나 1 이상일 경우, 펄에서 0 은 거짓, 0이 아닌 숫자는 참이기에, 그 중복된 줄은 "참(true)"이 되어 print 되지 않습니다. (unless 는 if의 정반대이기에)

따라서, 결국 유일한 줄, 즉 유니크(Unique)한 줄만 프린트되고, 중복된(Duplicated) 줄은 자연스레 무시되는 것입니다.


자장면 : 현재 $_{자장면} 의 값은 undef
자장면 : 이제 $_{자장면} 값은 1. 앞의 자장면에서 +1 했기에
자장면 : $_{자장면} 의 값은 이제 2로 증가
탕수육 : $_{탕수육} 은 처음 나왔으니 undef


위의 경우, 맨 처음 나온 "자장면"이라는 줄만 출력되고, 다음 줄의 자장면들은 모두 무시됩니다. 왜냐하면 2번째 "$_{자장면}" 부터는 값이 undef 이 아니기 때문입니다.





파일에서, 중복된 빈 줄들만 삭제하는 방법: ▶▶ 펄/Perl] 여러 개의 빈줄 제거, 하나의 빈줄로 합치기, Collapse Multiple Blank Lines Into One

☞ Perl(펄)

0 Comments:

Post a Comment

<< Home RSS 2.0 feed

구글 Google 에서 제공하는 무료 블로그 서비스인 블로거 Blogger 의 인터넷 주소는 www.blogger.com 입니다. Blogger 에 블로그를 만들면, blogspot.com 이라는 주소에 블로그가 생성됩니다.
블로그를 직접 방문하지 않고도 최신 게시물을 구독하려면 RSS 2.0 feed 주소를 리더기에 등록하시면 됩니다.
Categories
Previous Posts
Monthly Archives
Top