将纯文本数据库解析为数据结构

时间:2015-02-19 07:10:58

标签: regex perl parsing data-structures perl-data-structures

我有一个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解析器?

2 个答案:

答案 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>'
                       }
        };