Problem mit Tie::file und zeilenende
Dauna
- perl
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
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
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
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
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!!!!!!!!!!
(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.
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!!!!!!!!!!!!!!!!!!!!!!!
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
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.
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
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 :-))
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";
}
}
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!
#######################################################
<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
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?
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
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
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ß.
servus!
hey genau das brauch ich klappt alles vielen vielen danke bussi
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.
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
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!
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
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