Diese Website existiert nur weil wir Werbung mit AdSense ausliefern.
Bitte den AdBlocker daher auf dieser Website ausschalten! Danke.

Massenänderung einer CSV-Datei

Alles rund um die verschiedenen Konsolen und shells sowie die Programmierung unter Linux

Moderator: Moderatoren

Antworten
Heart
Hacker
Hacker
Beiträge: 449
Registriert: 10. Jul 2004, 14:37

Massenänderung einer CSV-Datei

Beitrag von Heart »

Hi,

ich habe eine csv-Datei, die so aussieht:

Code: Alles auswählen

18.02.2005,05:05,1.3066,1.3068,1.3065,1.3066,1
18.02.2005,05:10,1.3068,1.3072,1.3065,1.3068,21
.....usw.
Der zweite Wert ist also die Zeit.

Wie kann ich mittels einem Skript bei allen Zeilen dieser Datei die Zeit um 1 Stunde zurücksetzen?

Die Datei sollte also im obigen Bsp dann so aussehen:

Code: Alles auswählen

18.02.2005,04:05,1.3066,1.3068,1.3065,1.3066,1
18.02.2005,04:10,1.3068,1.3072,1.3065,1.3068,21
.....usw.
Vielen Dank
Desktop 10/2012
Benutzeravatar
regexer
Advanced Hacker
Advanced Hacker
Beiträge: 1005
Registriert: 3. Dez 2004, 09:29
Wohnort: $_

Beitrag von regexer »

Hallo!
Die Lösung könnte ziemlich kompliziert aussehen. Wenn man z.B. als Zeit "01.03.2005,00:45" hat, muss das Programm schlau genug sein und "28.02.2005,23:45" ausgeben. Wenn man es ganz sauber machen will, muss man sogar einen eventuellen Jahreswechsel bzw. Schaltjahrberechnung in betracht ziehen.

Das alles kann man aber umgehen, indem man auf das Computer-interne Datumsformat (Sekunden seit 1. Jan 1970) umwandelt, anschließend 3600 Sekunden abzieht und das Ergebnis wieder in das "normale" Format zurückwandelt. In der Scriptsprache Perl sieht dann die Lösung so aus:

Code: Alles auswählen

#!/usr/bin/perl

use Time::Local;

while (<>) {
  # Aus der Eingabezeile das Datum holen
  ($day, $mon, $year, $hour, $min)=(split /[.,:]/)[0..4];

  # in Sekunden umwandeln
  $year-=1900;
  $time = timelocal(0,$min,$hour,$day,$mon,$year);

  # minus 3600 Sekunden
  $time-=3600;

  # zurueckwandeln
  ($n_min, $n_hour, $n_day, $n_mon, $n_year) =(localtime($time))[1..5];
  $n_year+=1900;

  # die ersten 16 Zeichen der Eingabezeile loeschen
  s/^.{16}//;

  # Datum formatiert ausgeben
  printf "%02d.%02d.%04d,%02d:%02d",
         $n_day, $n_mon, $n_year, $n_hour, $n_min;

  # Rest der Zeile ausgeben
  print;
}
Der Aufruf funktioniert wiefolgt:

Code: Alles auswählen

script.perl <eingabe.csv >ausgabe.csv
Heart
Hacker
Hacker
Beiträge: 449
Registriert: 10. Jul 2004, 14:37

Beitrag von Heart »

Super, werde das gleich heute abend @home testen....

VIELEN DANK dafür!!!
Desktop 10/2012
Benutzeravatar
regexer
Advanced Hacker
Advanced Hacker
Beiträge: 1005
Registriert: 3. Dez 2004, 09:29
Wohnort: $_

Beitrag von regexer »

Vorsicht! Fehler!
Ich muss mein Script korrigieren, da die funktionen timelocal bzw. localtime die Monate bei 0 beginnend zählen. (Januar ist Monat Nr. 0 und nicht Monat 1). Bitte also folgende Version nehmen:

Code: Alles auswählen

#!/usr/bin/perl

use Time::Local;

while (<>) {
  # Aus der Eingabezeile das Datum holen
  ($day, $mon, $year, $hour, $min)=(split /[.,:]/)[0..4];

  # in Sekunden umwandeln
  $mon--;
  $year-=1900;
  $time = timelocal(0,$min,$hour,$day,$mon,$year);

  # minus 3600 Sekunden
  $time-=3600;

  # zurueckwandeln
  ($n_min, $n_hour, $n_day, $n_mon, $n_year) =(localtime($time))[1..5];
  $n_mon++;
  $n_year+=1900;

  # die ersten 16 Zeichen der Eingabezeile loeschen
  s/^.{16}//;

  # Datum formatiert ausgeben
  printf "%02d.%02d.%04d,%02d:%02d",
         $n_day, $n_mon, $n_year, $n_hour, $n_min;

  # Rest der Zeile ausgeben
  print;
}
Sorry!
Heart
Hacker
Hacker
Beiträge: 449
Registriert: 10. Jul 2004, 14:37

Beitrag von Heart »

...works like a charme :wink:

Nochmals DANKE
Desktop 10/2012
Heart
Hacker
Hacker
Beiträge: 449
Registriert: 10. Jul 2004, 14:37

Beitrag von Heart »

Kannst Du mir nochmal behilflich sein? Das Format hat sich ein wenig geändert. Jetzt müssten 5 Minuten subtrahiert ...

Aus
FDAXU7,I,20070702,080500,8038.00,8038.00,8025.00,8031.50,1236,0
sollte also
FDAXU7,I,20070702,080000,8038.00,8038.00,8025.00,8031.50,1236,0
werden....
Desktop 10/2012
Heart
Hacker
Hacker
Beiträge: 449
Registriert: 10. Jul 2004, 14:37

Beitrag von Heart »

Danke an ZaB|SHC| (#linux-club.de Chat), hier die Lösung für die Nachwelt:

Code: Alles auswählen

#!/usr/bin/perl

use Time::Local;

while (<>) {
  # Aus der Eingabezeile das Datum holen
  $line = $_;
  ($year_month_day, $hour_min_second)=(split /,/, $line)[2..3];
  $year_month_day =~ /(\d{4})(\d{2})(\d{2})/;
  $year = $1 - 1900;
  $mon = $2 -1;
  $day = $3;
  $hour_min_second =~ /(\d{2})(\d{2})/;
  $hour = $1;
  $min = $2;

  # in Sekunden umwandeln
  $time = timelocal(0,$min,$hour,$day,$mon,$year);

  # minus 3600 Sekunden
  $time-=300;

  # zurueckwandeln
  ($n_min, $n_hour, $n_day, $n_mon, $n_year) =(localtime($time))[1..5];
  $n_mon++;
  $n_year+=1900;

  # die ersten 16 Zeichen der Eingabezeile loeschen
  $line =~ s/$year_month_day/$n_year . sprintf('%02d', $n_mon) . sprintf('%02d',$n_day)/e;
  $line =~ s/$hour_min_second/sprintf('%02d', $n_hour) . sprintf('%02d', $n_min) . '00'/e;

  # Rest der Zeile ausgeben
  print $line;
}
Desktop 10/2012
Antworten