免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 4997 | 回复: 21
打印 上一主题 下一主题

[字符串匹配算法] 嵌套匹配 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-04-24 19:40 |只看该作者 |倒序浏览
30可用积分
进行过许多文本解析之后,发现有一个非常有用的算法:在具有嵌套结构的文本中匹配字符串:

字符串: if a then if b then if c then d end if e then f end end end

要求匹配出所有  if .. end 的结构, 按照深度保存成一个散列:

{
    0 => [ q<if a then if b then if c then d end if e then f end end end> ],
    1 => [ q<if b then if c then d end if e then f end end> ],
    2 => [ q<if c then d end>, q<f e then f end>],
}

通常的正则匹配是从内层进行匹配的,也有用递归的算法来从最外层开始计算。

最佳答案

查看完整内容

修正了一些错误:{:3_188:}

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
2 [报告]
发表于 2013-04-24 19:40 |只看该作者
本帖最后由 rubyish 于 2013-04-26 13:07 编辑

修正了一些错误:{:3_188:}
  1. #!/usr/bin/perl
  2. use 5.016;

  3. my $s = 'if a then if b then if c then d end if e then f end end end';
  4. sub parse {
  5.     my @data = map /(\S.*\S)/, split /(if|end)/, shift;
  6.     my ( %i, %result );
  7.     $data[$_] =~ /(if|end)/ and push @{$i{$1}}, $_ for 0 .. $#data;
  8.     @{$i{if}} = reverse @{$i{if}};
  9.     my @L = reverse 0 .. $#{$i{end}};
  10.     for my $i ( 0 .. $#{$i{end}} ) {
  11.         if ( $i{if}[$i] > $i{end}[$i] ) {
  12.             my $l;
  13.             $i{if}[++$l] < $i{end}[$i] and last for @{$i{if}};
  14.             @{ $i{if} }[ $i .. $l ] = reverse @{$i{if}}[$i .. $l];
  15.             @L[$i .. $l] = ($L[$l]) x ($l - $i + 1);
  16.         }
  17.         my $join = "@data[$i{if}[$i] .. $i{end}[$i]]";
  18.         push @{$result{$L[$i]}}, $join;
  19.     }
  20.     \%result;
  21. }
  22. my $r1 = parse $s;

  23. say "$_ => ", join ' | ', @{ $r1->{$_} } for sort keys $r1;
复制代码

论坛徽章:
0
3 [报告]
发表于 2013-04-25 10:04 |只看该作者
本帖最后由 Perlvim 于 2013-04-25 10:06 编辑

rubyish 写的代码编译器最喜欢。

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
4 [报告]
发表于 2013-04-25 10:15 |只看该作者
Perlvim 发表于 2013-04-25 06:04
rubyish 写的代码编译器最喜欢。

十分感谢编译器的错爱~{:3_188:} {:3_188:} {:3_188:}

论坛徽章:
0
5 [报告]
发表于 2013-04-25 10:25 |只看该作者
本帖最后由 kk861123 于 2013-04-25 14:38 编辑

回复 1# Perlvim

这样可以吗?
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use Data::Dumper;

  4. my $line = 'if a then if b then if c then d end if e then f end end end';
  5. my @aConds;
  6. if ( $line =~ /^( # GROUP 1
  7.                   if \s*\S+\s* then \s*
  8.                     ( (?1)+  # Recurse to start of GROUP 1
  9.                        |     
  10.                        \S+   
  11.                     ) (?{ unshift @aConds, $2 }) # unshift the string matched in inner
  12.                   \s*end\s*
  13.                 )
  14.                       (?{ unshift @aConds, $1 }) # unshift the string matched in GROUP 1
  15.                 $/x ) {
  16.     print Dumper \@aConds;
  17. }

复制代码

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
6 [报告]
发表于 2013-04-25 11:05 |只看该作者
回复 5# kk861123


很好的解决方案 {:3_203:} {:3_203:}

第一次看到   (?1)  这件宝贝 大牛
它是什么?

论坛徽章:
0
7 [报告]
发表于 2013-04-25 11:47 |只看该作者
回复 6# rubyish


    perlre中搜"(?PARNO) (?-PARNO) (?+PARNO) (?R) (?0) "
我理解的是pattern捕捉,(?1) 代表了第一个group中的pattern

论坛徽章:
0
8 [报告]
发表于 2013-04-25 13:28 |只看该作者
回复 5# kk861123

结果对,但没看懂。



   

论坛徽章:
0
9 [报告]
发表于 2013-04-25 14:23 |只看该作者
文本解析的利器:
  1. use Parse::RecDescent;
复制代码
  1. #!/usr/bin/perl
  2. use strict; use warnings;
  3. use Data::Dumper;
  4. use Parse::RecDescent;

  5. # define grammar
  6. my $grammar = <<'EOG';
  7. start: condition { $return = [ $item[1] ] }
  8. condition: 'if' expr 'then' condition(s?) 'end' { $return = [ @item[1..5] ] }
  9.          | 'if' expr 'then' code 'end'          { $return = [ @item[1..5] ] }
  10. expr: /\S+/
  11. code: /\S+/
  12. EOG

  13. my $line = 'if a then if b then if c then d end if e then f end end end';
  14. my $parser = new Parse::RecDescent($grammar)
  15.     or die "Compilation error!\n";

  16. my $raConds = $parser->start($line);
  17. print Dumper $raConds;
  18. exit;
复制代码
result:
  1. $VAR1 = [
  2.           [
  3.             'if',
  4.             'a',
  5.             'then',
  6.             [
  7.               [
  8.                 'if',
  9.                 'b',
  10.                 'then',
  11.                 [
  12.                   [
  13.                     'if',
  14.                     'c',
  15.                     'then',
  16.                     'd',
  17.                     'end'
  18.                   ],
  19.                   [
  20.                     'if',
  21.                     'e',
  22.                     'then',
  23.                     'f',
  24.                     'end'
  25.                   ]
  26.                 ],
  27.                 'end'
  28.               ]
  29.             ],
  30.             'end'
  31.           ]
  32.         ];
复制代码

论坛徽章:
0
10 [报告]
发表于 2013-04-25 14:39 |只看该作者
回复 8# Perlvim


    加了点注释,你再看看?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP