Эта задачка началась как regexp matching, но бэктрекингом заниматься желания никакого не было, поэтому сначала сделал автомат, а потом закопался в компиляцию регекспов в NDFA и решил разбить задание на части.
#! /usr/bin/perl
use strict;
use warnings;
use Test::Most;
sub run_automata {
my ($aut, @symbols) = @_;
my $cur_state = $aut->{start};
while (defined(my $symbol = shift @symbols)) {
$cur_state = $aut->{states}->{$cur_state}->{$symbol}
// return;
}
return $cur_state;
}
my $a1 = {
states => {
s1 => { A => 's2', B => 's3' },
s2 => { B => 's3' },
s3 => { C => 's1' },
},
start => 's1',
};
is(run_automata($a1, qw/A/), 's2');
is(run_automata($a1, qw/A A/), undef);
is(run_automata($a1, qw//), 's1');
is(run_automata($a1, qw/B/), 's3');
is(run_automata($a1, qw/B C A/), 's2');
is(run_automata($a1, qw/A B C A B C A B C A B C A B/), 's3');
is(run_automata($a1, qw/A X/), undef);
is(run_automata($a1, qw/X/), undef);
is(run_automata($a1, qw/B A/), undef);
sub pairs {
my ($state, @range) = @_;
return map { $_ => $state } @range;
}
my $numeric = {
states => {
nothing => { pairs(after_sign => qw/- +/), pairs(in_integer => 0 .. 9) },
after_sign => { pairs(in_integer => 0 .. 9) },
in_integer => { pairs(in_integer => 0 .. 9), '.' => 'decimal', EOF => 'ok' },
decimal => { pairs(in_decimal => 0 .. 9) },
in_decimal => { pairs(in_decimal => 0 .. 9), EOF => 'ok' },
},
start => 'nothing',
};
is(run_automata($numeric, split('', '-123'), 'EOF'), 'ok', '1st num');
is(run_automata($numeric, split('', '1'), 'EOF'), 'ok');
is(run_automata($numeric, split('', '002'), 'EOF'), 'ok', 'leading zeros');
is(run_automata($numeric, split('', '2.34'), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', '2.'), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', '.3323'), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', 'asd'), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', ''), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', '+.32'), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', '-'), 'EOF'), 'ok');
isnt(run_automata($numeric, split('', '4.4.2'), 'EOF'), 'ok');
done_testing;
Recent Comments