Dauna: Problem mit Tie::file und zeilenende

Servus!

Ich hab ein Problem mit Tie::File.

Folgendes: Ich hab mir eine Flatfile erstellt (txt datei), diese sieht etwa so aus:

###################################
Username, name, passwort, sonstiges
Username2, name2, passowrt2, sonstiges2
###################################
usw.
(In der Datei sind übrigends keine rauten (#)).

Wenn ich Username oder name oder passwort bearbeiten will klappt alles super, aber bei dem letzten wert vor der neuen zeile scheitert es.
Ich habe viel rumprobiert von split über s/ über chomp usw. aber entweder es passiert nichts oder es werden alle Buchstaben in der reihe ersetzt durch die eingabe.

Hier mal ein kleiner Codeausschnitt hoffe ihr könnt mir da helfen!!!!

#!/usr/bin/perl -w

use strict;
use Tie::File;

open (LIST, "<liste.txt");
while (<LIST>)
{
my @ke = split /, /, $_;

my $open = 'liste.txt';
tie my @aenderung, 'Tie::File', $open;
for (@aenderung) {
s/$ke[3]/neuerwert/g;
}
untie @aenderung;
}

natürlich fehlt da noch VIEL mehr code aber ich bin mir sicher das hier irgendwo der fehler liegt.

weiss jemand rat??? danke

  1. weiss jemand rat??? danke

    Ja liess die Anleitung zu Tie::File nochmals bezüglich \n am ende.
    Willst du mit \n das Stringende treffen, dass wird das fehlgehen, weil Tie:File in der foreach schleife anders funktioniert als <File>.

    Übrigens: in jeder Zeile Datei öffnen und Tie:File aufrufen, ist idiotisch.

    mfg Beat

    --
    Woran ich arbeite:
    X-Torah
       <°)))o><                      ><o(((°>o
    1. servus!

      als erstes ich habe die Anleitung gelesen zumindest die von perldoc http://perldoc.perl.org/Tie/File.html
      aber WO steht da bitte eine Lösung zu meinem problem? also ich finde nix.

      Über Tie::file find ich extrem wenige Anleitungen und auf keinem finde ich eine Antwort.

      danke

      1. als erstes ich habe die Anleitung gelesen zumindest die von perldoc http://perldoc.perl.org/Tie/File.html
        aber WO steht da bitte eine Lösung zu meinem problem? also ich finde nix.

        Zunächst wird aus deinem Code das problem nicht klar, weil du uns verschweigst, wonach du in s/// suchst.

        Über Tie::file find ich extrem wenige Anleitungen und auf keinem finde ich eine Antwort.

        Wenn du über einen mit tie gebundenen Array iterierst, dann hat das Alieaselement kein \n am Ende.
        Du aber splittest wohl deinen String so, dass das letzte Element ein "\n" am Ende hat.

        Der Versuch, einen Linefeed anzuhängen erübrigt sich bei Tie File, weil das bei untie automatisch durchgeführt wird.

        "Records read from the tied array do not have the record separator string on the end; this is to allow

        $array[17] .= "extra";

        to work as expected.

        (See autochomp, below.) Records stored into the array will have the record separator string appended before they are written to the file, if they don't have one already. For example, if the record separator string is "\n", then the following two lines do exactly the same thing:

        $array[17] = "Cherry pie";
                $array[17] = "Cherry pie\n";"

        mfg Beat

        --
        Woran ich arbeite:
        X-Torah
        ><o(((°>        ><o(((°>
           <°)))o><                      ><o(((°>o
        1. servus!

          also irgendwie kapier ich das nicht bin ja auch ne frau *hehe

          ich habe doch nirgendswo ein string mit \n am ende.

          Also folgendes:

          Ich lasse daten in ein string eingeben diese werden in eine txt datei geschrieben

          (JEDER EINZELNE CODE IST UNGETESTET!!!!)

          #!/usr/bin/perl
          use strict;

          print "Username: ";
          my $username = <STDIN>;
          chomp $username;
          print "\nName: ";
          my $name = <STDIN>;
          chomp $name;
          print "\nAlter: ";
          my $alter = <STDIN>;
          chomp $alter;
          print "\nSonstiges: ";
          my $sonstiges

          my @speichern = ($username, $name, $alter, $sonstiges);
          open (LIST, "<liste.txt");
          print LIST join ", ","@speichern";
          close LIST;

          Das sieht dann in der txt datei genau so aus:
          ###############################################
          Username, Name, Alter, Sonstiges
          (noch ist hier keine neue zeile!)
          ###############################################
          Also man könnte den text genauso selbst reinschreiben und dennoch klappt es nicht also hat es damit schon einmal nichts zu tun.

          danach will ich es auslesen und ändern:

          #!/usr/bin/perl
          use strict;
          use Tie::File;

          open (LIST, "<liste.txt");
          while (<LIST>) {
          my @ke = split /, /, $_;

          (wenn ich jetzt die einzelnen werte aufzähle funktionieren alle
          $ke[0] = Username
          $ke[1] = Name
          ..
          $ke[3] = Sonstiges
          usw.)
          (jetzt zum aendern:)

          my $ersetzen = <STDIN>;  #hier kommt der text rein den ich gegen das wort ersetzen möchte
          chomp $ersetzen;

          my $open = "liste.txt";
          tie my @aenderung, 'Tie::File', $open;
          for (@aenderung) {
          if ($_ =~ m/Username/) {  #hier such ich nach dem usernamen den ich bearbeiten will
          s/$aenderung[3]/$ersetzen/g;
          }
          untie @aenderung;
          }
          close LIST;

          Das war der code im grossen und ganzen ich weiss nicht was ihr noch wissen möchtet beziehungsweise müsst

          vielen vielen dank schon einmal!!!!!!!!!!

          1. (JEDER EINZELNE CODE IST UNGETESTET!!!!)

            Es ist schwierig anhand von Code den man nicht starten kann nachzuvollziehen, was jetzt konkret dein Problem ist.

            Wenn ich ein lauffähiges Beispiel erstelle, klappt das Problemlos den letzten Wert zu ändern:

            #!/usr/bin/perl -w  
            use strict;  
            use Tie::File;  
            my $open = "liste.txt";  
            unlink $open if -e $open; # löschen  
            tie my @aenderung, 'Tie::File', $open;  
              
            # neu anlegen  
            for(1..10) {  
            push @aenderung, "a$_, b$_, c$_";  
            }  
              
            foreach (@aenderung) {  
            if ($_ =~ m/c10/) {  #hier such ich nach dem usernamen den ich bearbeiten will  
            s/c10/c10 neu/g;  
            }  
            }
            

            Warum benutzt du eigentlich nicht Tie::File auch zum anlegen der Datei?

            Struppi.

            1. Hier das Anmeldeskript

              #########################################################

              #!/usr/bin/perl -w

              use strict;

              print "Username:\n";
              my $nick = <STDIN>;
              chomp $nick;
              print "Name:\n";
              my $name = <STDIN>;
              chomp $name;
              print "Alter:\n";
              my $alter = <STDIN>;
              chomp $alter;
              print "Sonstiges :\n";
              my $sonstiges = <STDIN>;
              chomp $sonstiges;

              my @anmeldung = ($nick, $name, $alter, $sonstiges);

              open (LIST, ">>liste.txt");
              print LIST join(", ", @anmeldung);
              close LIST;

              ###########################################################

              Hier das "Aufrufeskript":

              ############################################################

              #!/usr/bin/perl -w

              use strict;
              use Tie::File;

              print "user suchen: ";
              my $nickname = <STDIN>;
              chomp $nickname;

              open (LIST, "<liste.txt");
              while (<$userlist>) {
              my @ka = split/, /, $_;

              print "Durch was ersetzen: ";
              my $ersetzen = <STDIN>;
              chomp $ersetzen;

              my $open = 'userliste/index.txt';
              tie my @aenderung, 'Tie::File', $open;

              for (@aenderung) {
              if ($_ =~ m/^$nickname/i) {
              s/$ka[6]/$ersetzen/g;
              }
              }
              untie @newchange;
              close LIST;

              #####################################################################

              hoffe ihr könnt mir jetzt helfen!!

              vielen dank!!!!!!!!!!!!!!!!!!!!!!!

              1. Ich habe wieder die gleiche blöde Frage:
                Was ist in $ka[6] drin?
                Steht dort ein "x", dann ersetzt
                      s/$ka[6]/$ersetzen/g
                einfach alle "x".

                Du solltest dir Gedanken über dein Flatfile machen. Einfach nur eine kommaseparierte Liste abzuspeichern ist keine gute Idee, vor allem dann nicht, wenn man aus einem Record dann den Wert zu einem Parameter sucht.

                mfg Beat

                --
                Woran ich arbeite:
                X-Torah
                ><o(((°>      ><o(((°>
                   <°)))o><                      ><o(((°>o
                1. servus.

                  mir fällt grad auf, dass das nicht $ke[6] sein sollte sondern $ke[3]

                  In @ke speichere ich die gesuche line in der txt datei ab.
                  Also das kommt zum beispiel in @ke:
                  Username, name, alter, sonstiges
                  $ke[0] = Username
                  $ke[1] = Name
                  $ke[2] = Alter
                  $ke[3] = Sonstiges

                  Aber das stimmt das alles durch den gleichen buchstaben ersetzt wird also wenn die zeile angenommen
                  Dauna, Nicole, 18, 1
                  heisst und ich die 1 durch 2 ersetzen möchte sieht das so aus
                  Dauna, Nicole, 28, 2

                  ich seh schon Tie::File wird nicht mein freund.

                  Wie kann ich das problem noch lösen?

                  eine Datenbank wie DBI oder DB_File möcht ich nicht benutzen.

                  1. ich seh schon Tie::File wird nicht mein freund.

                    Ich sehe kein Problem mit Tie::File.
                    Ich sehe ein Problem mit deinem File.
                    Es hat kein Konzept von einem Record.
                    Ein Record ist durch eine newline abgeschlossen.

                    Dein Record könnte auch so aussehen
                    <name>Richard</name><nick>Richi</nick>

                    Und dein Suche/Ersetze Pattern
                    s{<name>Richard</name>}{<name>Hannes</name>}

                    mfg Beat

                    --
                    Woran ich arbeite:
                    X-Torah
                       <°)))o><                      ><o(((°>o
                    1. servus!

                      daran hab ich gar nicht gedacht oh man hab schonmal rumprobiert und alles klappt wie es sollte

                      VIELEN DANK AN DICH DU BIST KLASSE :-))

                      1. servus!

                        sooooo nachdem ich mich jetzt länger mit dem neuen plan beschäftige steht schon das nächste problem vor der tür. also meine datei sieht jetzt so aus

                        #######################################################
                        <username>Dauna</username>
                        <name>Nicole</name>
                        <alter>18</alter>
                        <sonstiges>perl</sonstiges>
                        #######################################################
                        (ohne die rauten (#))

                        Das ändern geht leicht nur das aufrufen ist für mich unmöglich.
                        Also ich möchte jetzt zum beispiel "Nicole" angezeigt bekommen dazu schreib ich die datei beziehungsweise den namensraum in ein array und splitte ihn, mein versuch sieht so aus:

                        #!/usr/bin/perl -w

                        use strict;

                        open (LIST, "<list.txt");

                        while (<LIST>) {
                        if ($_ =~ m/<username>Dauna</username>/i) {
                        my @ke = split/<\w+>\w+</\w+>\s+/, $_;
                        print "$ke[0]\n"
                        print "$ke[1]\n";

                        usw.

                        }
                        }
                        close LIST;

                        aber das ist natürlich ein komplett falscher ansatz das merk ich selber :-(

                        langsam mach ich mich etwas peinlich hier ich total noob hehe

                        danke!

                        1. #######################################################
                          <username>Dauna</username>
                          <name>Nicole</name>
                          <alter>18</alter>
                          <sonstiges>perl</sonstiges>
                          #######################################################
                          (ohne die rauten (#))

                          Warum schreibst du nicht eine zeile pro User

                          <userid>1</userid><username>Dauna</username><name>Nicole</name><alter>18</alter><sonstiges>perl</sonstiges>
                          <userid>2</userid><username>Kalle</username><name>Noona</name><alter>1</alter><sonstiges>js</sonstiges>

                          Das ändern geht leicht nur das aufrufen ist für mich unmöglich.
                          Also ich möchte jetzt zum beispiel "Nicole" angezeigt bekommen dazu schreib ich die datei beziehungsweise den namensraum in ein array und splitte ihn, mein versuch sieht so aus:

                          #!/usr/bin/perl -w

                          use strict;

                          open (LIST, "<list.txt");

                          while (<LIST>) {
                          if ($_ =~ m/<username>Dauna</username>/i) {
                          my @ke = split/<\w+>\w+</\w+>\s+/, $_;
                          print "$ke[0]\n"
                          print "$ke[1]\n";

                          usw.

                          }
                          }
                          close LIST;

                          aber das ist natürlich ein komplett falscher ansatz das merk ich selber

                          my %user;

                          while (<LIST>) {
                            if ($_ =~ m/<username>Dauna</username>/i) {
                              while( $_ =~ s/^<(\w+)>([^<>]*)</\1>// ){
                                 # wir verwenden while mit s/// um eine Endlosschleife zu vermeiden
                                 # während du ein Tagname und Werte und \1 wieder Tagname findest
                                 # Speichere Tagname in $1 und wert in $2
                                 $user{$1} = $2 || ''; # $2 könnte leer sein
                              }
                            }
                          }

                          mfg Beat

                          --
                          Woran ich arbeite:
                          X-Torah
                             <°)))o><                      ><o(((°>o
                          1. servus!

                            danke schonmal leider klappt irgendetwas nicht.
                            gibt es keine möglichkeit das in ein array einzuspeichern und wieder auszulesen? ich fühle mich mit einem array sicherer und weiss besser damit umzugehen.

                            danke

                            struppi ich benutze Tie::File darum nicht weil ich es in diesem skript nicht brauche und extra einbinden zum öffnen wenns doch auch einfacher geht ist doch nicht wirklich sinnvoll oder?

                            1. servus!

                              danke schonmal leider klappt irgendetwas nicht.
                              gibt es keine möglichkeit das in ein array einzuspeichern und wieder auszulesen?

                              natürlich

                              ich fühle mich mit einem array sicherer und weiss besser damit umzugehen.

                              Das bezweifle ich.

                              print $user[3]

                              Was ist da drin? In welchem element ist schon wieder der name?

                              print $user{name}

                              struppi ich benutze Tie::File darum nicht weil ich es in diesem skript nicht brauche und extra einbinden zum öffnen wenns doch auch einfacher geht ist doch nicht wirklich sinnvoll oder?

                              Tie::File ist immer dann richtig, wenn dein File entweder grösser ist, oder Tendenz zum Wachstum hat.
                              Es ist eigentlich nie falsch.
                              Das kann man von open() nicht nicht sagen.

                              mfg Beat

                              --
                              Woran ich arbeite:
                              X-Torah
                                 <°)))o><                      ><o(((°>o
                              1. servus

                                ok danke werde mir in zukunft merken tie::file zu benutzen!

                                aber was meinst du mit $user[3]?

                                und wie mus ich jetzt splitten? ich probiere jetzt schon seit 11 uhr und nichts klappt ich hab es auch geschafft das alle werte brav aufgelistet werden aber sobald ein wert ein leerzeichen enthält ist wieder alles durcheinander.

                                danke

                                1. Bleib erstmal noch bei open() bis du Tie::File verstehst.

                                  Mach aus deiner Datei folgende Struktur:

                                  <username>Dauna</username><name>Nicole</name><alter>18</alter><sonstiges>perl</sonstiges>
                                  <username>DerDieDas</username><name>Alex</name><alter>19</alter><sonstiges>perl lernen</sonstiges>

                                  Datei öffnen
                                  In eine while/for schleife einlesen lassen
                                  Splitte so:
                                  @teile = split(/<.+?>(?!<)/, $_);

                                  (ungetestet!)

                                  Gruß.

                                  1. servus!

                                    hey genau das brauch ich klappt alles vielen vielen danke bussi

                        2. sooooo nachdem ich mich jetzt länger mit dem neuen plan beschäftige steht schon das nächste problem vor der tür. also meine datei sieht jetzt so aus

                          und ich frag mich immer noch, warum du nicht Tie::File verwendest?

                          Struppi.

                        3. also meine datei sieht jetzt so aus
                          [...]

                          Die Struktur ist nicht optimal. Du vermischst CSV mit XML und machst es Dir damit unnötig schwer. Entweder Du bleibst - wie ursprünglich - bei CSV, oder Du setzt XML ein, dann aber konsequent.

                          Wären Deine Daten so aufgebaut, wie im Ursprungsposting, wäre die Ausgabe ein Leichtes:

                          my $user = 'Nicole';  
                          while(<LIST>) {  
                            next unless /$user/;  
                            my ($name, $vname, $age, $status) = split /,/;  
                            print "$vname $name ist $age Jahre alt und hat den Status $status\n";  
                          }
                          

                          (ungetestet)

                          Siechfred

                          --
                          Obacht, hinter jedem noch so kleinen Busch könnte ein Indianer sitzen!
                          1. servus!

                            auslesen kann ich es ja so oder so nur mit dem ändern gibt es ein problem.

                            ich weiss das es umständlicher ist aber so wie in meinem jetzigen beispiel gefällt es mir besser vorallem da ich es so in mehreren bereichen nutzen kann und es übersichtlicher ist.

                            danke!

                            1. auslesen kann ich es ja so oder so nur mit dem ändern gibt es ein problem.

                              Nein, auch das ist kein Problem:

                              use Tie::File;  
                                
                              my $file = 'user.txt';  
                              tie my @userlist, 'Tie::File', $file or die "Couldn't tie $file: $!";  
                                
                              my $vname = 'Nicole';  
                              my $status = 2;  
                              for my $i ( 0..$#userlist ) {  
                                my @dummy = split /,/, $userlist[$i];  
                                next if $dummy[1] ne $vname;  
                                $dummy[3] = $status;  
                                $userlist[$i] = join ',', @dummy;  
                              }  
                                
                              untie @userlist;
                              

                              Natürlich lässt sich das noch verfeinern, aber das Prinzip sollte doch einleuchten, oder?

                              Siechfred

                              --
                              Obacht, hinter jedem noch so kleinen Busch könnte ein Indianer sitzen!
          2. my @speichern = ($username, $name, $alter, $sonstiges);
            open (LIST, "<liste.txt");

            open (LIST, ">", "liste.txt") or die("Zugriff verweigert $!");

            print LIST join ", ","@speichern";

            warum "@array" ???

            close LIST;

            Wichtig: Deine Datei besteht aus nur einer Zeile, die zudem nicht durch ein Linefeed abgeschlossen ist.

            Das sieht dann in der txt datei genau so aus:
            ###############################################
            Username, Name, Alter, Sonstiges
            (noch ist hier keine neue zeile!)
            ###############################################
            Also man könnte den text genauso selbst reinschreiben und dennoch klappt es nicht also hat es damit schon einmal nichts zu tun.

            danach will ich es auslesen und ändern:

            #!/usr/bin/perl

            use warnings;

            use strict;
            use Tie::File;

            open (LIST, "<liste.txt");
            while (<LIST>) {
            my @ke = split /, /, $_;

            (wenn ich jetzt die einzelnen werte aufzähle funktionieren alle
            $ke[0] = Username
            $ke[1] = Name
            ..
            $ke[3] = Sonstiges
            usw.)
            (jetzt zum aendern:)

            my $ersetzen = <STDIN>;  #hier kommt der text rein den ich gegen das wort ersetzen möchte
            chomp $ersetzen;

            my $open = "liste.txt";
            tie my @aenderung, 'Tie::File', $open;

            mach mal:
            print scalar @aenderung;

            Der Array @aenderung enthält die Elemente, welche durch den in Tie::File verwendeten recsep ("\n") definiert werden. Da du kein "\n" hast hast du genau ein Array Element.

            for (@aenderung) {
            if ($_ =~ m/Username/) {  #hier such ich nach dem usernamen den ich bearbeiten will
            s/$aenderung[3]/$ersetzen/g;

            Die Bedingung $_ eq $aenderung[3] ist genau beim dritten Element des Arrays erfüllt. Weil dein File aber nur aus einer Zeile besteht, tritt der Fall nie ein. $aenderung[3] ist undefined
            Ürigens gilt: manipuliere nie ein Arrayelement, über welches du gerade iterierst, sondern nur den Alias des gegenwärtige Elements.

            aber vielleicht meinst du auch $ke[3]

            }
            untie @aenderung;
            }
            close LIST;

            Bitte teste deinen Code, bevor du hier postest.

            mfg Beat

            --
            Woran ich arbeite:
            X-Torah
            ><o(((°>       ><o(((°>
               <°)))o><                      ><o(((°>o