If you need to work with a specific known line number and have a known record width, perhaps you should consider using seek to control your input rather than reading in the entire file. This could also be used to estimate a start position to avoid a fair bit of reading time. Otherwise, a sample of your input file might be helpful (or is that the hash you provided? - if so, do you have the option of changing your input format?).
Update: Upon further consideration, did you not mean a given line number by "specific line"? Is "bakjob1_details" a unique identifier? Does every record header (and only record headers) end with "_details"? It seems like this should all be done in a database, but assuming that the answer to all the above is yes, the following should function:
use strict; use warnings; my $filename = 'input.txt'; my %record = (); #Read records { open FILEHANDLE, "<$filename"; my @tree_refs = (); while (<FILEHANDLE>) { if (@tree_refs and /(.*)\_details/) { die "Corrupt record encountered at $_"; } if (/(\S*)\_details/) { if ($1) { unshift @tree_refs, {}; $record{$1} = $tree_refs[0]; } else { die "Record without name encountered at $_"; } } elsif (/\=.*\{/) { my $name = (split '=')[0]; $name =~ s/\s*//g; unshift @tree_refs, $tree_refs[0]->{$name} = {}; } elsif (/\}/) { shift @tree_refs; } elsif (/\=/) { (my $name, my $value) = (split '=')[0 .. 1]; $name =~ s/\s*//g; $value =~ s/\s*||\,//g; $tree_refs[0]->{$name} = $value; } else { die "Unexpected condition at $_" } } close FILEHANDLE; } #Edit appropriate records $record{bakjob1}->{debit}->{customer2} = '21.0'; $record{bakjob1}->{credit}->{customer2} = '42.0'; $record{bakjob2}->{debit}->{customer2} = '84.0'; $record{bakjob2}->{credit}->{customer2} = '168.0'; #Output records open FILEHANDLE, ">$filename"; for my $root_key (keys %record) { print FILEHANDLE " $root_key\_details \= \{\n"; my @queue = (); my $last_depth = 1; # Root-level elements for my $key (keys %{$record{$root_key}}) { if (ref $record{$root_key}->{$key}) { # Stick it on the queue push @queue, {record => $record{$root_key}->{$key}, key => $key, depth => 2, }; } else { # Output values my $value = $record{$root_key}->{$key}; print FILEHANDLE ' 'x4 . "$key \= $value\,\n"; } } while (my $element = shift @queue) { if ($last_depth >= $element->{depth}) { for (reverse $element->{depth} .. $last_depth) { print FILEHANDLE ' 'x$_ . "\}\,\n"; } } print FILEHANDLE ' 'x$element->{depth} . "$element->{key} \= +\{\n"; for my $key (keys %{$element->{record}}) { if (ref $element->{record}->{$key}) { # Stick it on the qu +eue push @queue, {record => $element->{$key}, key => $key, depth => 1+$element->{depth}, }; } else { # Output values my $value = $element->{record}->{$key}; print FILEHANDLE ' 'x($element->{depth}+1) . "$key \= + $value\,\n"; } } $last_depth = $element->{depth}; } for (reverse 1 .. $last_depth) { print FILEHANDLE ' 'x$_ . "\}\,\n"; } } close FILEHANDLE;
In reply to Re: Pattern Matching - a Tricky one
by kennethk
in thread Pattern Matching - a Tricky one
by John007
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |