【问题标题】:Parsing plain text database into data structures将纯文本数据库解析为数据结构
【发布时间】:2015-02-19 07:10:58
【问题描述】:

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

【问题讨论】:

  • 你的预期输出是什么?'
  • 是的,您已经使用 YACC/LEX 自定义解析文件,并且您已经在珍珠中构建了一个正则表达式
  • @BhargavModi : regec in Pearl ???
  • @serenesat 我应该发布一个演示答案,但这只是一个想法目的吗?
  • @BhargavModi:珍珠???如果您的意思是perl,那么又是拼写错误。

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


【解决方案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);

【讨论】:

  • 所以你建议编写我自己的解析器!
【解决方案2】:

这是你想要的吗?

#!/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>'
                       }
        };

【讨论】:

    猜你喜欢
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    • 2011-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多