MatchPattern


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;

my ($nums, $patt, $nums_pos, $from_pos) = @_ ;

$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 ($nums, $patt, $nums_pos, $from_pos) = @_ ;

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,

};
}

define a piece of regexp is passed or missed, or waitting for input

sub match_meta_patt {
my $args = shift;

puts $args;

my $state = new_state($args);

puts $state;

my $nums = $args->{nums};
my $nums_pos = $args->{nums_pos};
my $from_pos = $args->{from_pos};
my $num = $nums->[$nums_pos];

say $num;

puts $state->{class};

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 }

}

say $pass_flag;

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

}

say $flag;

$state->{flag} = $flag;
$state->{matched} = $matched;
$state->{nums_pos} = $nums_pos;
$state->{from_pos} = $from_pos;
$state->{last_pos} = $last_pos;

puts $state;

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;

你可能感兴趣的:(MatchPattern)