Manipulieren Sie das wissenschaftliche Format ohne das "e"

8

Ich versuche, eine Datei zu manipulieren, die Zahlen in wissenschaftlicher Notation enthält, aber ohne das eSymbol, dh 1.2e+3geschrieben als 1.2+3.

Die einfachste Sache , die ich dachte , mit zu tun , awkwar zu ersetzen +mit e+, die unter Verwendung von gsubFunktion und meine Berechnung in der neuen Datei zu tun. Gleiches gilt für den Minusfall. Eine einfache Korrektur kann also mit dem folgenden Befehl durchgeführt werden

awk '{gsub("+", "e+", $1); print $1, $2, $3, $4, $5}' file_in

und machen Sie dasselbe in allen Spalten.

Die Datei enthält jedoch auch negative Zahlen, was die Sache etwas komplizierter macht. Eine Beispieldatei ist unten zu sehen

 1.056000+0 5.000000-1 2.454400-3 2.914800-2 8.141500-6
 2.043430+1 5.000000-1 2.750500-3 2.698100-2-2.034300-4
 3.829842+1 5.000000-1 1.969923-2 2.211364-2 9.499900-6
 4.168521+1 5.000000-1 1.601262-2 3.030919-2-3.372000-6
 6.661784+1 5.000000-1 5.250575-2 3.443669-2 2.585500-5
 7.278104+1 5.000000-1 2.137055-2 2.601701-2 8.999800-5
 9.077287+1 5.000000-1 1.320498-2 2.961020-2-1.011600-5
 9.248130+1 5.000000-1 3.069610-3 2.786329-2-6.317000-5
 1.049935+2 5.000000-1 4.218794-2 3.321955-2-5.097000-6
 1.216283+2 5.000000-1 1.432105-2 3.077165-2 4.300300-5

Irgendeine Idee, wie man mit einer solchen Datei manipuliert und berechnet?

Danke
quelle
2
Wie möchten Sie Berechnungen mit einem Format wie dem 2.698100e-2-2.034300e-4 durchführen?
Ctac_
3
Dies scheint wahrscheinlich als Spaltendaten mit fester Breite analysiert zu werden . Das scheinbare Leerzeichen zwischen den Spalten ist nur ein Artefakt des Zahlenformats, das positive Werte mit einem führenden Leerzeichen anstelle eines Pluszeichens anzeigt.
Ilmari Karonen

Antworten:

14

Ist diese Ausgabe korrekt?

 1.056000e+0 5.000000e-1 2.454400e-3 2.914800e-2 8.141500e-6
 2.043430e+1 5.000000e-1 2.750500e-3 2.698100e-2-2.034300e-4
 3.829842e+1 5.000000e-1 1.969923e-2 2.211364e-2 9.499900e-6
 4.168521e+1 5.000000e-1 1.601262e-2 3.030919e-2-3.372000e-6
 6.661784e+1 5.000000e-1 5.250575e-2 3.443669e-2 2.585500e-5
 7.278104e+1 5.000000e-1 2.137055e-2 2.601701e-2 8.999800e-5
 9.077287e+1 5.000000e-1 1.320498e-2 2.961020e-2-1.011600e-5
 9.248130e+1 5.000000e-1 3.069610e-3 2.786329e-2-6.317000e-5
 1.049935e+2 5.000000e-1 4.218794e-2 3.321955e-2-5.097000e-6
 1.216283e+2 5.000000e-1 1.432105e-2 3.077165e-2 4.300300e-5

Code:

perl -lne 's/(\.\d+)(\+|\-)/\1e\2/g; print' sample

Erläuterung:

  • -lne Achten Sie auf Zeilenenden, verarbeiten Sie jede Eingabezeile und führen Sie den folgenden Code aus

  • s/(\.\d+)(\+|\-)/\1e\2/g::

    • Ersatz ( s)
    • (.\d+)(\+|\-) finde zwei Gruppen von (einem Punkt und Zahlen) und (einem Plus oder Minus)
    • \1e\2Ersetzen Sie sie durch die erste Gruppe und edann durch die zweite Gruppe
    • g global - hören Sie nicht bei der ersten Ersetzung in jeder Zeile auf, sondern verarbeiten Sie alle möglichen Treffer
  • print Drucken Sie die Zeile

  • sample Eingabedatei

Dieser fügt Platz hinzu, wenn er fehlt. Tatsächlich wird unabhängig davon ein Leerzeichen zwischen den Zahlen eingefügt. Dh. Wenn in einigen Fällen zwei Leerzeichen vorhanden wären, wäre nur eines in der Ausgabe vorhanden.

perl -lne 's/(\.\d+)(\+|\-)(\d+)(\s*)/\1e\2\3 /g; print' sample

Das meiste davon ähnelt dem vorherigen. Das Neue ist die (\d+)Gruppe Nr. 3 und die (\s*)Gruppe Nr. 4. *Hier bedeutet optional. In der Substitution wird nein \4verwendet. Es gibt stattdessen ein Leerzeichen.

Die Ausgabe ist folgende:

 1.056000e+0 5.000000e-1 2.454400e-3 2.914800e-2 8.141500e-6 
 2.043430e+1 5.000000e-1 2.750500e-3 2.698100e-2 -2.034300e-4 
 3.829842e+1 5.000000e-1 1.969923e-2 2.211364e-2 9.499900e-6 
 4.168521e+1 5.000000e-1 1.601262e-2 3.030919e-2 -3.372000e-6 
 6.661784e+1 5.000000e-1 5.250575e-2 3.443669e-2 2.585500e-5 
 7.278104e+1 5.000000e-1 2.137055e-2 2.601701e-2 8.999800e-5 
 9.077287e+1 5.000000e-1 1.320498e-2 2.961020e-2 -1.011600e-5 
 9.248130e+1 5.000000e-1 3.069610e-3 2.786329e-2 -6.317000e-5 
 1.049935e+2 5.000000e-1 4.218794e-2 3.321955e-2 -5.097000e-6 
 1.216283e+2 5.000000e-1 1.432105e-2 3.077165e-2 4.300300e-5 

quelle
Vielen Dank für die Antwort! Ja es scheint richtig !! Können Sie erklären, was Sie getan haben, um später darauf zurückgreifen zu können?
Thanos
Ist es auch möglich, die letzte Spalte ($ 5 $) von der vorherigen durch ein Leerzeichen zu trennen?
Thanos
Du bist perfekt! Vielen Dank für Ihre Hilfe!
Thanos
@Thanos Siehe das Update. Und beachte, dass ich .in der ersten Gruppe zuvor einen Backslash hinzugefügt habe . Das ist richtig. Ohne diesen Backslash würde der Punkt keinen wörtlichen Punkt bedeuten.
2

Sie könnten auch verwenden sed, zB:

<infile sed -E 's/([0-9])([+-])([0-9])/\1e\2\3/g' | awk '{ print $1 + 0 }'

Dies berücksichtigt jedoch nicht, dass die Spalten in der OP-Liste manchmal nicht getrennt sind. Hier ist eine Problemumgehung mit angemessener Genauigkeit:

<infile sed -E 's/.{11}/& /g'       |
sed -E 's/([0-9])([+-])/\1e\2/g'    |
gawk '{ print $1 + 0 }' OFMT='%.7g'

Ausgabe:

1.056
20.4343
38.29842
41.68521
66.61784
72.78104
90.77287
92.4813
104.9935
121.6283
Thor
quelle
Dies entfernt die Auflösung aus den Zahlen, und ich bin nicht sicher, ob es funktionieren wird, wenn ein negativer Wert neben einem anderen liegt, wie im Beispiel in der Frage2.698100-2-2.034300-4
Pipe
@pipe: Du hast recht, ich habe dieses Detail verpasst. Ich habe eine Problemumgehung hinzugefügt, indem ich Speicherplatz hinzugefügt habe. Wrt. Genauigkeit, ich habe die OFMTVariable verwendet, um die Genauigkeit von awk auf die gleiche wie die der Eingabe zu setzen
Thor