Schrift
[thread]12923[/thread]

Text zwischen def. Tags in Blöcke mit def. Länge aufteilen.

Leser: 1


<< |< 1 2 >| >> 12 Einträge, 2 Seiten
leo11
 2008-12-21 14:05
#117378 #117378
User since
2008-08-14
250 Artikel
BenutzerIn
[default_avatar]
Hallo liebe Perl-Fans.

Ich habe ein Programm geschrieben, dass den Text:

BEFORE> <Text>ZeileA
ZeileB
ZeileC</Text>After
<Text>Zeile1
Zeile2 Zeil3</Text>After2

in folgenden umwandelt:

BEFORE>
<Text>Zeil</Text>
<Text>eA Z</Text>
<Text>eile</Text>
<Text>B Ze</Text>
<Text>ileC</Text>
After
<Text>Zeil</Text>
<Text>e1 </Text>
<Text>Zeil</Text>
<Text>e2 Z</Text>
<Text>eil3</Text>
After2

Das Programm sieht 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#!/usr/bin/perl -n

BEGIN {
    use strict;
    use warnings;
    #use Data::Dumper;

    my $filename = $ENV{FILENAME};
    unless (defined($filename)) {die "No filename in environment (filename)\n";}

    @ARGV = $filename;

    my $flag = '0';
    my @lines;
    my $whole_match;
    my @part_before_match;
    my @part_after_match;
    my @number_of_matches;
}

if ( $_ =~ m/<Text>/ ) {
    $flag = '1';
}

if ( $flag == '1' ) {
    $_ =~ s/\r\n//;
    $_ =~ s/\n//;
    $whole_match = $whole_match . $_ . " ";
    if ( $_ =~ m/<\/Text>/ ) {
        $flag = '0';
        @number_of_matches = $whole_match =~ m/(Text>)/g;
        if ( scalar(@number_of_matches) > 2 ) { 
            die "More then one Text in one line.";
        }
        @part_before_match = $whole_match =~ /(.*)(?=<Text>)/;
        @part_before_match->[0] =~ s/^ *$//g;
        @part_after_match = $whole_match =~ /(?<=<\/Text>)(.*)/;
        @part_after_match->[0] =~ s/^ *$//g;
        $whole_match =~ s/[^<]*<Text>//;
        $whole_match =~ s/<\/Text>.*//s;
        @lines = $whole_match =~ m/(.{1,4})/g;
        if ( defined @part_before_match &&  @part_before_match->[0] ne "") {print "@part_before_match\n";}
        #print Dumper @part_before_match;
        foreach my $line (@lines) {
            print "    <Text>$line</Text>\n";
        }
        if ( defined  @part_after_match && @part_after_match->[0] ne "") {print "@part_after_match\n";}
        #print Dumper @part_after_match;
        undef @lines;
        undef $whole_match;
        undef @part_before_match;
        undef @part_after_match;
        undef @number_of_matches;
    }
}
else {
    print;
}


a.)So richtig überzeugt bin ich von meiner Umsetzung nicht. Was haltet ihr davon?

b.)Für die Dateien die ich habe macht es seinen Dienst. Trotzdem würd ich gern den Fall abfangen, dass es auch geht wenn ich Zeilen habe in denen mehr als einmal die Kombination <Text>....</Text> vorkommt.
Gast Gast
 2008-12-21 14:40
#117379 #117379
Ist das da oben denn das was am Ende wirklich ausgegeben werden soll? Ich kann da beim besten Willen irgendwie keine reghelmäßigkeit erkennen, ich haette ja mit sowas gerechnet:

BEFORE> <Text>ZeileA
ZeileB
ZeileC</Text>After

BEFORE>
<Text>ZeileA</Text>
<Text>ZeileB</Text>
<Text>ZeileC</Text>
After

Aber auf deine Ausgabe kann ich mir leider keinen Reim machen, wie genau soll denn die Ausgabe aussehen?

MfG
styx-cc
 2008-12-21 14:44
#117380 #117380
User since
2006-05-20
533 Artikel
BenutzerIn

user image
Hm, jetzt glaub ichs zu sehen, du willst immer 4 Zeichen zwischen <Text> und </Text> haben?
Hatte ich anfangs nicht gesehen, da bei dir in der Ausgabe eine Zeile auch nur drei Zeichen dazwischen hat (<Text>e1 </Text>).

MfG
Pörl.
leo11
 2008-12-21 14:54
#117381 #117381
User since
2008-08-14
250 Artikel
BenutzerIn
[default_avatar]
styx-cc+2008-12-21 13:44:24--
Hm, jetzt glaub ichs zu sehen, du willst immer 4 Zeichen zwischen <Text> und </Text> haben?

Ja genau. nach dem Skript sollen es immer 4 Zeichen zwischen den beiden Tags sein.

Der zu verarbeitende Text ist leider etwas komisch formatiert. Hier mal ein anderes Bsp.:
<Feld><Text>Hallo liebe Perl-Gemeinde,
ich wünsche euch ein schönes Fest und
einen guten Rustch ins neue
Jahr.</Text></Feld><Sig>
abc</Sig>
...

soll werden zu:
<Feld>
<Text>Hall</Text>
<Text>o li</Text>
<Text>ebe </Text>
<Text>Perl</Text>
<Text>-Gem</Text>
...
styx-cc
 2008-12-21 15:59
#117382 #117382
User since
2006-05-20
533 Artikel
BenutzerIn

user image
Bitte schön:

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
#!/usr/bin/perl -w
use strict;
use Data::Dumper;

local $/ = '';
my $data = <DATA>;

do {
$data =~ m|(<Text>.+</Text>)|s;
my $prepared_string = prepare_string($1);
$data =~ s/$1/$prepared_string/s;
} while($1);

