#!/usr/bin/perl use strict; use warnings; use Data::Dumper; package Token; use Moose; has 'type' => ( is => 'rw' ); has 'value' => ( is => 'rw' ); package Tokenizer; use Moose; has 'token' => ( isa => 'ArrayRef', default => sub { [] }, is => 'rw', ); sub tokenize { my $self = shift; my $stream = shift || ''; TOKEN: { $self->add_token('SECTION', $1) if $stream =~ /\G\[(\w+)\]/gcx; $self->add_token('VARIABLE', $1) if $stream =~ /\G(\w+)\s*=/gcx; $self->add_token('VALUE', $1) if $stream =~ /\G(\w+)/gcx; redo TOKEN if $stream =~ /\G\s+/gcx; }; } sub add_token { my $self = shift; my ($t, $v) = @_; push @{$self->token}, Token->new( type => $t, value => $v ); } package main; my $d; { local($/); $d = ; } my $t = Tokenizer->new; $t->tokenize($d); warn Dumper $t; my %config; my ($cur_section, $cur_variable, $cur_value); for my $token (@{$t->token}) { $cur_section = $token->value if $token->type eq 'SECTION'; die unless $cur_section; $cur_variable = $token->value if $token->type eq 'VARIABLE'; $cur_value = $token->type eq 'VALUE' ? $token->value : undef; push @{$config{$cur_section}->{$cur_variable}}, $cur_value if (defined $cur_value and defined $cur_variable); } warn Dumper \%config; __DATA__ [foo] bar = buz qiz = 42 17 23 [languages] favorite = perl python ruby disliked = C Java