2022년 6월 9일 목요일

[Perl] 텍스트 파일을 'chunk' 단위로 읽어들이기

chunk는 '큰 덩어리'라는 뜻이다. Perl을 이용하여 텍스트 파일을 읽어들일 때, 보통은 while 루프를 이용하여 줄 단위로 하나씩 읽어서 순차적으로 처리하게 된다. 그러나 어떤 분리자를 경계로 하여 구분된 여러 라인의 덩어리를 단위로 삼아서 변수로 읽어들이고 싶을 때도 있을 것이다. 예를 들어서 EMBOSS primersearch 프로그램의 결과 파일을 살펴보도록 하자. 다음에 보인 그림은 9개 프라이머쌍의 정보를 담고 있는 파일을 이용하여 하나의 FASTA file을 뒤져 amplimer를 탐색한 결과이다. 인간이 읽고 이해하기에는 쉽지만, 컴퓨터로 하여금 결과를 집계하도록 만들려면 매우 불편하다. 특히 수백 혹은 그 이상의 FASTA file에 대하여 primersearch를 돌렸다고 가정해 보자. 


언제 어떻게 활용될지 몰라서 프라이머 염기서열은 일단 가렸다. FASTA 파일 하나에 대해서 하나의 결과 파일을 쓰게 할 수도 있고, 여러 FASTA 파일에 대한 탐색 결과를 하나의 결과 파일에 몰아서 기록할 수도 있다. 후자의 방법을 이용하려면, 결과 파일 내에 입력 FASTA 파일에 따른 구분자를 넣을 수도 있다. 여러 FASTA 파일에 대한 탐색 결과를 처리하는 더 미련하고 복잡한 방법도 얼마든지 고안할 수 있다.
  

한 쌍의 프라이머에 대한 amplimer 탐색 결과는 빈 줄("\n\n")을 경계로 다른 결과와 구분된다. 바로 이것이 하나의 chunk이다. 이를 구현하기 위한 힌트는 StackOverflow의 Grabbing Chunks of Data from File in Perl에서 얻었다.

local $/ = "\n\n";

open LOG, $ARGV[1];
while ( $chunk = <LOG> ) {
   # do something on $chunk
}

결국은 "\n"을 경계로 하여 $chunk 변수를 분할하여 세부적인 작업을 해야 된다. 그러나 이렇게 하는 것이 편한 이유는, chunk 단위가 하나의 프라이머 쌍에 대한 '모든' amplimer 예측 결과에 해당하기 때문이다. 

Multi-record GenBank 파일은 '//'로 개별 단위가 분리된다. 오늘 알아본 방법을 통해서 GenBank 파일을 chunk 단위로 처리할 생각은 '1'도 없다. chunk 내의 구조가 워낙 복잡하기 때문이다. 꼭 필요하다면 csplit 유틸리티를 써서 각 레코드를 물리적인 파일로 나누어 버리는 것이 더욱 현명하다. 다음은 실제 응용 사례이다. 코드가 약간 난해하다! 아니, 난해할 것은 없다. 파일 분리자로 사용할 '//'를 정규표현식으로 나타낸 것에 불과하다. 맨 뒤의 '{*}'가 어떤 의미인지 알기가 좀 어렵다. csplit의 매뉴얼에 의하면 'repeat the previous pattern as many times as possible'이다. 'find ... -exec' 명령어에서 맨 뒤의 '\;'도 이해하기 쉽지는 않다. Bash 환경에서 {}, (), \, ; 등이 나오면 본능적으로 긴장을 하게 된다.

csplit --prefix=test ../genome.gbk '/^\/\/$/' '{*}'

리눅스 bash 환경에서 출현하는 특수한 문자 중 나를 가장 긴장하게 만드는 것은 바로 GNU parallel 유틸리티의 고급 용법이다...

BLAST parser 따위는 제발 짜지 말라는 글(Mad Scientist)이 기억났다. 과거에 BioPerl을 이용하여 human readable 형태의 BLAST 결과 파일을 파싱하는 코드를 짰던 적은 있다. 그 이후에 Zerg를 한동안 사용했었다. 잠시 추억에 젖어서 찾아보니 Zerg는 2003년에 나온 프로그램이다(논문 링크). 지금은 tabular output을 지정하면 되니 되므로 특별히 parser를 쓸 필요가 없다. Alignment를 반드시 눈으로 봐야 한다고 고집하지 않는다면 말이다. 2000년대 초반의 blastall 프로그램이 tabular output을 제공하지 않았었던가? 기억이 나지 않는다.

이러한 명령행 환경의 자료 조작 업무를 이제는 전부 Python으로 대체해 나가야 할까? 장기적으로는 그것이 정답일 수 있는데, 자꾸 손은 Perl Cookbook을 향하고 있으니...

댓글 없음: