2013-11-15 2 views
3

그래서이 파일에는 480000 개 이상의 행과 1380 개의 열이 있습니다. 두 번째 행의 값이 Sex : Female 또는 Sex : Male 인 경우 첫 번째 행의 값에 F_ 또는 M_을 추가하는 파이프 라인이 있어야합니다.Perl, secod 행의 값을 기준으로 첫 번째 행의 값을 변경하십시오.

내 파일의 첫 번째 줄은 기본적으로 개별 ID 다음에 셀 유형 -N 또는 -G가옵니다. 두 번째 줄은 그 개인이 Female 또는 Male인지 여부를 나타내며 나머지 줄은 첫 번째 열의 probe_Ids이고 다른 열은 각 개인의 해당 베타 값입니다. 그게 더 합리적이라면 나는 다음의 몇 줄을 추가 할 것이다.

제 입력 열은 첫 번째 열이 없으면 탭으로 구분됩니다.

1740-N 1546-N 1546-G 1740-G 1228-G 5121-N 5121-G 
Sex: Female Sex: Female Sex: Female Sex: Female Sex: Male Sex: Female Sex: Female 

내 출력은 첫 번째 열없이 (탭 - 구분 된) 이런 성 라인 출력하지 않은 것

F_1740-N F_1546-N F_1546-G F_1740-G M_1228-G F_5121-N F_5121-G 

주 보일 것이다.

아무도 도와 줄 수 있습니까? 작은 수의 열이 있으면 수동으로 수행 할 것입니다.

이것은 모든 프로그램에서 수행 할 수 있습니다. 나는 펄을 고수하지 않는다.

+0

파일의 첫 번째와 두 번째 행 또는 파일 쌍을 이루는 행입니까? –

+0

둘 다 하나의 파일에 있습니다. 두 번째 행은 첫 번째 행에 대한 결정 요인이지만 두 가지 모두 필요하지는 않습니다. 하나만 헤더로 사용해야합니다. 그리고 너무 많은 시간을 절약 할 수 있습니다. – user2997397

+0

이것은 파일의 첫 번째와 두 번째 행이며 파일의 여러 위치가 아닌 한 쌍의 파일이라는 것을 의미합니다. –

답변

1

한 줄의 버퍼를 유지한다.

my $last_line = <>; 
if ($last_line) { 
    while (my $this_line = <>) { 
     if ($this_line =~ /^Sex:/) { 
     adjust_for_sex($last_line, $this_line); 
     next; # Don't display the Sex row. 
     } 

     print($last_line); 
     $last_line = $this_line; 
    } 

    print($last_line); 
} 

그리고 이것은 실제 변화를 수행하는 코드이다 :이 같은

sub adjust_for_sex { 
    my ($last_line, $this_line) = @_; 

    chomp($last_line); 
    my @last_fields = split /\t/, $last_line; 

    chomp($this_line); 
    my @this_fields = split /\t/, $this_line; 

    for my $i (0..$#last_fields) { 
     my ($sex) = $this_fields[$i] =~ /^Sex: (.)/ 
     or die; 

     $last_fields[$i] = $sex . "_" . $last_fields[$i]; 
    } 

    # Changes the first argument in the caller. 
    $_[0] = join("\t", @last_fields) . "\n"; 
} 
+0

몇 가지 문제가 해결되었습니다. – ikegami

+0

이름을 실제로 변경하지 않았거나 올바른 방법으로 수행하지 않았을 수도 있습니다. – user2997397

+0

'다음'을 사용해야하는 곳에서 '다시 실행'을 사용하여 무한 루프에 걸렸습니다. 결정된. 어쨌든 새로운 정보를 기반으로 한 섹스 라인이 하나 뿐이며 파일의 두 번째 줄입니다.이 솔루션은 잔인합니다. – ikegami

0

뭔가 AWK에서 작동합니다. 그것은 비록 첫 번째 행에서 모든 데이터를 저장하지만 조금의 메모리가 필요할 것입니다. 일을 할 수있는 다음과 같은 파일 무언가에 걸쳐이 패턴의 반복을 일치하는 라인의 쌍 경우

BEGIN {FS="\t"} 

NR == 1 { 
    for (i = 1; i <= NF; i++) { 
     f[i]=$i 
    } 
    next 
} 

NR == 2 { 
    for (i = 1; i <= NF; i++) { 
     $i=gensub(/Sex: ([FM]).*/, "\\1", "g", $i) 
     $i=$i"_"f[i] 
    } 
    print 
    next 
} 

{print} 

:

BEGIN {FS="\t"} 

line && /^Sex:/{ 
    split(line, f) 
    line="" 

    for (i = 1; i <= NF; i++) { 
     $i=substr($i, 0, 6) 
     gsub(/^Sex: /, "", $i) 
     printf "%s ", $i"_"f[i] 
    } 
    print "" 
    next 
} 

line {print line} 

{line=$0} 
+0

나중에 파일에 이드와 섹스 라인이있을 수 있다는 인상을 받았습니다. 그렇다면 @ user2997397? – ikegami

+0

잘 모르겠습니다. 나는 묻기를 시도했으나 좋은 대답을 얻지 못했습니다. 파일에 다른 줄이 없으면 NR 패턴을 제거하면 작동합니다 (기본 인쇄도 마찬가지 임). 그럴 경우 다음과 같은 펄 응답이 더 필요합니다. –

+0

아마도 ** 사용중인 언어 인 것 같기 때문에 **'awk' **를 언급 할 가치가 있습니다. –

0

이 가정 기록 된 입력 파일 라인의 쌍을 반복하는 것은 함께 구문 분석했다 . 첫 번째 2 줄을 파싱 한 후 중지하도록 쉽게 수정할 수는 있지만, 답을 밝히고 나면 op의 질문에 대답하지 않더라도 그대로 두겠습니다. 어쩌면 그것은 다른 누군가에게 유용 할 것입니다.

#!perl 

use strict; 
use warnings; 

open(IN, "in.txt") or die $!; 
open(OUT, ">out.txt") or die $!; 
my $secondLine ; 
while(<IN>) { 
    my $firstLine = $_; 
    chomp $firstLine; 
    $secondLine = <IN> || ""; 
    chomp $secondLine; 
    # Break out if there are no more lines with data (actually, this just detects 1-2 blank lines in a row, not necessarily at the end of the file yet) 
    if ((! $firstLine) && (! $secondLine)) { last } 
    my @firstLine = split(/\s+/, $firstLine); 
    my @secondLine = split(/\s*Sex:\s*/, $secondLine); 
    # The first element in @secondLine will always be the "null" before the first "Sex: ". 
    # Throw it away. 
    shift @secondLine; 
    if (scalar(@firstLine) != scalar(@secondLine)) { die "Uneven # of fields in these 2 lines:\n$firstLine\n$secondLine\n" } 

    # OK, output time. 
    for (my $i=0; $i<scalar(@firstLine); $i++) { 
    print OUT substr($secondLine[$i], 0, 1) . "_$firstLine[$i] "; 
    } 
    print OUT "\n"; 
} 
close(IN); 
close(OUT); 

if (! $secondLine) { 
    warn "The file does not appear to have an even number of lines.\n"; 
} 
+0

파일에 ID와 성별 이상의 의미가 있다는 인상을 받았습니다. 그렇다면 @ user2997397? (더 많은 라인을 표시하라는 요청에 대해 OP 만이 후속 조치를 취한 경우) – ikegami

+0

@ikegami 내 게시물을 업데이트했습니다. – user2997397

+0

@ikegami 한 ID와 성별로 무엇을 의미하는지 모르겠습니다! 그것은 한 줄의 성 (ids)과 한 줄의 성 (gender)입니다. 3에서 479973까지의 라인이 실제 데이터입니다 – user2997397

0

에 대해 어떻게 :

#!/usr/bin/perl 


while(<>) { 
    chop; 
    @N=split; 
    $_=<>; 
    chop; 
    s/\s*Sex:\s*//g;s/emale/ /g;s/ale/ /g; 
    @S=split; 
    foreach $k (0..$#N) { 
    $i=$N[$k]; $g=$S[$k]; 
    print "$g" . '_' . "$i " ; 
    } 
    print "\n"; 
} 
+0

파일에 ID와 성별 이상의 의미가 있다는 인상을 받았습니다. 그렇다면 @ user2997397? (OP 만 더 많은 라인을 표시하라는 요청을 따라 갔다면 – ikegami

+0

도 작동하지 않으며 @N, @S, $ k, $ N, $ i 및 $ g 인 것을 설명 할 수 있습니까? 이 기호에 관한 오류가 있습니다. – user2997397

0

이 당신을 위해 작동 할 수 있습니다 (GNU를 나오지도) :

sed -ri '1{N;:a;s/(\b[0-9]{4}-[GN].*\n)\s*Sex:\s*(.)\S+/\2_\1/;ta;s/\n//}' file 

이 라인 1과 2를 결합하고 더 이상의 열 때까지 대체 루프를 수행 일치시킬 수 있습니다.

+0

나와 함께 작동하지 않았습니다. (sed : illegal option - r)와 같은 오류가 계속 발생했습니다 – user2997397

2
$ awk -F'\t' ' 
NR%2 { split($0,a); next } 
{ 
    for (i=1;i<=NF;i++) 
     printf "%s%s_%s", (i==1?"":FS), ($i~/Female/?"F":"M"), a[i] 
    print "" 
} 
' file 
F_1740-N  F_1546-N  F_1546-G  F_1740-G  M_1228-G  F_5121-N F_5121-G 
+0

코드를 시도했지만 빈 파일 만 생성했습니다. – user2997397

+0

그런 다음 스크립트를 잘못 복사하거나 붙여 넣거나 그렇지 않으면 불가능한 것처럼 입력 파일을 비어 있거나 손상 시켰습니다. –

관련 문제