- 论坛徽章:
- 8
|
逛论坛的时候,学习了Send_linux大大的字符串匹配的KMP算法
http://bbs.chinaunix.net/forum.p ... mp;fromuid=29097174
觉得很有意思,在网上有很多关于C实现的,perl的话:- use Data::Dumper;
- my $from = 'abababd ababc';
- my $find = 'ababc';
- # 分隔字符串为array
- my @from = split '', $from;
- my @find = split '', $find;
- print $find, "\n";
- print @{ calc( \@find ) }, "\n";
- print "\n";
- print kmp( \@from, \@find );
- ############################
- # 计算字符串的重复值
- sub calc {
- my ($array) = @_;
- # 取与字串相同长度的array 并将第一个置0
- my @tmp = (@$array);
- $tmp[0] = 0;
- # 之后的每一个字符都与开头字串比较,取@tmp 前一个值作为比较字符
- # 若为0,前一字符个与开头不重复,比较字符指向开头0
- # 若不为0,前一个字符与开头有重复,如果还相同,@tmp 值加1,否则为0,后继自符重新从头开始比较
- for ( 1 .. $#tmp ) {
- if ( $array->[$_] eq $array->[ $tmp[ $_ - 1 ] ] ) {
- $tmp[$_] = $tmp[ $_ - 1 ] + 1;
- }
- else {
- $tmp[$_] = 0;
- }
- }
- return \@tmp;
- }
- sub kmp {
- my ( $from, $find ) = @_;
- # 初始从开头比较
- my $i = 0;
- my $tmp = calc($find);
- # 剩余字串长度小于搜索字串,则退出返回-1
- while ( ( $#{$from} - $i ) >= $#{$find} ) {
- # 观察每次步进长度
- print @$from[ $i .. $#{$from} ], "\n";
- # j 标记搜索到的字串长度
- my $j = 0;
- while ( $find->[$j] eq $from->[ $i + $j ] ) {
- # 搜索到的长度与字符串长度相同,说明找到,返回index位置
- if ( $j == $#{$find} ) {
- return $i;
- }
- else {
- $j++;
- }
- }
- # 有相同的字符串,根据计算的值来跳转多个字符并重新比较
- # $j 为相同的个数(以1为基数),@tmp[$j-1] 为同开始字符重复的个数
- if ($j) {
- $i += $j - $tmp->[ $j - 1 ];
- }
- else {
- $i++;
- }
- }
- return -1;
- }
复制代码 输出:- #字符串以及计算重复值结果
- ababc
- 00120
- #每次查找过程
- abababd ababc
- ababd ababc
- abd ababc
- d ababc
- ababc
- ababc
- 8
复制代码 求大神shell方案!!哈哈 |
|