Alexander (HH): Perl-Vergleich für zwei Variabeln gleichzeitig

Beitrag lesen

Moin Moin!

Abend Forum

Angenommen ich habe eine CSV-Datei mit folgendem Inhalt:
Obstnummer(Zahl einmalig/Identifizierer), Obsthaltbarkeit(Tage), Obstfarbe, Obstname

Also:
1001, 10, grün, Apfel
1002, 5, rot, Kirsche
1003, 12, gelb, banane
usw...

Jetzt ist es mir möglich, nach einem Kriterium zu filtern (Obstname):

zuerst die Zeile einlesen
my $zeile = <LESER>;

Zeile aufsplitten:
my ($Obstnummer, $Obsthaltbarkeit, $Obstfarbe, $Obstname) = split(/,/,$zeile);

"Schon falsch!!" ist übertrieben, aber CSV-Dateien liest man typischerweise mit Text::CSV ein. Schlicht und ergreifend, weil CSV-Dateien einige Gemeinheiten enthalten können, die mit einem schlichten split nicht zu erschlagen sind, angefangen bei Quotes und Trennzeichen in gequoteten Werten.

Für Deinen trivialen Fall mag split gerade noch ausreichen.

Ist Dir übrigens bewußt, dass die meisten Felder mit einem Leerzeichen anfangen?

Dannach vergleichen:
if($Obstname eq "Banane") {mach was in diesen geschweiften Klammern steht}

Das wird bei deinem Beispiel nie passieren, denn Du hast nur " banane", was etwas deutlich anderes ist als "Banane".

-> Alle Bananen werden selektiert.Bis hierher kein Problem.

Was, wenn man aber alles Obst herausfiltern will, daß zwingend "rot" sein muss _und_ genau eine Haltbarkeit von "5" Tagen hat. Also beide $-Variablen ($Obstfarbe und $Obsthaltbarkeit) mussen zutreffen, damit die Anweisung in der Klammer ausgeführt werden. Wie schreibe ich das am besten?

Ergänzend zu den reinen Perl-Lösungen:

Du kannst mit DBI und DBD::CSV CSV-Dateien als Mini-Datenbanken benutzen, und damit den Weg für einen leichten Wechsel auf "richtige" Datenbanken legen:

  
#!/usr/bin/perl  
  
use strict;  
use warnings;  
  
use DBI;  
use Data::Dumper;  
  
my $dbh=DBI->connect(  
	'dbi:CSV:', # DB-Treiber und DB-Verbindung ("connect string")  
	'',         # Login (sinnfrei für CSV)  
	'',         # Passwort (sinnfrei für CSV)  
	{ # Optionen:  
		# DBI generisch:  
		RaiseError => 1,               # Fehler rufen die() auf  
		AutoCommit => 1,               # Transaktionen explizit starten  
		FetchHashKeyName => 'NAME_lc', # fetchXXX_hashref liefert Spaltennamen in Kleinbuchstaben  
		# spezifisch für DBD::CSV:  
		f_dir => '.',                  # Dateien (=Tabellen) liegen im aktuellen Verzeichnis  
		f_ext => '.csv',               # Dateien haben die Endung ".csv"  
		f_encoding => 'utf8',          # Dateien sind UTF8-codiert  
		csv_eol => "\n",               # Zeilen enden mit "\n"  
		csv_sep_char => ',',           # Spalten sind mit "," getrennt  
		csv_quote_char => '"',         # Strings sind mit '"' gequoted  
		csv_escape_char => '"',        # '"' innerhalb von Strings wird als '""' geschrieben  
		csv_tables => {  
			# Einstellungen für bestimmte Tabellen  
			obst => {  
				# Einstellung für Tabelle "obst"  
				file => 'obst.csv',    # Dateiname (redundant)  
				col_names => [qw( id haltbarkeit farbe name )], # Spaltennamen - stehen normalerweise in der ersten Zeile  
				skip_first_row => 0,   # Erste Zeile enthält schon Datensätze  
			},  
		},  
	}  
);  
  
my $sth=$dbh->prepare(q[  
	SELECT  
		id,  
		name  
	FROM  
		obst  
	WHERE  
		haltbarkeit = ?  
		AND  
		farbe = ?  
]);  
# ^-- Platzhalter benutzen. IMMER. Wenn nicht, sollen Dir die Finger abfaulen.  
$sth->execute(5,"rot");  
while (my $hr=$sth->fetchrow_hashref()) {  
	print Dumper($hr);  
}  
$sth->finish();  
$dbh->disconnect();  

Zugegeben, für Dein Mini-Problem ist das Overkill.

Aber wenn Du irgendwann einmal von CSV-Dateien weg kommst und eine richtige Datenbank benutzt, mußt Du (idealerweise) nur den connect-Aufruf ändern, und das Programm arbeitet ohne weitere Änderungen z.B. mit PostgreSQL:

  
my $dbh=DBI->connect(  
	'dbi:Pg:dbname=obstkiste',  
	'obstler',  
	'geheim',  
	{  
		RaiseError => 1,  
		AutoCommit => 1,´  
		FetchHashKeyName => 'NAME_lc',  
		pg_enable_utf8 => 1,  
	}  
);  

Oder mit Oracle:

  
my $dbh=DBI->connect(  
	'dbi:Oracle:obstkiste',  
	'obstler',  
	'geheim',  
	{  
		RaiseError => 1,  
		AutoCommit => 1,´  
		FetchHashKeyName => 'NAME_lc',  
	}  
);  

Oder mit SQLite:

  
my $dbh=DBI->connect(  
	'dbi:SQLite:dbname=obstkiste.sqlite',  
	'obstler',  
	'geheim',  
	{  
		RaiseError => 1,  
		AutoCommit => 1,´  
		FetchHashKeyName => 'NAME_lc',  
	}  
);  

Oder mit jeder x-beliebigen Datenbank, die per ODBC ansprechbar ist:

  
my $dbh=DBI->connect(  
	'dbi:ODBC:obstkiste',  
	'obstler',  
	'geheim',  
	{  
		RaiseError => 1,  
		AutoCommit => 1,´  
		FetchHashKeyName => 'NAME_lc',  
	}  
);  

Oder mit jeder x-beliebigen Datenbank, die per JDBC ansprechbar ist:

  
my $dbh=DBI->connect(  
	'dbi:JDBC:hostname=obstkiste.example.com;port=9001;url=jdbc:opentext:db:',  
	'obstler',  
	'geheim',  
	{  
		RaiseError => 1,  
		AutoCommit => 1,´  
		FetchHashKeyName => 'NAME_lc',  
	}  
);  

Und notfalls sogar zur DB-Karrikatur MySQL:

  
my $dbh=DBI->connect(  
	'dbi:mysql:database=obstkiste;host=evil.example.com;port=3306',  
	'obstler',  
	'geheim',  
	{  
		RaiseError => 1,  
		AutoCommit => 1,´  
		FetchHashKeyName => 'NAME_lc',  
	}  
);  

Zu Platzhaltern siehe z.B. http://perlmonks.org/?node_id=811732 und http://perlmonks.org/?node_id=839078.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".