字符串通配符的匹配算法

 

字符串通配符的匹配算法

如何实现带有?*通配符的字符串(string)匹配呢,可以把问题拆开看

只含有?的模型(pattern),和只含有*的模型

 

只含有?的模型理解起来非常简单,因为?就等于一个字符,含有?的模型就等于一个字符串

判断是否匹配,只要在给定字符串中,查找含有?的字符串就行了,而在字符串中查找字符串就是用indexOf.

只不过现有的indexOf,不知道'?'就代表任意字符,所以需要自己动手改写一下.

程序如下

function indexOf(str: String, find: String, pos: Number): Number

{

    if(undefined == str || undefined == find ) return;

    if(undefined == pos || pos < 0) pos = 0;

 

    var si=pos, slen=str.length, fi=0, flen=find.length;

    while(si<slen && fi<flen)

    {

        if( str.charAt(si) == find.charAt(fi)

            || find.charAt(fi) == '?' ) // 碰到?,可以继续往下比较

        {

            si++; fi++;

        }

        else

        {

            si = si-fi+1;

            fi=0;

        }

    }

    if( fi==flen ) return si-flen;

    else return -1;

}

//-Example

var string = "abaabbabc";

var pattern = "a?babc";

trace( indexOf(string, pattern) ); // 3

 

可以看到,经过我们改写的indexOf,已经把'?'当作任意字符了.

lastIndexOf的改写也是类似,不同的地方要注意字符的比较方向和indexOf相反

 

现在使用改写了的indexOf或者lastIndexOf就可以解决含有?的模型匹配问题了.

因为只需要在查到的同时再比较一下stringpattern的长度,看看是否相同就可以得出判断.

为了提高效率,可以把长度判断放在查询前面.

 

function matchWithInterrogation(str: String, pattern: String): Boolean

{

    if(str.length != pattern.length ) return false;

    else return indexOf(str, pattern) > -1;

}

 

------------------------------------------------------------------------

 

接着,我们来看只含有*通配符的模型匹配算法.

因为一个*代表的可以是0个或者N个的字符,所以一个含有*通配符的模型,是不能确定长度的.

不能简单的认为是pattern.length,这个长度值,只是把*看作普通字符来统计.

另外,几个连续的*的意义和一个*的意义是相同的,比如

*代表0-n个字符

**也代表0-n个字符....这个不用多解释了吧~

 

由于*的特殊性,我们无法确定它所代表的长度,反过来说,我们又可以认为它是任意长度.

也就说,可以把*看作是空字符,1,a,123,abcd!@$#%^%等等这样的字符或字符串.

 

既然这样,我们就不能把stringpattern按照逐字的形式一个一个来比较.

但可以变成一串一串来比较,而且可以不用管串与串之间是否是紧挨着的.

什么意思呢?

比如

string: Oh year.Totay is weekend!

pattern: *ye*a*e*

 

模型的有效字符是y,e,a,e

ye是连在一起的,可以把ye当成一个串来看,其它的也可以看作是一个串,只是这样的串长度为1.

 

我们先在string中找ye,找到了唯一存在的地方Oh (ye)ar....

接着找a,发现ye后面就有一个a,那么Oh (yea)r....

然后找e,Oh (yea)r.Totay is w(e)ekend!

于是找完了,但是我们发现a不一定在ye后面,Totay中也有一个a,e的话weekend里面就有3,那是不是一定要按照上面的方法找呢?

 

是的.这里有个就近原则,如果从左向右找,就以在未查询过部分的最左边找到为匹配,从右向左找,亦然.

因为最近的被匹配掉了,还有远的可以用来再匹配.

假如不是这样,那就有可能出现应该匹配的而匹配不到

比如

weekend

*e*e*e*

如果此时不用就近原则,就无法完成3e的匹配(前两个e间的*,可以认为是空字符)

 

使用就近原则,还利于方便程序的编写和方法的理解.

 

通过上面的解释,发现含有*通配符的模型,只是在string中不停的依次搜索而已.既然是搜索当然要用到indexOf这个函数啦,哈哈是不是很眼熟.

那怎么用呢?很自然想到,把含有*的模型,*为分界线,分成几个包含有效字符的串.

然后以就近原则在指定的string里面,逐个的把这些串找出来,如果都找出来了,那就是匹配的,只要一个串没有找到,那就是不匹配了.

因为前面我们已经改写了indexOf这个函数,使得它可以辨别?通配符,所以在这里,就可以把?当成是一个串中的有效字符来理解.

 

我们还要感谢flashplayer提供了String.split这个函数,哈哈,分割的任务就靠它了.现在我们万事俱备就欠编程.

 

在写程序之前,有几个注意事项.

第一,注意模型的头是*,还是有效字符

如果是*,*后的第一个串,可以在string的任意位置

如果是有效字符,那第一个串,一定也要在string的头

尾部也是如此

第二,注意几个极端现象.

a)模型没有*,那就是一个含?字符串的匹配,可以用前面的matchWithInterrogation函数来解决

b)模型只有*,前面说了连续的*意义等同于只有一个*,而只有一个*就说明string可以是任意字符,包括空

c)模型为空,也就是只有string为空时才匹配

d)bc认为,连续的*间存在一个空字符,空字符匹配空字符,而在字符串范围内查找空字符,就返回搜索的起始位置.

第三,注意String.split的分割符在字符串的开头或者末尾时,第一或最后一个元素为空字符

 

好了,可以开始动手写程序了

function matchWithAsterisk(str: String, pattern: String): Boolean

{

    if(undefined == str || undefined == pattern ) return;

 

    var ps = pattern.split('*');

    if( 1==ps.length ) // 没有*的模型

        return matchWithInterrogation(str, ps[0]);

   

    var si = indexOf(str, ps[0], 0); // string头查找第一个串

    if( 0 != si ) return false; // 第一个串没找到或者不在string的头部

    si += ps[0].length; // 找到了串后,按就近原则,移到未查询过的最左边

 

    var plast=ps.length-1; // 最后一串应单独处理,为了提高效率,将它从循环中取出

    var pi=0; // 跳过之前处理过的第一串

    while(++pi<plast)

    {

        if(''==ps[pi]) continue; //连续的*,可以忽略

        si = indexOf(str, ps[pi], si); // 继续下一串的查找

        if(-1==si) return false; // 没有找到

        si += ps[pi].length; // 就近原则

    }

 

    if(''==ps[plast]) // 模型尾部为*,说明所有有效字符串部分已全部匹配,string后面可以是任意字符

        return true;

 

    // 从尾部查询最后一串是否存在

    var last_index = lastIndexOf(str, ps[plast]);

    // 如果串存在,一定要在string的尾部, 并且不能越过已查询过部分

    return (last_index == str.length - ps[last].length) && (last_index >= si);

}

//-Example

var string = "Oh year.Totay is weekend!";

var pattern = "*ye*a*e*";

trace( match(string, pattern) ); // true

var string = "weekend";

var pattern = "e*e*e";

trace( match(string, pattern) ); // false

 

 

原文地址:我不记得了,大家如果知道的话给我留个言,我补上,谢谢

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值