<Tab>
次のように区切られたテキストファイルがあるとします。
file name size owner
file1.txt 12.345 root
file2.txt 0.172222 user1
file3.txt 2.46e2 user2
file4.txt 12345 root
file5.txt 21 user3
file6.txt 246.0 user1
file name owner last modified last accessed
text4.txt root 12.73 13.53
text5.txt user3 15.3333 34
file1.txt root 23 31.0032
ファイルは複数の「テーブル」で構成され、各テーブルはヘッダー行で始まり、いくつかのデータ行が含まれています。一部の列は数字ですが、各テーブルは異なる数字とさまざまな種類の列を持つことができます。列のタイプは事前に不明であり、表ヘッダーに基づいて判別できません。
表の値はさまざまな形式になっています。整数、浮動小数点小数、または科学表記の数です。
私の質問は、このテーブルのすべての数値フィールドを同じ形式に変換する方法です。たとえば、"%.2f"
printf書式指定子を使用して各数値フィールドの書式を指定できます。もちろん、数字以外のフィールドは変更されていないままにする必要があります。
また、このファイルに含まれるすべての数値フィールドをランダムに調整できるようにしたいです(たとえば、42を加えてから7を掛けます)。
私が探しているソリューションは現場ベースでなければなりません。ファイル全体をスキャンし、各フィールドに対して数字であることを確認する必要があります。数値の場合は、調整されフォーマットされた値を印刷する必要があります。それ以外の場合は、原稿のみ印刷する必要があります。
同様のことを行うために使用できることを知っていますawk
。しかし、私の記憶が正しい場合は、数値の内部表現awk
に使用されるため、double
精度と大きな値に問題がある可能性があります。したがって、理想的には、少なくとも64ビット整数を正しく処理できる他のものを使用したいと思います。
これを達成する簡単な方法はありますか?
答え1
Scalar::Util
looks_like_number()
perlには、フィールドが数値であるかどうかを検出するために使用できる便利な関数を持つモジュール(v5.8以降のperlに含まれています)があります。
looks_like_number
完璧ではありませんが、かなり良いです。
目的のタスクを実行する単純なPerlプログラムの簡単な概要は次のとおりです。
#! /usr/bin/perl
use Scalar::Util qw(looks_like_number);
while(<>) {
chomp;
my @fields=split("\t");
foreach my $f (0..scalar @fields-1) {
if (looks_like_number($fields[$f])) {
$fields[$f] += 42;
$fields[$f] *= 7;
$fields[$f] = sprintf("%.2f",$fields[$f]);
}
}
print join("\t",@fields),"\n";
}
上記のサンプルデータを入力として使用すると、次のものが印刷されます。
file name size owner
file1.txt 380.41 root
file2.txt 295.21 user1
file3.txt 2016.00 user2
file4.txt 86709.00 root
file5.txt 441.00 user3
file6.txt 2016.00 user1
file name owner last modified last accessed
text4.txt root 383.11 388.71
text5.txt user3 401.33 532.00
file1.txt root 455.00 511.02
以下は、すべての計算にMath :: BigFloatを使用して小数点以下の桁数を2桁に丸める別のバージョンのスクリプトです。
#! /usr/bin/perl
use Scalar::Util qw(looks_like_number);
use Math::BigFloat;
while(<>) {
chomp;
my @fields=split("\t");
foreach my $f (0..scalar @fields-1) {
if (looks_like_number($fields[$f])) {
my $BF = Math::BigFloat->new($fields[$f]);
$BF->badd(42);
$BF->bmul(7);
$BF->ffround(-2);
$fields[$f] = $BF->bstr();
}
}
print join("\t",@fields),"\n";
}
入力例:
file name owner last modified last accessed
text4.txt root 12.73 13.53
text5.txt user3 15.3333 34
file6.txt root 903709792518875002.42857142857142857142 903709792518875002
file7.txt root 6659166111488656281486807152009765625 539422123247359763587428687890625
出力:
file name owner last modified last accessed
text4.txt root 383.11 388.71
text5.txt user3 401.33 532.00
file6.txt root 6325968547632125311.00 6325968547632125308.00
file7.txt root 46614162780420593970407650064068359669.00 3775954862731518345112000815234669.00