Verwenden von Perl zum Zählen der Anzahl wissenschaftlicher Zahlen in einer Datei


10

Wie kann ich die Anzahl der wissenschaftlichen Zahlen in einer Datei zählen? Die Datei enthält auch einige Kopfzeilen, die übersprungen werden müssen.

Ein Teil des Inhalts der Datei befindet sich unten.

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

Wie kann ich also die ersten vier Zeilen des obigen Beispiels überspringen und die Anzahl der wissenschaftlichen Zahlen in der Datei zählen?

Antworten:


14

Mit dem Kernmodul Scalar::Utilkönnen Sie Folgendes tun:

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

Mehr über looks_like_numberkann in sehen perldoc perlapi.


+1 cool, ich wusste nichts überlooks_like_number
Steeldriver

7

Mit GNU grep

Sie können grepdies mithilfe der PCRE-Funktionen tun. Das gleiche Muster kann übrigens auch in Perl verwendet werden:

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

Sie können auch wc -wWörter zählen, ich zähle die obigen Zeilen, aber das grepgibt eine einzelne Übereinstimmung in einer Zeile zurück, sodass es in diesem Szenario nicht wirklich wichtig ist.

Verwenden von Perl

Für Perl können Sie diesen einen Liner verwenden:

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

Verweise


@StephaneChazelas - danke für die Bearbeitung. Es tut mir leid, dass ich immer nur auf GNU-Systemen bin. Vergessen Sie diesen Punkt also immer wieder. Ich werde versuchen, diesen Fehler nicht zu machen.
slm

4

egrep wird funktionieren:

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

AKTUALISIEREN:

Wenn eine Zeile sowohl eine Zahl als auch eine andere Zeichenfolge enthält, können wir awkdas Problem lösen:

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 )

Dies würde zu falschen Ergebnissen führen, wenn eine Zeile zufällig sowohl eine Zahl als auch eine andere Zeichenfolge enthält. Die obige Antwort, bei der die Option -o von grep verwendet wird, um nur Übereinstimmungen auszugeben, ist korrekter.
Johnny

Ich wusste vorher nichts über -oPdie in slm answer erwähnte Option, aber ich habe mein Problem mit awk@Johnny
Nidal

3

Angenommen, Sie haben nur wissenschaftliche Zahlen nach der 4. Zeile, können Sie etwas wie das Folgende tun.

tail -n +5 filename | wc - w

Für die von Ihnen angegebene Eingabe beträgt die Ausgabe 33, nachdem der obige Befehl ausgeführt wurde.


3

Wenn Sie einfach die Anzahl der durch Leerzeichen getrennten Felder zählen müssen, die den Kopfzeilen in Perl folgen, können Sie dies einfach tun

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

Wenn Sie wirklich nur wissenschaftlich formatierte Zahlen zählen müssen, besteht ein Ansatz möglicherweise darin, Zahlen nach einem geeigneten regulären Ausdruck zu suchen und zu ersetzen und dann die Anzahl der Ersetzungen zu zählen (der Perl-Substitutionsausdruck gibt die Anzahl der Ersetzungen zurück, wenn Sie sie an eine Variable binden )

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

2

Es hängt alles davon ab, was Sie tatsächlich als wissenschaftliche Zahl betrachten möchten , was Sie von Ihrer Eingabe erwarten können und wo Sie akzeptieren können, diese Zahlen in der Eingabe zu finden.

Zum Beispiel in:

That's inferior to the LK2E2000 model.

Ich kann entweder 0 oder 2 (inf und 2E2000) oder 3 (inf, 2E200, 0) Zahlen finden (oder bis zum Äußersten gehen und nach allen Zeichenfolgen suchen, die eine gültige Zahl bilden: 17 (inf, 2, 2E2, 2E20, 2E200, 2E200, 2E2000, 2, 20, 200, 2000, 0, 00, 000, 0, 00, 0)).

Wenn Sie wissen, dass Ihre Eingabe nur Zahlen im X.XXXXXXXXE-XXX enthält und dass es sich um eigene Wörter handelt, ist es möglicherweise sicherer, nur in ganzen Wörtern danach zu suchen:

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

Die Idee dort ist, ein Wort pro Zeile zu erhalten und die gesamte Zeile ( -x) mit dem gewünschten Muster abzugleichen. Um eine wissenschaftliche Notationsnummer (-1,2e + 1234 ... solange es ein eoder gibt E) zuzulassen , können Sie das Muster ändern in:

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

Oder machen Sie das e...Teil optional, um alle Arten von Dezimal-Gleitkommazahlen zuzulassen:

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

Das alles gibt die gleiche Antwort für Ihre spezifische Eingabe, aber wo dies einen Unterschied machen würde, gibt es eine Eingabe, die von dem in Ihrem Beispiel gezeigten strengen Muster abweicht.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.