서로 다른 두 패턴 사이에 숫자를 곱하고 전체 파일을 인쇄합니다.

서로 다른 두 패턴 사이에 숫자를 곱하고 전체 파일을 인쇄합니다.

패턴 사이의 숫자를 승수로 바꾸고 모든 줄을 인쇄하고 싶습니다. 이 파일은 newick 형식의 트리 파일이며 한 줄만 포함합니다. 내 목표는 )전후의 모든 숫자 입니다 :. 두 기호 사이의 모든 숫자에 100을 곱하고 싶습니다.

문서:

((((A_8:0.000846,(A_5:0.002449,(A_1:1e-06,((A_4:1e-06,((A_7:1e-06,A_6:0.001061)0.714000:1e-06,A_3:1e-06)0.314500:1e-06)0.358667:1e-06,A_2:1e-06)0.361000:1e-06)0.434800:1e-06)0.683500:0.001619)0.888571:0.001931,A_9:0.00069)0.688471:0.000691,...

나에게 가장 쉬운 방법은 먼저 모든 ":" 기호를 새 줄로 바꾸어 파일을 분할하는 것 같습니다. 따라서 내 모든 대상 숫자는 이제 별도의 행에 표시되며 )아래의 awk 스크립트를 사용하여 대상 숫자에 100을 곱하지만 대상 숫자가 없는 행을 유지할 수 없습니다.

스크립트:

sed 's/:/\n/g' df9.tree | awk -F")" '{OFS=")"} $2=$2*100 {print $0}'
sed 's/:/\n/g' df9.tree | awk '$NF ~/)/ {$NF *=100}1'

이 경우 다음 숫자를 곱하여 )파일 전체를 인쇄하려면 어떻게 해야 합니까? 아니면 :과 사이의 숫자를 직접 찾아서 )100을 곱하고 전체 파일을 인쇄하는 또 다른 더 쉬운 방법이 있습니까 ?

업데이트: 예상 출력

((((A_8:0.000846,(A_5:0.002449,(A_1:1e-06,((A_4:1e-06,((A_7:1e-06,A_6:0.001061)71.4000:1e-06,A_3:1e-06)31.4500:1e-06)35.8667:1e-06,A_2:1e-06)36.1000:1e-06)43.4800:1e-06)68.3500:0.001619)88.8571:0.001931,A_9:0.00069)68.8471:0.000691,...)

답변1

awk 'BEGIN {OFS=FS=":"; ORS=RS=")"} NR>1 {$1=sprintf("%.4f", $1 * 100)}1' df9.tree

별도의 RS 레코드와 FS 필드를 허용하는 경우 필수 번호는 항상 첫 번째 레코드 다음의 첫 번째 필드에 있습니다.

답변2

$ perl -pe 's/\)([-0-9.]+):/sprintf ")%.4f:", $1 * 100/eg' df9.tree
((((A_8:0.000846,(A_5:0.002449,(A_1:1e-06,((A:1e-06,((A_7:1e-06,A:0.001061)71.4000:1e-06,A:1e-06)31.4500:1e-06)35.8667:1e-06,A:1e-06)36.1000:1e-06)43.4800:1e-06)68.3500:0.001619)88.8571:0.001931,A:0.00069)68.8471:0.000691,...

):문자 뒤에 오는 모든 숫자를 100을 곱한 숫자(하나 이상의 숫자, 마침표 또는 빼기 문자의 시퀀스로 정의됨)로 바꿉니다 .

예를 들어 )0.714000:다음과 같이 변경합니다.)71.4000:

/e이는 연산자의 RHS에서 Perl 코드를 실행하기 위해 Perl의 정규식 평가 수정자를 사용합니다 s///. 세부정보를 보고 man perlop검색하세요 s\/PATTERN. sprintf숫자를 소수점 이하 4자리로 형식화하는 데 사용됩니다.


)사이의 숫자가 :일반 십진수 표기법("0.714000") 또는 "C float" 스타일 과학 표기법("1e-06")일 수 있는 경우 정규식은 가능한 모든 변형을 일치시키기 위해 좀 더 복잡해야 합니다.

$ perl -pe 's/\)(([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?):/sprintf ")%.4f:", $1 * 100/eg' df9.tree
((((A_8:0.000846,(A_5:0.002449,(A_1:1e-06,((A_4:1e-06,((A_7:1e-06,A_6:0.001061)71.4000:1e-06,A_3:1e-06)31.4500:1e-06)35.8667:1e-06,A_2:1e-06)36.1000:1e-06)43.4800:1e-06)68.3500:0.001619)88.8571:0.001931,A_9:0.00069)68.8471:0.000691,...)

다음 방법도 작동할 수 있지만 일치하지 않는 숫자가 있을 수 있습니다.

perl -pe 's/\)([-0-9.eE+]+):/sprintf ")%.4f:", $1 * 100/eg'

답변3

Perl을 사용하면 s///e평가 단계를 사용하여 일치하는 항목이 숫자인지 확인하고 그에 따라 바꿀 수 있습니다.

perl -MScalar::Util=looks_like_number -pe '
s{\)\K.*?(?=:)}{ looks_like_number($&) ? $&*100 : $& }ge' file

GNU awk를 사용하여 정규식을 레코드 구분 기호로 사용하십시오.

gawk 'prevRT==")" && RT==":" && $0+0 == $0 {$0 *= 100} {ORS = prevRT = RT}
1' RS='[):]' file

이는 비교를 통해 기록의 숫자적 특성을 테스트합니다 $0+0 == $0.

답변4

POSIX sed데스크탑 계산기 및 bash 쉘과 함께 사용하면 dc그림에 표시된 결과를 얻을 수 있습니다. 먼저 합성할 문자열의 형태를 계산한 다음 이를 bash에 푸시하여 합성합니다.

echo 'echo "'"$(sed -e '
  s#)\([^:)]\{1,\}\):#)$(echo "4k100 \1*1/p"|dc):#g' < file)"'"'|sh

또는 출력을 생성하는 명령으로 미리 채워진 변수를 평가할 수 있습니다.

var='echo "'$(sed -e '
  s#)\([^:)]\{1,\}\):#)$(echo "4k100 \1*1/p"|dc):#g' < inp)\"

eval "$var"

필드와 구분 기호를 추적 split하려면 4개의 인수 함수를 사용하세요 .GNU awk

awk '{
  split($0, a, /[:)]/, s)
  for (i=1; i in a; i++)
    print (s[i-1] s[i] == "):" ? sprintf("%.4f",a[i]*100):a[i]) s[i]
  $0=RS
}1' ORS= file

관련 정보