Perlを使用してファイル内の科学的数を数える


10

ファイル内の科学的数値の数を数えるにはどうすればよいですか?ファイルには、スキップする必要がある数行のヘッダーもあります。

ファイルの内容の一部を以下に示します。

FileHeaderLine1
FileHeaderLine2
FileHeaderLine3
FileHeaderLine4
2.91999996E-001 2.97030300E-001 3.02060604E-001 3.07090908E-001 3.12121212E-001 3.17151517E-001
3.22181821E-001 3.27212125E-001 3.32242429E-001 3.37272733E-001 3.42303038E-001 3.47333342E-001
3.52363646E-001 3.57393950E-001 3.62424254E-001 3.67454559E-001 3.72484863E-001 3.77515137E-001
3.82545441E-001 3.87575746E-001 3.92606050E-001 3.97636354E-001 4.02666658E-001 4.07696962E-001
4.12727267E-001 4.17757571E-001 4.22787875E-001 4.27818179E-001 4.32848483E-001 4.37878788E-001
4.42909092E-001 4.47939396E-001 4.52969700E-001

では、上記の例の最初の4行をスキップして、ファイル内の科学的数値の数を数えるにはどうすればよいでしょうか。

回答:


14

コアモジュールを使用するとScalar::Util、次のことができます。

$ perl -MScalar::Util=looks_like_number -anle '
    $count += grep { looks_like_number($_) } @F;
    END { print $count }
' file
33

詳細についてlooks_like_numberは、を参照してくださいperldoc perlapi


+1クール、私は知りませんでしたlooks_like_number
Steeldriver '20 / 06/20

7

GNU grepの使用

grepPCRE機能を使用して、これを行うことができます。ちなみに、Perlでも同じパターンを使用できます。

$ grep -oP '\d+E[-+]?\d+' file.txt  | wc -l
33

を使用wc -wして単語を数えることもできgrepます。上の行を数えていますが、行で1つの一致を返すので、そのシナリオでは実際には問題になりません。

Perlの使用

Perlの場合、次の1つのライナーを使用できます。

$ perl -lane '$c += grep /\d+E[-+]?\d+/, @F; END { print $c; }' file.txt 
33

参考文献


@StephaneChazelas-編集ありがとうございます。申し訳ありませんが、これまでGNUシステムしか使用していないため、この点は常に忘れがちです。私はその間違いをしないように努めます。
slm

4

egrep 働くでしょう:

egrep "[0-9].[0-9]E-[0-9]" YourFile | wc -w

更新:

行に数字と他の文字列の両方が含まれている場合awk、問題を解決するために使用できます。

awk -F' ' '{for(i=1;i<=NF;i++)if(!(i%1))$i=$i "\n"}1' YourFile | egrep "[0-9].[0-9]E-[0-9]" | wc -w ( or wc -l )

行に数字と他の文字列の両方が含まれている場合、これは誤った結果をもたらします。grepの-oオプションを使用して一致のみを出力する上記の答えは、より正確です。
ジョニー

-oP以前、slmの回答に記載されているオプションについて知りませんでしたが、awk@ Johnny を使用して問題を修正しました
Nidal

3

4行目以降は科学的数値しかないと仮定すると、以下のようなことができます。

tail -n +5 filename | wc - w

入力した入力の場合、上記のコマンドを実行すると、出力は33になります。


3

perlのヘッダー行に続く空白で区切られたフィールドの数を数える必要がある場合、私はあなたがちょうどできると思います

perl -lane '$sum += $#F+1 if $. > 4; END{print $sum}' file

科学的にフォーマットされた数値のみをカウントする必要がある場合は、適切な正規表現に従って数値を検索して置換し、置換の数をカウントする方法があります(perl置換式は、変数にバインドすると置換の数を返します)

perl -lane '$sum += s/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?//g if $. > 4; END{print $sum}' file

2

すべては、実際に科学的数値と見なしたいもの、入力に含めることが期待できるもの、および入力内でそれらの数値を見つけるために受け入れることができる場所にまで及びます。

たとえば、次の場所にあります。

That's inferior to the LK2E2000 model.

0または2(infおよび2E2000)または3(inf、2E200、0)のいずれかの番号(または極端な場合は、有効な番号を形成するすべての文字シーケンスを探します:17(inf、2、2E2、 2E20、2E200、2E200、2E2000、2、20、200、2000、0、00、000、0、00、0))。

入力にX.XXXXXXXXE-XXX内の数字のみが含まれていて、それらが独自の単語であることがわかっている場合は、次のような単語全体で検索する方が安全な場合があります。

tr -s '[[:blank:]]' '[\n*]' | LC_ALL=C grep -xEc '[0-9]\.[0-9]{8}E-[0-9]{3}'

そこでの考えは、1行に1ワードを取得-xし、必要なパターンに対して行全体()を照合することです。科学的記数法の番号(-1.2e + 1234 ... eまたはaがある限りE)を許可するには、パターンを次のように変更します。

[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9])[eE][-+]?[0-9]+

または、e...パーツをオプションにして、あらゆる種類の10進浮動小数点数を許可します。

[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9])([eE][-+]?[0-9]+)?

それはすべて、特定の入力に対して同じ答えを与えますが、それが違いをもたらすのは、サンプルに示されている厳密なパターンから逸脱する入力がある場合です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.