Thread Datei einlesen und Zeile in anderer Datei suchen (6 answers)
Opened by bora99 at 2021-09-13 16:56

haj
 2021-09-13 20:52
#193571 #193571
User since
2015-01-07
527 Artikel
BenutzerIn

user image
Danke, dass Du das Problem samt Beispieldaten geliefert hast!

Nun ist "Eleganz" ja im Auge des Betrachters, und in meinen Augen kann man da schon ein paar Dinge eleganter machen:
Code (perl): (dl )
1
2
3
4
5
if( ! open( RFH, $TestFile_Read))
  {
  print STDERR "Test File '$TestFile_Read' kann nicht gelesen werden !\n";
  exit 1;
  }

Das schreibe ich so:
Code (perl): (dl )
1
2
open (my $rfh, '<', $TestFile_Read)
    or die "Test File '$TestFile_Read' kann nicht gelesen werden : '$!'\n";

Den open mit drei Parametern zu verwenden, also auch beim Lesen den Modus '<' mit anzugeben, hat sich weitgehend eingebürgert. Eine lexikalische Variable anstelle einer globalen für den Handle anzugeben ist inzwischen ebenfalls üblich. die ersetzt die Kombination print STDERR und exit 1. Und schließlich habe ich auch den Grund des Scheiterns noch in die Fehlermeldung übernommen.

In Deiner while-Schleife mir auf, dass Du $TestFile_Search in jeder Runde der Schleife neu aufmachst - und die Datei nur einmal am Ende schließt. Das ist in diesem speziellen Fall ohne negative Wirkung, aber elegant ist das nicht. Wenn Deine Suchdatei nicht hunderttausend Zeilen umfasst, dann würde ich die einmal einlesen und die Suchpatterns in einem Array speichern. Ausserdem trennst Du in allen Fällen das Zeilenende ab, hängst aber hinterher bei jeder Verwendung von $line wieder ein Zeilenende dran. Das ist defensiv programmiert und sauber, aber "elegant" würde ich beides weglassen.

Und anstelle der Schleife durch die Sucheinträge kann man die in einem einzigen Such-Pattern zusammenfassen: Perl kümmert sich dann darum, dass beim ersten Treffer Schluss ist und $found = 1 (das Du sowieso nicht verwendest, das müsste Dir wegen use strict auf die Zehen fallen) sowie last fallen weg. Das sieht dann insgesamt so aus:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/perl -w
use strict;

my $TestFile_Read   = "testfile_1";
my $TestFile_Search = "testfile_2";

# Suchdatei lesen aufbauen und Pattern aufbauen
open (my $sfh, $TestFile_Search)
    or die "Test File '$TestFile_Search' kann nicht gelesen werden: '$!'\n";
my @search = <$sfh>;
close $sfh;
my $pattern = join "|", map { quotemeta } @search;

# Testdatei lesen und durchschleifen
open (my $rfh, $TestFile_Read)
    or die "Test File '$TestFile_Read' kann nicht gelesen werden: '$!'\n";
while( my $line_r = <$rfh> )
   {
   # print "File_Read: $line_r";
      if( $line_r =~ /^($pattern)$/ )
        {
           print "Gefunden ($TestFile_Read in $TestFile_Search): $line_r";
        }
   }
close $rfh;


Dabei habe ich noch keine Module verwendet. Für Deinen Fall finde ich interessant CPAN:autodie und CPAN:List::Util, die sind beide bei Perl schon mit dabei. Dabei kümmert sich autodie um die Fehlerbehandlung beim Öffnen von Dateien (allerdings mit englischen Fehlermeldungen), und mit List::Util wird's etwas "lesbarer" als mit der Quotemeta-Pattern-Bastelei:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/perl -w
use strict;
use autodie;
use List::Util qw/any/;

my $TestFile_Read   = "testfile_1";
my $TestFile_Search = "testfile_2";

# Suchdatei lesen aufbauen und Pattern aufbauen
open (my $sfh, $TestFile_Search);
my @search = <$sfh>;
close $sfh;

# Testdatei lesen und durchschleifen
open (my $rfh, $TestFile_Read);
while( my $line_r = <$rfh> )
   {
   # print "File_Read: $line_r";
      if( any { $line_r eq $_ } @search )
        {
           print "Gefunden ($TestFile_Read in $TestFile_Search): $line_r";
        }
   }
close $rfh;

View full thread Datei einlesen und Zeile in anderer Datei suchen