Schrift
[thread]6057[/thread]

Regex-Problem mit Backreferences (Seite 4)



<< |< 1 2 3 4 5 >| >> 45 Einträge, 5 Seiten
Crian
 2004-02-05 12:54
#79789 #79789
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Ich glaub dann würd ich einen gemischten Ansatz fahren.

1) Splitten bis zum nächsten (bzw. ersten) Anzahlelement oder bis zum Ende, falls keines mehr kommt, so dass der Rest nach dem Anzahlelement im letzten Arrayelement ist.
2) Die Anzahl Zeichen, die im vorletzten Arrayelement steht, aus dem letzten vorn ausschneiden und dazwischenschieben, mit dem letzten Arrayelement bei 1) fortfahren.

Kannst Du Dich denn darauf verlassen, dass die angegebene Anzahl an Zeichen für den folgenden String immer stimmt?
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
DemoFreak
 2004-02-05 17:58
#79790 #79790
User since
2003-09-06
54 Artikel
BenutzerIn
[default_avatar]
Also, ich hab jetzt mal ein wenig anders probiert, und das scheint zu klappen.

Es tat sich zwischendrin noch ein weiteres Problem auf: die Dateien werden auf Unix-Systemen vorgehalten, wo der Zeilenvorschub (in solchen variablen Feldern wie Kommentaren o.ä.) eigentlich 0x0A sein sollte, allerdings gibt es auch Datensätze, wo die Felder auf Windowsmaschinen gepflegt wurden, wodurch dann die Zeilenenden in diesen variablen Feldern 0x0D0x0A sind. Wenn ich jetzt meinen Script auf einer Unixmaschine ausführe, stimmt die Längenangabe des variablen Strings mit der tatsächlichen Länge überein, wenn ich allerdings denselben Script auf einer Windowsmaschine ausführe, fällt er bei den datensätzen, die diese Windowszeilenumbrüche enthalten, auf die Nase, weil er die zwei Zeichen zu einem Metazeichen zusammenzieht und auch nur einfach zählt. Und sagt mir nicht, dass ich das mittels Setzen von $/ umgehen kann, das kann ich nicht. Hat a) keine Wirkung, und b) musste ich das eh anders setzen, weil die Datensätze in den Dateien mit einem Sonderstring markiert sind. Falls jemand eine Idee hat, wie ich dieses Problem adressieren kann, wäre ich sehr dankbar. Momentan helfe ich mir damit, dass ich nicht akkurat einen String der Länge x herausziehe, sondern einen String der Länge 0..x (greedy bis zum nächsten Leerzeichen). Naja... ;)

Ich poste mal den Code, bitte zerrupfen und mich mit der Nase auf unsinnige Ansätze stoßen, ich bin ein Perl-Anfänger auf dem Weg der Besserung. :D

Code: (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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/perl

use strict;
use warnings;

local $/ = "====> ";                                      # Datensatzende ist "====>"

my @ind = (4, 8, 22, 29, 34, 36, 38, 40, 42,
              44, 46, 48, 50, 52, 55, 63, 65, 71,
              73, 75, 77, 85, 87, 92, 94, 99, 101,
             106, 108, 113, 115, 120, 122);              # Indice der Längenfelder für VarStrings

my $filename = shift or die "Kein Dateiname angegeben!";
open XY, "<$filename" or die "Konnte Datei $filename nicht oeffnen!";

while (<XY>) {
   my $line = $_;
   if ($. == 1) {
       die "Datei $filename ist scheinbar kein OVO-Historyfile!" unless ($line =~ "Version 3");
       next;
   };
   my $i = 0;
   my $pnt = 0;
   my @parts;
   while (length($line) > 0) {
       $line =~ s/([^ ]+) //; my $part = $1;
       push @parts, $part;
       next if ($pnt > $#ind);
       if ($i == $ind[$pnt]) {
print "Gotcha! $i - ";
           $line =~ s/(.{0,$part}) //s; my $varstr = $1;
print "$varstr\n";
           push @parts, $varstr;
           $pnt++; $i++;
       }
   } continue {
       $i++;
   }
   for ($i=0; $i<=$#parts; $i++) { print "Element $i: $parts[$i]\n"; }
   print "\n";
}

close XY;


Die nicht eingerückten print sind nur zum Debuggen, einfach wegdenken ;)
Gruss, Hannes
Crian
 2004-02-05 18:40
#79791 #79791
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
1.) Ich würde die Datendatei vorher mit dos2unix konvertieren, dann hast Du die Probleme mit den verschiedenartigen Zeilenumbrüchen vom Hals.


2.) Anstelle von

for ($i=0; $i<=$#parts; $i++)

ist

for my $i (0..$#parts)

perliger und besser lesbar.



3.) Was soll der continue-Block?



4.) Möchtest Du wirklich [^ ] statt \S?


5.) Schreib nicht ([{ohne guten Grund}]) zwei Anweisungen hintereinander in eine Zeile.


6.) Warum setzt Du das Datensatzende auf diesen komischen Pfeil? (Btw ist der Kommentar falsch, da ist noch ein Leerzeichen am Ende des Pfeiles.)


7.) Warum kopierst Du das handliche es ($_) in das unhandliche $line?


8.) Statt

Code: (dl )
1
2
$line =~ s/([^ ]+) //;
my $part = $1;


geht auch (TIMTOWDI)

Code: (dl )
(my $part, $line) = split / /, $line, 2;


und hier ist split imho der RE vorzuzuziehen.


9.) Es ist sehr schön, ob Du den Erfolg von Open testest. Aber bitte gib $! mit aus, da steht drin warum nicht.


10.) Und teste das Schließen von Dateien, die Du schreibst auf Erfolg!



