我需要匹配非常短的文本段(1到7个字母),并且我知道如何在有限状态机中指定可接受的字符串.我认为为这个应用程序构建一个正则表达式会变得太乱,难以维护.我需要一个易于使用的模块,我可以编写一个FSM,如果模块可以生成一个正则表达式供我使用,那将是一个很大的好处.有没有人知道一个可以做到这一点的模块?
amo*_*mon 10
即使没有模块,编写FSM也很容易.
my $state = 0;
while (my $token = shift @input) {
$state = $state_table{$state}->($token);
}
Run Code Online (Sandbox Code Playgroud)
其中状态表是一个散列,状态为键,匿名子为值:
0 => sub {
my $nextstate;
given (shift) {
when ('a') {print "its an a"; $nextstate = 2}
default {$nextstate = 1}
}
return $nextstate;
},
1 => sub {
my $token = shift;
my $nextstate = ({
a => sub {print "Its an a"; 2}
}->{$token} // sub {1})->();
return $nextstate;
},
2 => ...
Run Code Online (Sandbox Code Playgroud)
(注意,在这种情况下状态0和1是等效的)
等要写出Perl中的开关,可以过滤源之间进行选择时,given- when构建和散列,这将使您的工作轻松.特别是哈希(哈希哈希的子程序)可以使表驱动编程变得非常容易.
但是,如果使用正则表达式可以很容易地表达问题,则可能值得这样做.请注意,Perl正则表达式不仅限于正则表达式,因此您必须小心使用哪些功能.正则表达式优于状态机的主要优点是执行速度,因为正则表达式引擎是高度优化的.语法也很简单,这使得它们更容易编写.不要忘记您可以使用/x修饰符包含非语义空白:
m{
.*? # match anything
(?:
a # followed by an a
| b # or a b
)
}x
Run Code Online (Sandbox Code Playgroud)
绝对等同于(但比可读性更好)
/.*?(?:a|b)/
Run Code Online (Sandbox Code Playgroud)
因此,手写正则表达式不仅可能更短(并且每个优秀的程序员都是懒惰的),而且还有很多乐趣.
您可以像这样定义您的状态:
my $state_machine = qr{
^(?&STATESTART)$
(?(DEFINE)
(?<STATESTART> (?&STATE0) )
(?<STATE0> a (?&STATE2)
| . (?&STATE1) )
(?<STATE1> a (?&STATE2)
| . (?&STATE1) )
(?<STATE2> ... )
)
}x;
print "->$x<- is part of the language" if $x =~ $state_machine;
Run Code Online (Sandbox Code Playgroud)
这将对应于使用哈希的状态机的上述草图.请注意,在使用命名的正则表达式模式建模FSM时,您应该只进行尾递归.