G. Thomas: Probleme bei exaktem Suchbegriff

Hi,

also ich hab ein einfaches Script welches eine durch Tabulatoren getrennte "Textdatenbank" durchsuchen soll. Klappt auch alles wunderbar, bis auf die Sachen mit dem exaktem Suchbegriff.

if ($Line[1]=~ /\b$Search\b/i)
{
&search;
}

so habe ich ihn implementiert. Durch die \b Einträge sollte das Script doch eigentlich nur dann einen Treffer melden wenn der Suchbegriff 100% (bei mir noch mit /i) mit dem in der Textdatei übereinstimmt, oder? Tja schön wärs...

Ich habe z.B. Einträge wie:
NNR-0.6-S3
NNR-1.2-S3
NNR-1.8-S3
NNR-2.4-S3

Wenn ich jetzt nach "nnr" oder "NNR" suche sollte das Script eigentlich nichts finden, tut es aber doch nämlich alle diese Einträge obwohl ich mit dem \b das doch eigentlich verhindern wollte!

Weiß jemand was ich da falsch mache und könnte mir ggf. einen Lösungsvorschlag posten?

best regards
G. Thomas

  1. hi!

    if ($Line[1]=~ /\b$Search\b/i)

    [...]

    Ich habe z.B. Einträge wie:
    NNR-0.6-S3
    NNR-1.2-S3
    NNR-1.8-S3
    NNR-2.4-S3
    Wenn ich jetzt nach "nnr" oder "NNR" suche sollte das Script eigentlich nichts finden, tut es aber doch
    nämlich alle diese Einträge obwohl ich mit dem \b das doch eigentlich verhindern wollte!

    \b erkennt Wortgrenzen, in deinem Fall also den Anfang der Zeile und den Strich. Was du suchst, ist
    wahrscheinlich \s.

    Siehe auch "perldoc perlre".

    bye, Frank!

    1. Hallo Ihr!

      \b erkennt Wortgrenzen, in deinem Fall also den Anfang der Zeile und den Strich. Was du suchst, ist
      wahrscheinlich \s.

      Konkreter ist hier wohl \t gefragt, da ja zwischen den Tabs auch Einträge mit Leerzeichen vorkommen könnten. Natürlich weiß ich nicht, wie das in diesem Fall ausschaut ...

      Wenn man jetzt aber nach \t$Search\t sucht, gibt es das Problem, daß die Einträge am Rand nicht gefunden werden. Diese müssten dann alternativ zu \t zugelassen werden:
      (^\t)$Search(\t$)

      Möchte man mit diesem Ausdruck die Eintraäge eventuell ersetzen, hat man jedoch das Problem, daß mal Tabs mit gematched werden und mal nicht. Insbesondere beim mehrfachen Ersetzen (Option g) geht das ganze in die Hose, da der Tabulator am Ende des einen Treffer nicht mehr als Anfang für den nächsten Treffer herangezogen wird. Hier bräuchte man wieder einen Ausdruck, der den Tabulator als Begrenzer zwar erkennt, jedoch nicht mit ins Ergebnis zieht. Hier helfen die "zero-width lookahead assertions" bzw. "zero-width lookbehind assertions":
      (^(?<=\t))$Search((?=\t)$)

      Wenn man statt der "positive" Variante (= bedeutet hier ein Tab muss vorkommen) die "negative" Variante verwendet (mit ! für ungleich), würde man so etwas formulieren wie "es darf kein Zeichen folgen, daß kein Tab ist" (?![^\t]). Ein Zeilenende wäre also auch o.k.:
      (?<![^\t])$Search(?![^\t])

      Jetzt sieht das ganze endlich so verwirrend aus, daß man spätestens nächste Woche nicht mehr genau weiß, was man damit bezweckt hat ;-)

      Gruß,
         Jörk

      1. Hi nochmal,

        danke für eure Mühen, allerdings klappt das irgendwie nicht :(
        Hier mal das Script, vielleicht hab ich mich auch blöd ausgedrückt:

        #!/usr/bin/perl

        DB Abfrage

        Temporäre Usereingabe, später Formular

        print "Suche nach?\n";
        $Search = <STDIN>;
        chomp($Search);

        if ($Search eq '')
        {
          print "Sie muessen einen Suchbegriff eingeben!\n";
          die;
        }

        $Count = 0;

        open (DBASE, "Mappe.txt") die "Kann File nicht oeffnen:$!";

        Durchsuchen der ersten Kategorien nach dem Suchbegriff

        while (<DBASE>)
        {
        @Line = split(/\t/, $_);

        if ($Line[0]=~ /\b$Search\b/) # hae!?
        {
        &search;
        }

        if ($Line[1]=~ /\b$Search\b/i)
        {
        &search;
        }

        if ($Line[2]=~ /\b$Search\b/i)
        {
        &search;
        }

        if ($Line[3]=~ /\b$Search\b/i)
        {
        &search;
        }

        if ($Line[4]=~ /\b$Search\b/i)
        {
        &search;
        }

        } # Ende der While Schleife
        close(DBASE);

        if ($Count == '0')
        {
          print "Leider kein Treffer\n";
        }
        else
        {
        print "Es wurde(n) $Count Uebereinstimmung(en) gefunden\n";
        }

        SUB fuer die Ausgabe der gefundenen Ergebnisse

        sub search
        {
        if ($Count == '0')
        {
          print "Suche nach $Search brachte folgende Ergebnisse:\n\n";
        }
          $Count++;
        if ($Line[5] ne '')
        {
          print "Beschreibung: $Line[5]\n";
        }
        if ($Line[6] ne '')
        {
          print "Heizschlauch Spannung: $Line[6]\n";
        }
        if ($Line[7] ne '')
        {
          print "Heizschlauch Serie: $Line[7]\n";
        }
        if ($Line[8] ne '')
        {
          print "Duesentyp: $Line[8]\n";
        }
        if ($Line[9] ne '')
        {
          print "Anzahl der Bohrungen: $Line[9]\n";
        }
        if ($Line[10] ne '')
        {
          print "Durchmesser der Bohrung: $Line[10]\n";
        }
        if ($Line[11] ne '')
        {
          print "Preis APRO: $Line[11] DM\n";
        }
        } #Ende SUB

        1. hi!

          »»  @Line = split(/\t/, $_);
          »»  if ($Line[0]=~ /\b$Search\b/) # hae!?

          Das ist ja Quatsch. Wenn du die Zeile so splittest, hast du ja schon alle Tabs rausgeschmissen und
          kannst anhand derer nichts mehr überprüfen. Wenn der String also jetzt _genau_ mit dem gesuchten
          String übereinstimmen soll, verwendest du einfach ein
            if ($Line[x] eq $Search)

          Wenn der gesuchte String nur vorkommen soll, verwendest du einen regulären Ausdruck. In diesem Fall
          ist es wahrscheinlich egal, wo genau der String vorkommt, also kannst du einen regulären Ausdruck über
          die ganze Zeile machen (hat jetzt nichts mit deinem spezifischen Problem zu tun):
            if (/$Search/i) bzw. if (/$Search/)

          btw. Um zu überprüfen, ob eine Variable gefüllt ist, verwendest du einfach "if ($var)", um zu überprüfen,
          ob sie leer ist, verwendest du "if (!$var)". Das ist einfacher und imho aussagekräftiger.

          bye, Frank!

          1. Hallo ihr beiden!

            »»  @Line = split(/\t/, $_);
            »»  if ($Line[0]=~ /\b$Search\b/) # hae!?

            Das ist ja Quatsch. Wenn du die Zeile so splittest, hast du ja schon alle Tabs rausgeschmissen und
            kannst anhand derer nichts mehr überprüfen. Wenn der String also jetzt _genau_ mit dem gesuchten
            String übereinstimmen soll, verwendest du einfach ein
              if ($Line[x] eq $Search)

            Richtig! Bislang bin ich (und Frank wohl auch) davon ausgegangen, daß Du etwas in folgender Form verwendest:
            while (<DBASE>)
            {
              if (/(?<![^\t])$Search(?![^\t])/i)
              {
                &search;
              }
            }

            Wenn Du jedoch nur die ersten fünf Spalten prüfen möchtest könntest Du auch wieder einen String bilden, in dem diese fünf Spalten mit einem Tab getrennt sind:
            while (<DBASE>)
            {
              @Line = split(/\t/, $_);
              $toTest = join(/\t/, @line[0..4])
              if ($toTest =~ /(?<![^\t])$Search(?![^\t])/i)
              {
                &search;
              }
            }

            btw. Um zu überprüfen, ob eine Variable gefüllt ist, verwendest du einfach "if ($var)", um zu überprüfen,
            ob sie leer ist, verwendest du "if (!$var)". Das ist einfacher und imho aussagekräftiger.

            Falsch! Oder besser: bedingt Richtig ... Der einstellige String '0' z.B. wird hierdurch als leer erkannt. Meistens möchte man aber wissen, ob gar kein Text enthalten ist. In diesem Falle muß man die Variable wohl oder übel mit einem leeren String vergleichen.

            Gruß,
               Jörk

            1. Hi,

              Dankeschön für eure Hilfe, klappt jetzt wunderbar!

              best regards
              GT