Эта задачка началась как 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; } # [-+]?\d+(\.\d+)? 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;