print Dumper $data;

## subs ##
sub prepare_string {
my $string = shift;
$string =~ s/\n|<Text>|<\/Text>//g;

my $chunk_size = 4;
my $prepared_string;
for (my $i = 0; $i <= length($string); $i=$i+4) {
my $part = substr($string, $i, $chunk_size);
$prepared_string .= "<Text>$part</Text>\n";
}
return $prepared_string;
}

__DATA__
<Feld><Text>Hallo liebe Perl-Gemeinde,
ich wünsche euch ein schönes Fest und
einen guten Rustch ins neue
Jahr.</Text></Feld><Sig>
abc</Sig>


MfG

Edit - Die Ausgabe:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
stefan@stefan-laptop:~/perl$ perl sort.pl
$VAR1 = '<Feld><Text>Hall</Text>
<Text>o li</Text>
<Text>ebe </Text>
<Text>Perl</Text>
[...]
<Text>ins </Text>
<Text>neue</Text>
<Text>Jahr</Text>
<Text>.</Text>
</Feld><Sig>
abc</Sig>
';
Pörl.
leo11
 2008-12-21 21:35
#117384 #117384
User since
2008-08-14
250 Artikel
BenutzerIn
[default_avatar]
@styx-cc
Danke für deine Hilfe.

Da der Text auch Leerzeilen enthalten kann habe ich $/ = undef gesetzt. Damit wäre das auch abgefangen. Des Weiteren können die Tags <Text> auch mehrfach kommen. Bspw.:

<Feld><Text>Hallo liebe Perl-
Gemeinde.

diesmal mit leerzeile
</Text></Feld><Sig>
abc</Sig>
<Text>Viele Grüße
leo11</Text><Text>ps.: schönen abend</Text>

Daher habe ich mit der Zeile
$data =~ m|(<Text>[^<]*</Text>)|sg
die Gier rausgenommen und den Modifier g zugefügt. Leider wird trotzdem immer nur der erste Treffer gesplittet. Woran liegt das?
leo11
 2008-12-21 21:52
#117386 #117386
User since
2008-08-14
250 Artikel
BenutzerIn
[default_avatar]
Eine Lösung hab ich nun:
Code (perl): (dl )
1
2
3
4
5
@match = $data =~ m|(<Text>[^<]*</Text>)|sg;
foreach my $m (@match) {
    my $prepared_string = prepare_string($m);
    $data =~ s/$m/$prepared_string/s;
}



Eine Erklärung wieso das oben nicht ging wär trotzdem nett.

Außerdem würde mich intressieren ob die Lösung auch bei 10 MB Dateien vertretbar ist.

(Nachträglich editiert)
Gast Gast
 2008-12-21 22:18
#117387 #117387
"c" also "continue" wäre richtig.
"c" macht hinter der Stelle weiter wo der letzte Match war. Dann klappt es auch mit der Schleife.
styx-cc
 2008-12-22 01:13
#117388 #117388
User since
2006-05-20
533 Artikel
BenutzerIn

user image
Naja, 10 MB sind imo noch nicht kritisch (haengt natuerlich vom Produktivsystem ab), aber du musst dir im Klaren darueber sein, dass er die gesamte Datei auf einmal einliest, nicht zeilenweise.
Pörl.
leo11
 2008-12-22 07:47
#117389 #117389
User since
2008-08-14
250 Artikel
BenutzerIn
[default_avatar]
Ich bin auf ein unerwartetes Problem mit Klammern gestoßen.
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/perl
use strict;
use Data::Dumper;
use warnings;

local $/ = undef;
my $data = <DATA>;
my @match;

@match = $data =~ m|(<Text>[^<]*</Text>)|sg;
foreach my $m (@match) {
    my $prepared_string = prepare_string($m);
    $data =~ s/$m/$prepared_string/s;
}

print $data;

## subs ##
sub prepare_string {
  my $string = shift;
  $string =~ s/\n|<Text>|<\/Text>//g;
  
  my $chunk_size =  10;
  my $prepared_string;
  for (my $i = 0; $i <= length($string); $i=$i+$chunk_size)  {
    my $part = substr($string, $i, $chunk_size);
    $prepared_string .= "<Text>$part</Text>\n";
  }
  return $prepared_string;
}

__DATA__
<Feld><Text>Hallo liebe Perl-
Geme(i)nde.

diesmal mit leerzeile
</Text></Feld><Sig>
abc</Sig>
<Text>V[iel]e Grüße
leo11</Text><Text>ps.: schönen abend</Text>


Wenn der Text runde oder eckige Klammern enthält wird er nicht gesplittet. In diesem Fall wird nur das "ps.: schönen abend" gesplittet. Offensichtlich matcht der Ausdruck
Code (perl): (dl )
$data =~ s/$m/$prepared_string/s; 
nicht mehr. Recherchen haben mich zu Text::Balanced geführt, nur ist mir nicht klar wie ich damit das Problem beheben kann. Mir leuchtet das Problem auch nicht recht ein.

@styx-cc
bzgl. des auf einmal einlesens: Vielleicht wäre ein Konzept besser dass deinen und meinen Ansatz vermischt. Wir könnten einen zeilenbasierten Match in der Art
Code (perl): (dl )
if ( {<Text>} ..  {</Text>}

machen, und dann den Teil vorher und nachher herausnehmen. Allerdings ist es dann wieder schlecht wenn bspw. im Teil danach auch ein <Text> kommt. Womit ich wieder bei dem Grund bin, wieso ich im Forum gelandet bin. )-: Ich denke ich gehe erstmal dem Problem mit den Klammern nach. Könnt ihr mir da weiter helfen?
<< |< 1 2 >| >> 12 Einträge, 2 Seiten



View all threads created 2008-12-21 14:05.