package Estring::Function::MatchPattern;
use Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(match_pattern);
use 5.016;
use YAML qw(Dump);
sub puts { say Dump(@); }
sub debug { say Dump(@); exit; }
sub match_pattern {
my $args = shift;
$args->{nums_pos} = $args->{nums_pos} || 0;
$args->{from_pos} = $args->{from_pos} || -1;
my $patt = $args->{patt};
my $state;
foreach my $sub_patt (@{ $patt }) {
$args->{patt} = $sub_patt;
$state = match_branch_pattern($args);
# puts $state;
return $state if ( $state->{flag} == 1 );
}
return $state;
}
sub match_branch_pattern {
my $args = shift;
my $nums = $args->{nums};
my $length_nums = scalar @{ $nums };
my $length_patt = scalar @{ $args->{patt} };
my $nums_pos = $args->{nums_pos};
my $from_pos = $args->{from_pos};
my $patt_pos = 0;
my $matched = 0;
my $branch_flag = 0;
while ($nums_pos < $length_nums) {
say $nums_pos;
# say $patt_pos;
my $args = {
nums => $nums,
patt => $args->{patt},
nums_pos => $nums_pos,
patt_pos => $patt_pos,
from_pos => $from_pos,
matched => $matched,
};
# puts $args;
my $state = match_meta_patt($args);
# puts $state;
my $flag = $state->{flag};
# say $flag;
$nums_pos = $state->{nums_pos} + 1;
$from_pos = $state->{from_pos};
# matched 也要继承
$matched = $state->{matched};
# 如果没有匹配的话
if ($flag == 0) {
# 正则重置,从开始匹配
$patt_pos = 0;
# 内部计数器也清零
$matched = 0;
}
# 如果匹配到的话
elsif ($flag == 1) {
$matched = 0;
# 由于 length_patt 比 最大索引大一个
# 所以,要在 patt_pos 递增后统计
$patt_pos++;
last if ($patt_pos == $length_patt);
}
elsif ($flag == 2) {
$patt_pos++;
last if ($patt_pos == $length_patt);
}
elsif ($flag == 3) {
$matched = $matched + 1;
}
# 风头正劲
elsif ($flag == 4) {
# nums_pos 已经增加了
# patt_pos 不需要变化
# 主要将业绩统计一下吧
$matched = $matched + 1;
}
# 碰壁了
elsif ($flag == 5) {
# 用之前保存的业绩,抵挡一下
$nums_pos = $state->{last_pos};
$patt_pos++;
last if ($patt_pos == $length_patt);
}
}
return {
flag => $branch_flag,
from_pos => $from_pos,
nums_pos => $nums_pos,
};
}
sub match_meta_patt {
my $args = shift;
my $state = new_state($args);
my $nums = $args->{nums};
my $nums_pos = $args->{nums_pos};
my $from_pos = $args->{from_pos};
my $num = $nums->[$nums_pos];
my $flag = 0;
my $last_pos = 0;
my $lazy_mode = $state->{lazy_mode};
my $min = $state->{min};
my $max = $state->{max};
my $matched = $state->{matched};
my $pass_flag = 0;
if ( ref($state->{class}) eq ref([]) ) {
$args->{patt} = $state->{class};
my $pass_state = match_pattern($args);
$pass_flag = $pass_state->{flag};
$nums_pos = $pass_state->{nums_pos};
$from_pos = $pass_state->{from_pos};
}
else {
# say "reach here";
if (exists $state->{class}{$num}){
$pass_flag = 1;
} else { $pass_flag = 0 }
}
if ($pass_flag == 1) {
if ($nums_pos - $from_pos > $matched) { $from_pos = $nums_pos }
$matched++;
# {1,1} 不是贪婪模式
if ($matched < $min) { $flag = 1; }
elsif ($matched == $min) {
if ($lazy_mode == 1) {
$flag = 2;
$matched = 0;
} else {
$flag = 3;
# 保存最近一次匹配的位置
$state->{last_pos} = $nums_pos;
}
}
# 可以用 -1 代表无穷大
elsif ($matched != $max ) {
$flag = 4;
# 保留退路
$state->{last_pos} = $nums_pos;
}
elsif ($matched == $max) {
$flag = 2;
$matched = 0;
}
}
else {
if ($matched >= $min) {
$flag = 5;
}
else {
$flag = 0;
}
$matched = 0; # reset
}
$state->{flag} = $flag;
$state->{matched} = $matched;
$state->{nums_pos} = $nums_pos;
$state->{from_pos} = $from_pos;
$state->{last_pos} = $last_pos;
return $state;
}
sub new_state {
my $args = shift;
my $patt = $args->{patt};
my $patt_pos = $args->{patt_pos};
my $matched = $args->{matched} || 0;
return {
class => $patt->[$patt_pos][0],
min => $patt->[$patt_pos][1][0],
max => $patt->[$patt_pos][1][1],
lazy_mode => $patt->[$patt_pos][2],
matched => $matched,
nums_pos => $args->{nums_pos},
};
}
1;