Hab ich alles gefunden? ;) :p\n\n

<!--EDIT|Crian|1076000317-->
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
DemoFreak
 2004-02-05 18:58
#79792 #79792
User since
2003-09-06
54 Artikel
BenutzerIn
[default_avatar]
- Ich kann die Dateien nicht einfach konvertieren, die Daten sollen in der nächsten Ausbaustufe direkt von der Unixmaschine über das Netzwerk gelesen werden. Und sie erst zu kopieren und dann zu wandeln ist bei Dateigrössen um die 40-50MB eher nicht meine Intention. ;)

- Stimmt. Ist schöner.

- Der continue-Block soll garantieren, dass $i auch inkrementiert wird, wenn ich mit next aus der Schleife hüpfe. Ich könnte natürlich $i auch ganz am Anfang inkrementieren und dafür die Indice um jeweils 1 erhöhen... stimmt.

- Naja, ich bin mir nicht ganz sicher. Der Datenfeld-Trenner ist 0x20, was für Bedeutungen hat \s denn ausserdem noch?

- Ok ok :o)

- Das Datensatzende ist durch HP so vorgegeben, deren exportierte Dateien enthalten das so. Danke für den Hinweis bzgl. des Kommentars.\n\n

<!--EDIT|DemoFreak|1076000909-->
Gruss, Hannes
DemoFreak
 2004-02-05 19:04
#79793 #79793
User since
2003-09-06
54 Artikel
BenutzerIn
[default_avatar]
7. Weil ich immer Angst habe, dass ich mir irgendwo $_ überschreibe und mir dann der Inhalt, den ich eigentlich noch haben will, nicht mehr zur Verfügung steht. ;)

8.-9. Jo. Danke. :)

10. Werd' ich versuchen mir zu merken.
Gruss, Hannes
Crian
 2004-02-05 19:09
#79794 #79794
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Auch bei meiner Variante durchläuft $i die Werte von 0 bis zum letzten Arrayindex.

Zum Continueblock: Dann mach lieber am Anfang der inneren Schleife ++$i und lass das ++ weiter hinten und den Continueblock weg.

Statt

Code: (dl )
for ($i=0; $i<=$#parts; $i++) { print "Element $i: $parts[$i]\n"; }


Kannst Du auch ganz elegant schreiben:

Code: (dl )
print "Element $_: $parts[$_]\n" for (0..$#parts);


:D


Wegen der CR LF / LF Problematik: Führ einmal nach dem Einlesen Deiner "Zeile"

s~\r\n~\n~g;

aus. (Du bist doch unter Linux/Unix?)\n\n

<!--EDIT|Crian|1076001657-->
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
DemoFreak
 2004-02-05 20:10
#79795 #79795
User since
2003-09-06
54 Artikel
BenutzerIn
[default_avatar]
- Hab ich dann auch gemerkt, nachdem ich schon geschrieben hatte. :D

- Wenn ich ++$i benutze, wird $i nach dem Durchlaufen der Schleife inkrementiert, auch wenn das ganz vorn steht?

- Das sieht wirklich gut aus. Ohne das jetzt probiert zu haben:
Code: (dl )
map { print Element $_: $parts[$_]\n" } 0..$#parts
sollte wohl auch gehen, und ist sicher noch viel "geekiger". :D

- Ich bin eben nicht unter Linux/Unix, und ausserdem soll der Script zur Not auf beiden Seiten laufen, also will ich solche "Korrekturen" nicht durchführen.
Gruss, Hannes
DemoFreak
 2004-02-05 20:12
#79796 #79796
User since
2003-09-06
54 Artikel
BenutzerIn
[default_avatar]
Ach, noch ein Nachtrag: ich hatte vorhin die eine RE gegen das split ausgetauscht, weil es wirklich besser und verständlicher aussieht, aber split fällt bei dem bewussten CR/LF-Problem ebenfalls auf die Nase. Also bin ich wieder auf

Code: (dl )
1
2
$line =~ s/([^ ]+) //;
my $part = $1;


umgesteiegen. Das funzt. :)
Gruss, Hannes
Crian
 2004-02-05 21:32
#79797 #79797
User since
2003-08-04
5866 Artikel
ModeratorIn
[Homepage]
user image
Hmmm das erstaunt mich, dass die RE geht und Split nicht.

Zu Deiner map-Variante: map im void Kontext ist unfein - genau dafür ist for da - aber sieht schon interessant aus ;-)

Zu den Zeilenumbrüchen: Hmmm.... da brüte ich nochmal drüber... es kann also sein dass Du Dateien mit gemischten Umbrüchen in den Daten bekommst und das Skript sollte sie unter Windows und unter Linux richtig verstehen. Und die Dateien sollen nicht konvertiert werden, weil sie riesig sind und außerdem mal übers Netz geholt werden.... hab ich das jetzt richtig zusammengefasst?
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
DemoFreak
 2004-02-06 21:47
#79798 #79798
User since
2003-09-06
54 Artikel
BenutzerIn
[default_avatar]
Ich würde sagen, ja. :o)

Wobei ich einschränkend dazu sagen muss, dass der Zwang natürlich nicht wirklich besteht. Wenn es ohne unvertretbaren Aufwand nicht anders zu machen ist, als die Dateien vorher zu konvertieren, dann werden sie eben konvertiert. Letzten Endes zählt das Ergebnis. Aber wenn man schon mal was macht und dabei auch noch lernen kann, dann sollte man doch IMHO versuchen, es "richtig" zu machen, oder? ;)
Gruss, Hannes
<< |< 1 2 3 4 5 >| >> 45 Einträge, 5 Seiten



View all threads created 2004-02-04 14:37.