2つの異なるパターンの間に数字を掛けてファイル全体を印刷します。

2つの異なるパターンの間に数字を掛けてファイル全体を印刷します。

パターン間の数字を乗数に置き換えて、すべての行を印刷したいです。このファイルはnewick形式のツリーファイルで、1行だけが含まれています。私の目標は)前後のすべての数です:。 2つの記号の間のすべての数に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を掛けた数字(1つ以上の数字、ピリオド、またはマイナス文字のシーケンスとして定義)に置き換えます。

たとえば、)0.714000:次のように変更します。)71.4000:

/eこれは、演算子のRHSでPerlコードを実行するためにPerlの正規表現評価修飾子を使用しますs///。詳細を表示してman perlop検索してくださいs\/PATTERNsprintf数値を小数点以下の4桁にフォーマットするために使用されます。


)間の数字が:一般的な10進表記法(「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

関連情報