我有一个100MB纯文本数据库文件,我想解析并转换为数据结构以便于访问。环境是perl和cygwin。由于我们收到来自第三方数据的纯文本文件,因此我无法使用任何现有的解析器,如xml或google协议缓冲区。
文本文件如下所示。
Class=Instance1
parameterA = <val>
parameterB = <val>
parameterC = <val>
ref = Instance2
Class=Instance2
parameterA = <val>
parameterB = <val>
parameterC = <val>
该文件包含大量类变体。
解析此问题的最佳选择是什么? yacc / lex会帮助我,还是应该编写自己的perl解析器?
答案 0 :(得分:1)
这应该可以解决问题。它通过检查第一行来自动检测行结束,这里假设一条记录用空行分隔。
在每个记录中,假设键/值对用等号(=
)连接,可能还有一些空格。
这是我的代码:
#!/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;
my $db_file;
GetOptions(
'file=s' => \$db_file,
);
sub detect_line_ending {
my ($fh) = @_;
my $line = <$fh>;
# Rewind to the beginning
seek($fh, 0, 0);
my ($ending) = $line =~ m/([\f\n\r]+$)/s;
return $ending;
}
sub process_chunk {
my ($chunk, $line_ending) = @_;
my @lines = split(/$line_ending/, $chunk);
my $section = {};
foreach my $line (@lines) {
my ($key, $value) = split(/[ \t]*=[ \t]*/, $line, 2);
$section->{$key} = $value;
}
return $section;
}
sub read_db_file {
my ($file) = @_;
my $data = [];
open (my $fh, '<', $file) or die $!;
my $line_ending = detect_line_ending($fh);
{
local $/ = $line_ending.$line_ending;
while (my $chunk = <$fh>) {
chomp $chunk;
my $section = process_chunk($chunk, $line_ending);
push @$data, $section;
}
}
close $fh;
return $data;
}
print Dumper read_db_file($db_file);
答案 1 :(得分:1)
这是你想要的吗?
#!/usr/bin/perl
use Data::Dumper;
use Modern::Perl;
my %classes;
my $current;
while(<DATA>) {
chomp;
if (/^Class\s*=\s*(\w+)/) {
$classes{$1} = {};
$current = $1;
} elsif (/^(\w+)\s*=\s*(.+)$/) {
$classes{$current}{$1} = $2;
}
}
say Dumper\%classes;
<强>输出:强>
$VAR1 = {
'Instance2' => {
'parameterC' => '<val>',
'parameterB' => '<val>',
'parameterA' => '<val>'
},
'Instance1' => {
'parameterC' => '<val>',
'ref' => 'Instance2',
'parameterB' => '<val>',
'parameterA' => '<val>'
}
};