Thread Zeilenzahl bestimmen bei veränderten Seperator (21 answers)
Opened by manu at 2012-08-01 13:58

topeg
 2012-08-02 12:48
#160492 #160492
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Bedenke für einen Computer gibt es keine Zeilen in dem sinne. Es das wie wir es interpretieren. Wenn du sagst "/>" soll das ende einer sein dann ist das für Perl auch so.

Wenn du wissen willst in welcher "\n"-Zeile ein Wert, ist aber anders parsen willst musst du das passend Programmieren

Ein Ansatz:
more (30.4kb):
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/usr/bin/perl
use strict;
use warnings;
use XML::Parser;
use Data::Dumper;
use IO::File;

my $file='test.out.xml';

my $tree={
    type       => 'root',
    name       => 'root',
    values     =>{},
    line_start => 0,
    line_end   => 0,
    childs     => [],
};
my @deep=($tree);

my $xmlp = XML::Parser->new( Handlers =>
  {
    # Datei öffenen beim starten des Parsens
    Init  => sub{
      my $parser=shift;
      # den Dateinamen aus dem Parser-Objekt holen
      my $fh = IO::File->new($parser->{Base}, 'r') or die( "Error open $parser->{Base} ($!)\n" );
      # einen Eintrag im Parser für das Filehandle machen
      $parser->{__MY__FH__}={fh => $fh, lastline=>$fh->getline()};
    },

    # tag start
    Start => sub{
      my $parser=shift;
      my $name=shift;
      my %values=@_;
      my $line=test_line($parser->{__MY__FH__},"<$name");

      my $element={
          type       => 'tag',
          name       => $name,
          values     => \%values,
          line_start => $line,
          line_end   => $line,
          childs     => [],
        };
      push(@{$deep[-1]->{childs}},$element);
      push(@deep,$element);
    },

    # tag end
    End   => sub{
      my $parser=shift;
      my $name=shift;
      my $line=test_line($parser->{__MY__FH__},">");

      if(@deep > 1)
      {
        my $element=pop(@deep);
        $element->{line_end}=$line;
      }
    },

    # Strings zwischen tags
    Char  => sub{
      my $parser=shift;
      my $string=shift;

      # an vorhandenen String anhängen
      if(@{$deep[-1]->{childs}} && $deep[-1]->{childs}->[-1]->{type} eq 'char')
      {
        $deep[-1]->{childs}->[-1]->{childs}.=$string;
        return;
      }

      # ignoriere "\n" und leere Zeilen
      if($string=~/\s*/s)
      {
        if(@{$deep[-1]->{childs}} && $deep[-1]->{childs}->[-1]->{type} eq 'char')
        { $deep[-1]->{childs}->[-1]->{line_end}++ while($string=~/[\x0a\x0d]/gc); }
        return;
      }

      my $line=test_line($parser->{__MY__FH__},$string);
      my $element={
          type       => 'char',
          name       => '',
          values     =>{},
          line_start => $line,
          line_end   => $line,
          childs     => $string
        };
      push(@{$deep[-1]->{childs}},$element);
    },
  });

$xmlp->parsefile($file);

print Dumper($tree);

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

sub test_line
{
  my $fh=shift;
  my $string=shift;

  my $line=-1;

  # ist es in der letzten gelesenen Zeile?
  my $pos=index($fh->{lastline},$string);
  my $tell=$fh->{fh}->tell();
  if($pos >= 0)
  {
    # schon gefundenes löschen
    substr($fh->{lastline},0,$pos+length($string),'');
    #aktuelle Zeilennummer
    $line=$fh->{fh}->input_line_number();
  }
  else
  {
    # Datei weiter einlesen bis gefunden
    while($fh->{lastline}=$fh->{fh}->getline())
    {
      my $pos=index($fh->{lastline},$string);
      if($pos >= 0)
      {
        # schon gefundenes löschen
        substr($fh->{lastline},0,$pos+length($string),'');
        #aktuelle Zeilennummer
        $line=$fh->{fh}->input_line_number();
        last;
      }
    }
  }

  # zurück zu letzer position wenn nicht gefunden
  $fh->{fh}->seek($tell,0) if($line == -1);

  return $line;
}

View full thread Zeilenzahl bestimmen bei veränderten Seperator