免费注册 查看新帖 |

Chinaunix

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

[其他] 有没有大神愿意试试把这个perl改成shell脚本呀~ [复制链接]

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-11-20 17:49 |只看该作者 |倒序浏览
逛论坛的时候,学习了Send_linux大大的字符串匹配的KMP算法
http://bbs.chinaunix.net/forum.p ... mp;fromuid=29097174
觉得很有意思,在网上有很多关于C实现的,perl的话:
  1. use Data::Dumper;

  2. my $from = 'abababd ababc';
  3. my $find = 'ababc';

  4. # 分隔字符串为array
  5. my @from = split '', $from;
  6. my @find = split '', $find;

  7. print $find, "\n";
  8. print @{ calc( \@find ) }, "\n";
  9. print "\n";
  10. print kmp( \@from, \@find );

  11. ############################
  12. # 计算字符串的重复值
  13. sub calc {
  14.     my ($array) = @_;

  15.     # 取与字串相同长度的array 并将第一个置0
  16.     my @tmp = (@$array);
  17.     $tmp[0] = 0;

  18. # 之后的每一个字符都与开头字串比较,取@tmp 前一个值作为比较字符
  19. # 若为0,前一字符个与开头不重复,比较字符指向开头0
  20. # 若不为0,前一个字符与开头有重复,如果还相同,@tmp 值加1,否则为0,后继自符重新从头开始比较
  21.     for ( 1 .. $#tmp ) {
  22.         if ( $array->[$_] eq $array->[ $tmp[ $_ - 1 ] ] ) {
  23.             $tmp[$_] = $tmp[ $_ - 1 ] + 1;
  24.         }
  25.         else {
  26.             $tmp[$_] = 0;
  27.         }
  28.     }
  29.     return \@tmp;
  30. }

  31. sub kmp {
  32.     my ( $from, $find ) = @_;

  33.     # 初始从开头比较
  34.     my $i   = 0;
  35.     my $tmp = calc($find);

  36.     # 剩余字串长度小于搜索字串,则退出返回-1
  37.     while ( ( $#{$from} - $i ) >= $#{$find} ) {

  38.         # 观察每次步进长度
  39.         print @$from[ $i .. $#{$from} ], "\n";

  40.         # j 标记搜索到的字串长度
  41.         my $j = 0;
  42.         while ( $find->[$j] eq $from->[ $i + $j ] ) {

  43.             # 搜索到的长度与字符串长度相同,说明找到,返回index位置
  44.             if ( $j == $#{$find} ) {
  45.                 return $i;
  46.             }
  47.             else {
  48.                 $j++;
  49.             }
  50.         }

  51.         # 有相同的字符串,根据计算的值来跳转多个字符并重新比较
  52.         # $j 为相同的个数(以1为基数),@tmp[$j-1] 为同开始字符重复的个数
  53.         if ($j) {
  54.             $i += $j - $tmp->[ $j - 1 ];
  55.         }
  56.         else {
  57.             $i++;
  58.         }
  59.     }
  60.     return -1;
  61. }
复制代码
输出:
  1. #字符串以及计算重复值结果
  2. ababc
  3. 00120

  4. #每次查找过程
  5. abababd ababc
  6. ababd ababc
  7. abd ababc
  8. d ababc
  9. ababc
  10. ababc
  11. 8
复制代码
求大神shell方案!!哈哈

论坛徽章:
2
射手座
日期:2014-10-10 15:59:4715-16赛季CBA联赛之上海
日期:2016-03-03 10:27:14
2 [报告]
发表于 2013-11-20 21:48 |只看该作者
本帖最后由 yinyuemi 于 2013-11-20 21:49 编辑

回复 1# huang6894

  1. from='abababd ababc';
  2. find='ababc';

  3. arr_from=($(sed 's/./ "&"/g;s/ //' <<<$from));
  4. arr_find=($(sed 's/./ "&"/g;s/ //' <<<$find));

  5. ############################
  6. # 计算字符串的重复值
  7. #sub calc {
  8. function calc_(){
  9.     array=($*);
  10.     # 取与字串相同长度的array 并将第一个置0
  11.     tmp=($*);
  12.         tmp[0]=0;
  13.         len=${#tmp[*]};
  14. # 之后的每一个字符都与开头字串比较,取@tmp 前一个值作为比较字符
  15. # 若为0,前一字符个与开头不重复,比较字符指向开头0
  16. # 若不为0,前一个字符与开头有重复,如果还相同,@tmp 值加1,否则为0,后继自符重新从头开始比较
  17.         for ((i=1;i<=len-1;i++))
  18.         do       
  19.                 if [[ ${array[$i]} == ${array[${tmp[$((i-1))]}]} ]]
  20.                 then
  21.                         tmp[$i]=$((tmp[i-1]+1));
  22.                 else
  23.                         tmp[$i]=0;
  24.                 fi
  25.         done
  26.     echo ${tmp[@]};
  27. }


  28. function kmp() {
  29.     eval from_=("$(sed 's/./ "&"/g;s/ //' <<<$1)");
  30.         eval find_=("$(sed 's/./ "&"/g;s/ //' <<<$2)");
  31.         # 初始从开头比较
  32.         m=0;
  33.         tmp1=($(eval calc_ "${find_[*]}"));
  34.         len1=${#find_[*]};
  35.         len2=${#from_[*]};
  36.     # 剩余字串长度小于搜索字串,则退出返回-1
  37.     while(( len2-m >= len1))
  38.         # 观察每次步进长度
  39.         do
  40.                 for((n=m;n<=len2-1;n++))
  41.                 do
  42.                         printf ${from_[$n]}
  43.                 done
  44.                 printf "\n";
  45.         # j 标记搜索到的字串长度
  46.         local j=0;
  47.                 while [[ ${find_[j]} == ${from_[$((m+j))]} ]]
  48.                 do
  49.             # 搜索到的长度与字符串长度相同,说明找到,返回index位置
  50.             if (( j == len1-1 ))
  51.                         then
  52.                                 echo $m;
  53.                                 return $m;
  54.             else
  55.                                 ((j++));
  56.                         fi
  57.                 done
  58.         # 有相同的字符串,根据计算的值来跳转多个字符并重新比较
  59.         # $j 为相同的个数(以1为基数),@tmp[$j-1] 为同开始字符重复的个数
  60.                 if ((j>0))
  61.                 then
  62.                         m=$((m+j-tmp1[j-1]))
  63.         else
  64.                         ((m++));
  65.                 fi
  66.         done
  67. }
  68. IFS=$'';
  69. echo $find;
  70. calc_ ${arr_find[@]};
  71. kmp $from $find;

复制代码

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
3 [报告]
发表于 2013-11-21 09:22 |只看该作者
回复 2# yinyuemi


    大神啊!!!大神啊~谢谢咯
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP