`
凤舞凰扬
  • 浏览: 65381 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

通配符识别的java实现

    博客分类:
  • Java
阅读更多

   前两天在网上无意看到一个关于使用java的正则表达式来进行通配符识别判断的实现。(http://blog.csdn.net/subchen/archive/2007/10/25/1843232.aspx)

   看了一下,程序其实有蛮多问题的,甚至都无法通过编译以及测试。我将程序改了一下,并稍微优化了一下结构,如下:

 

    private static final String PATTERN_LINE_START = "^" ;

    private static final String PATTERN_LINE_END = "$" ;

    private static final char[] META_CHARACTERS = { '$', '^', '[', ']', '(', ')',
                                                    '{', '}', '|', '+', '.', '\\' };

    /**
     * match function, support '*' and '?'.
     * The function is based on regex.
     * @param pattern
     * @param str
     * @return
     */
    public static boolean wildcardMatch(String pattern, String str) {
        pattern = convertToRegexPattern(pattern);
        return Pattern.matches(pattern, str);
    }

    private static String convertToRegexPattern(String wildcardString) {
        String result = PATTERN_LINE_START ;
        char[] chars = wildcardString.toCharArray() ;
        for (char ch : chars) {
            if (Arrays.binarySearch(META_CHARACTERS, ch)>=0) {
                result += "\\" + ch ;
                continue ;
            }
            switch (ch) {
                case '*':
                    result += ".*";
                    break;
                case '?':
                    result += ".{0,1}";
                    break;
                default:
                    result += ch;
            }
        }
        result += PATTERN_LINE_END ;
        return result;
    }

 

    后来运行了一下,发现这样的效率并不高,原代码中不支持?,而实际中对于?的通配符匹配,尤其是在java类名,文件名的识别上应用并不多,于是,另外写了个快速的实现,不使用正则表达式。

    public static boolean simpleWildcardMatch(String pattern, String str) {
        return wildcardMatch(pattern, str, "*");
    }

    public static boolean wildcardMatch(String pattern, String str, String wildcard) {
        if (StringUtils.isEmpty(pattern) || StringUtils.isEmpty(str)) {
            return false;
        }
        final boolean startWith = pattern.startsWith(wildcard);
        final boolean endWith = pattern.endsWith(wildcard);
        String[] array = StringUtils.split(pattern, wildcard);
        int currentIndex = -1;
        int lastIndex = -1 ;
        switch (array.length) {
            case 0:
                return true ;
            case 1:
                currentIndex = str.indexOf(array[0]);
                if (startWith && endWith) {
                    return currentIndex >= 0 ;
                }
                if (startWith) {
                    return currentIndex + array[0].length() == str.length();
                }
                if (endWith) {
                    return currentIndex == 0 ;
                }
                return str.equals(pattern) ;
            default:
                for (String part : array) {
                    currentIndex = str.indexOf(part);
                    if (currentIndex > lastIndex) {
                        lastIndex = currentIndex;
                        continue;
                    }
                    return false;
                }
                return true;
        }
    }

    为了验证这两个方法,测试类借用了一部分原文的测试例子:

public class RegexUtilsTest {
    /**
     * test '?' and '*'
     */
    @Test
    public void testWildMatch2() {
        assertTrue(RegexUtils.wildcardMatch("1234?", "12345"));
        assertTrue(RegexUtils.wildcardMatch("1234?", "1234"));
        assertFalse(RegexUtils.wildcardMatch("1234?", "123456"));

        assertTrue(RegexUtils.wildcardMatch("abc*x?yz*", "abcxxxyz"));
        assertTrue(RegexUtils.wildcardMatch("abc*xxx?yz*", "abcxxxyz"));
    }

    @Test
    public void testWildMatch() {
        assertTrue(RegexUtils.wildcardMatch("*", "toto"));
        assertFalse(RegexUtils.wildcardMatch("toto.java", "tutu.java"));
        assertFalse(RegexUtils.wildcardMatch("12345", "1234"));
        assertFalse(RegexUtils.wildcardMatch("*f", ""));
        assertTrue(RegexUtils.wildcardMatch("***", "toto"));

        assertFalse(RegexUtils.wildcardMatch("*.java", "toto."));
        assertFalse(RegexUtils.wildcardMatch("*.java", "toto.jav"));
        assertTrue(RegexUtils.wildcardMatch("*.java", "toto.java"));
        assertFalse(RegexUtils.wildcardMatch("abc*", ""));
        assertTrue(RegexUtils.wildcardMatch("a*c", "abbbbbccccc"));

        assertTrue(RegexUtils.wildcardMatch("abc*xyz", "abcxxxyz"));
        assertTrue(RegexUtils.wildcardMatch("*xyz", "abcxxxyz"));
        assertTrue(RegexUtils.wildcardMatch("abc**xyz", "abcxxxyz"));
        assertTrue(RegexUtils.wildcardMatch("abc**x", "abcxxx"));
        assertTrue(RegexUtils.wildcardMatch("*a*b*c**x", "aaabcxxx"));

        assertTrue(RegexUtils.wildcardMatch("abc*x*yz", "abcxxxyz"));
        assertTrue(RegexUtils.wildcardMatch("a*b*c*x*yf*z*", "aabbccxxxeeyffz"));
        assertFalse(RegexUtils.wildcardMatch("a*b*c*x*yf*zze", "aabbccxxxeeyffz"));
        assertTrue(RegexUtils.wildcardMatch("a*b*c*x*yf*z", "aabbccxxxeeyffz"));
        assertTrue(RegexUtils.wildcardMatch("a*b*c*x*yf*ze", "aabbccxxxeeyfze"));

        assertTrue(RegexUtils.wildcardMatch("*LogServerInterface*.java", "_LogServerInterfaceImpl.java"));
        assertTrue(RegexUtils.wildcardMatch("*Log*Impl.java", "_LogServerInterfaceImpl.java"));
        assertTrue(RegexUtils.wildcardMatch("abc*xyz", "abcxyxyz"));

        String str = this.getClass().getName() ;
        assertTrue(RegexUtils.wildcardMatch("com.oocllogistics.comp.*", str));
        assertTrue(RegexUtils.wildcardMatch(RegexUtilsTest.class.getName(), str));
        assertTrue(RegexUtils.wildcardMatch("*.RegexUtilsTest", str));
        assertTrue(RegexUtils.wildcardMatch("*com.oocllogistics.comp.util.RegexUtilsTest", str));
        assertTrue(RegexUtils.wildcardMatch("*.comp.*", str));

        assertFalse(RegexUtils.wildcardMatch("comp.*", str));
        assertFalse(RegexUtils.wildcardMatch("*.RegexUtils", str));
        assertTrue(RegexUtils.wildcardMatch("com.*.comp.*", str));
        assertTrue(RegexUtils.wildcardMatch("com.*.RegexUtilsTest", str));
        assertTrue(RegexUtils.wildcardMatch("com.*.RegexUtilsTest*", str));

        assertTrue(RegexUtils.wildcardMatch("*com.*.RegexUtilsTest", str));
        assertTrue(RegexUtils.wildcardMatch("*com.*.*UtilsTest*", str));
        assertTrue(RegexUtils.wildcardMatch("*com**UtilsTest*", str));
        assertTrue(RegexUtils.wildcardMatch("**com**Utils**", str));
        assertFalse(RegexUtils.wildcardMatch("com.", str));
    }

    @Test
    public void tesstSimpleWildcardMatch() {
        assertTrue(RegexUtils.simpleWildcardMatch("*", "toto"));
        assertFalse(RegexUtils.simpleWildcardMatch("toto.java", "tutu.java"));
        assertFalse(RegexUtils.simpleWildcardMatch("12345", "1234"));
        assertFalse(RegexUtils.simpleWildcardMatch("*f", ""));
        assertTrue(RegexUtils.simpleWildcardMatch("***", "toto"));

        assertFalse(RegexUtils.simpleWildcardMatch("*.java", "toto."));
        assertFalse(RegexUtils.simpleWildcardMatch("*.java", "toto.jav"));
        assertTrue(RegexUtils.simpleWildcardMatch("*.java", "toto.java"));
        assertFalse(RegexUtils.simpleWildcardMatch("abc*", ""));
        assertTrue(RegexUtils.simpleWildcardMatch("a*c", "abbbbbccccc"));

        assertTrue(RegexUtils.simpleWildcardMatch("abc*xyz", "abcxxxyz"));
        assertTrue(RegexUtils.simpleWildcardMatch("*xyz", "abcxxxyz"));
        assertTrue(RegexUtils.simpleWildcardMatch("abc**xyz", "abcxxxyz"));
        assertTrue(RegexUtils.simpleWildcardMatch("abc**x", "abcxxx"));
        assertTrue(RegexUtils.simpleWildcardMatch("*a*b*c**x", "aaabcxxx"));

        assertTrue(RegexUtils.simpleWildcardMatch("abc*x*yz", "abcxxxyz"));
        assertTrue(RegexUtils.simpleWildcardMatch("a*b*c*x*yf*z*", "aabbccxxxeeyffz"));
        assertFalse(RegexUtils.simpleWildcardMatch("a*b*c*x*yf*zze", "aabbccxxxeeyffz"));
        assertTrue(RegexUtils.simpleWildcardMatch("a*b*c*x*yf*z", "aabbccxxxeeyffz"));
        assertTrue(RegexUtils.simpleWildcardMatch("a*b*c*x*yf*ze", "aabbccxxxeeyfze"));

        assertTrue(RegexUtils.simpleWildcardMatch("*LogServerInterface*.java", "_LogServerInterfaceImpl.java"));
        assertTrue(RegexUtils.simpleWildcardMatch("*Log*Impl.java", "_LogServerInterfaceImpl.java"));
        assertTrue(RegexUtils.simpleWildcardMatch("abc*xyz", "abcxyxyz"));

        String str = this.getClass().getName() ;
        assertTrue(RegexUtils.simpleWildcardMatch("com.oocllogistics.comp.*", str));
        assertTrue(RegexUtils.simpleWildcardMatch(RegexUtilsTest.class.getName(), str));
        assertTrue(RegexUtils.simpleWildcardMatch("*.RegexUtilsTest", str));
        assertTrue(RegexUtils.simpleWildcardMatch("*com.oocllogistics.comp.util.RegexUtilsTest", str));
        assertTrue(RegexUtils.simpleWildcardMatch("*.comp.*", str));

        assertFalse(RegexUtils.simpleWildcardMatch("comp.*", str));
        assertFalse(RegexUtils.simpleWildcardMatch("*.RegexUtils", str));
        assertTrue(RegexUtils.simpleWildcardMatch("com.*.comp.*", str));
        assertTrue(RegexUtils.simpleWildcardMatch("com.*.RegexUtilsTest", str));
        assertTrue(RegexUtils.simpleWildcardMatch("com.*.RegexUtilsTest*", str));

        assertTrue(RegexUtils.simpleWildcardMatch("*com.*.RegexUtilsTest", str));
        assertTrue(RegexUtils.simpleWildcardMatch("*com.*.*UtilsTest*", str));
        assertTrue(RegexUtils.simpleWildcardMatch("*com**UtilsTest*", str));
        assertTrue(RegexUtils.simpleWildcardMatch("**com**Utils**", str));
        assertFalse(RegexUtils.simpleWildcardMatch("com.", str));
    }

    public void performanceTestWildcardMatch() {
        int loop = 1000 ;
        long start = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            testWildMatch();
        }
        long end = System.currentTimeMillis();
        System.out.println("Loop[1000] cost : " + (end - start) / 1000d + " seconds");

        loop = 5000 ;
        start = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            testWildMatch();
        }
        end = System.currentTimeMillis();
        System.out.println("Loop[5000] cost : " + (end - start) / 1000d + " seconds");

        loop = 10000 ;
        start = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            testWildMatch();
        }
        end = System.currentTimeMillis();
        System.out.println("Loop[10000] cost : " + (end - start) / 1000d + " seconds");
    }

    public void performanceTestSimpleWildcardMatch() {
        int loop = 1000 ;
        long start = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            tesstSimpleWildcardMatch();
        }
        long end = System.currentTimeMillis();
        // log.info("cost : "+(end - start)/1000d + " seconds");
        System.out.println("Loop[1000] cost : " + (end - start) / 1000d + " seconds");

        loop = 5000 ;
        start = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            tesstSimpleWildcardMatch();
        }
        end = System.currentTimeMillis();
        System.out.println("Loop[5000] cost : " + (end - start) / 1000d + " seconds");

        loop = 10000 ;
        start = System.currentTimeMillis();
        for (int i = 0; i < loop; i++) {
            tesstSimpleWildcardMatch();
        }
        end = System.currentTimeMillis();
        System.out.println("Loop[10000] cost : " + (end - start) / 1000d + " seconds");

    }

    @Test
    public void performanceTest() {
        System.out.println("------Test wildcardMatch---------");
        performanceTestWildcardMatch();
        System.out.println();
        System.out.println("------Test simpleWildcardMatch---------");
        performanceTestSimpleWildcardMatch();
    }
}

   其中PerformanceTest方法分别对wildcardMatch喝simpleWildcardMatch进行了1000,5000,10000次重复运行Test Case比较,其中每个case包括38个匹配断言。下面是性能测试结果:

 

------Test wildcardMatch---------
Loop[1000] cost : 0.703 seconds
Loop[5000] cost : 2.547 seconds
Loop[10000] cost : 4.907 seconds

------Test simpleWildcardMatch---------
Loop[1000] cost : 0.094 seconds
Loop[5000] cost : 0.25 seconds
Loop[10000] cost : 0.484 seconds

 

   我们可以看到,使用simpleWildCardMatch要比wildcardMatch方法快上一个数量级。 所以如果有朋友有兴趣,建议使用只支持*号的simpleWildcardMatch。(当然了,实际应用中,这种性能差别其实对application影响并不大)

    如果有网友有兴趣,可以尝试优化,或者提供更多的测试。

分享到:
评论

相关推荐

    Java开发技术大全(500个源代码).

    signByIF.java 用if语句实现符号函数示例 triangleStar.java 输出一个由*组成的直角三角形 upperToLowCase.java 大写转换成小写 variableScopeExample.java 变量使用范围示例 第3章 示例描述:本章学习对象和类...

    java范例开发大全源代码

    第1篇 Java编程基础  第1章 Java开发环境的搭建(教学视频:9分钟) 2  1.1 理解Java 2  1.2 搭建Java所需环境 3  1.2.1 下载JDK 3  1.2.2 安装JDK 4  1.2.3 配置环境 5  1.2.4 测试JDK配置...

    java范例开发大全

    实例264 泛型类的类型识别示例 523 实例265 强制类型转换示例 525 14.3 擦拭 526 实例266 无限界的擦拭 526 实例267 有限界的擦拭 527 14.4 集合泛型类 528 实例268 Hashtable的泛型化 528 实例269 多功能画笔 529 ...

    Java范例开发大全 (源程序)

    第1篇 Java编程基础  第1章 Java开发环境的搭建(教学视频:9分钟) 2  1.1 理解Java 2  1.2 搭建Java所需环境 3  1.2.1 下载JDK 3  1.2.2 安装JDK 4  1.2.3 配置环境 5  1.2.4 测试JDK配置是否成功 7...

    Java范例开发大全(全书源程序)

    Java范例开发大全(全书源程序),目录如下: 第1篇 Java编程基础 第1章 Java开发环境的搭建(教学视频:9分钟) 2 1.1 理解Java 2 1.2 搭建Java所需环境 3 ...实例264 泛型类的类型识别示例 523 实例265...

    java范例开发大全(pdf&源码)

    第1篇 Java编程基础 第1章 Java开发环境的搭建(教学视频:9分钟) 2 1.1 理解Java 2 1.2 搭建Java所需环境 3 1.2.1 下载JDK 3 1.2.2 安装JDK 4 1.2.3 配置环境 5 ...实例264 泛型类的类型识别示例 523 实例...

    Java开发技术大全 电子版

    10.5通配符参数311 10.6泛型方法313 10.7泛型接口315 10.8泛型类的继承317 10.8.1以泛型类为父类317 10.8.2以非泛型类为父类319 10.8.3运行时类型识别320 10.8.4强制类型转换321 10.8.5继承规则322 10.9...

    JCLILIB:一个用于解析命令行的Java 7库。-开源

    JCLILIB(Java命令行界面库)是一个小的Java库,用于解析命令行中提供的参数。 功能包括通过键(“ -h”),键和值(“ -f some_file”或“ -f = some_file”)或位置(例如,未附加在键上的第二个自变量)识别自...

    java微信公众号MVC开发框架

    url-pattern模式匹配微信公众号平台服务器配置的URL配置,如果需要处理多个微信公众号,可以配置多个servlet-mapping或者使用路径通配符匹配多个url链接。 3、spring配置文件 spring配置文件applicationContext.xml...

    java开发oa办公系统源码-pt:为了

    java开发oa办公系统源码 信息收集 主机信息收集 敏感目录文件收集 目录爆破 BurpSuite 搜索引擎语法 可搜索微博、人人网等屏蔽了主流搜索引擎的网站 js文件泄漏后台或接口信息 快捷搜索第三方资源 robots.txt 目录可...

    Lucene中文分词组件 JE-Analysis 1.5.1

    数量词采用“n”作为数字通配符 优化词典结构以便修改调整 1.1 —— 2006-06-06 增加扩展词典的静态读取方法 1.0.1 —— 2006-06-02 修正无法识别生僻字的问题 1.0 —— 2006-05-29 支持英文、...

    mqtt-regex:将带有参数的MQTT主题转换为正则表达式

    正则表达式 将带有参数的MQTT主题转换为正则表达式。 除非需要正则表达式支持,否则应使用更快的 例子 var mqtt_regex = require ( "mqtt-regex" ) ; var pattern = "chat/+id/+user/#path" ;...

    drb56-Assignment1

    ##Background:给定一个 4x4 的字母网格,Boggle 是通过让用户识别至少三个字符的有效英语单词来播放的,这些单词可以通过连接 boggle 板上的相邻字母来制作。 相邻的字母可以水平、垂直或对角地彼此相邻。 请注意...

    MacGesture:适用于macOS的全局鼠标手势

    :raising_hands:产品特点全局鼠标手势识别通过手势可配置的快捷方式调用基于包标识符的应用过滤手势格式手势首字母缩写向左移动L 提升U 向右移R 下移D 左键Z 向上转u 车轮Dp d 手势可以包含通配符匹配( ?...

    Lucene中文分词组件 JE-Analysis 1.4.0

    数量词采用“n”作为数字通配符 优化词典结构以便修改调整 1.1 —— 2006-06-06 增加扩展词典的静态读取方法 1.0.1 —— 2006-06-02 修正无法识别生僻字的问题 1.0 —— 2006-05-29 支持英文、...

    Mybatis-plus(Mybatis增强工具包) v3.3.2

    3、Spring根据不同环境加载不同配置支持(支持typeAliasesPackage通配符扫描)。 【自动生成Entity Mapper Service文件】Mybatis-plus(Mybatis增强工具包) v3.3.2更新日志分页参数提取,单元测试用例修复 达梦...

Global site tag (gtag.js) - Google Analytics