`
凤舞凰扬
  • 浏览: 66925 次
  • 性别: 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实现一个将自然语言转换为cron表达式的工具包,可用于对话机器人的定时任务以及平常开发中的cron表达式识别

    总的来说,这个Java实现的自然语言到cron表达式转换工具包,结合了NLP技术,旨在降低用户与系统交互的难度,提高用户体验,特别是在对话机器人和定时任务管理场景下。其背后涉及的理论和技术都是计算机科学和人工...

    java实现的连接数据库及模糊查询功能示例

    Java实现连接数据库及模糊查询功能示例 Java语言是当前最流行的程序设计语言之一,在数据处理和存储方面,Java提供了非常强大的支持。连接数据库是Java编程中非常重要的一步,通过连接数据库,Java程序可以对数据库...

    带通配符的字符串匹配.zip

    在IT领域,字符串匹配是一项基础且重要的任务,广泛应用于文件搜索、文本处理、模式识别等多个场景。当涉及到“带通配符的字符串匹配”时,我们通常是指在字符串搜索过程中,使用特殊字符(如星号(*)或问号(?))来...

    Thinking in Java 练习题答案

    练习题可能要求你识别并实现这些模式。 解答这些练习题不仅有助于深化对Java的理解,还能提高编程技巧,为实际项目开发打下坚实的基础。通过深入研究和实践,你可以成为一名熟练的Java开发者。

    java环境搭建步骤

    path变量用于指定系统可以识别的命令所在的目录,比如Java编译器和运行时环境的路径。classpath变量用于指定Java类加载器在查找类时需要搜索的目录路径。具体来说,path变量需要在原有值的基础上添加JDK安装目录下的...

    2018最新Java基础教程视频

    - **环境变量设置**: 设置JAVA_HOME、PATH等环境变量,确保系统能够识别Java命令行工具。 #### 2. Java基本语法 - **注释**: 单行注释(`//`)、多行注释(`/* */`)和文档注释(`/** */`)。 - **数据类型**: 基本...

    C#代码转java代码

    C#到Java的转换工具通常会解析C#源代码,识别出语法规则,并按照Java的语法规则重构代码。这个过程中,工具需要处理的关键点包括但不限于: 1. 类和对象:C#中的类和接口转换为Java中的对应结构。 2. 方法:C#的...

    java开发实战经典第十二章课后习题答案

    习题可能要求识别和实现特定设计模式。 8. **反射机制**:Java的反射机制允许在运行时检查类的信息并动态调用方法。习题可能涉及获取类、字段和方法的信息,以及动态创建对象。 9. **泛型**:泛型提高了代码的类型...

    Java SE Development Kit 8

    Java SE Development Kit 8,简称JDK 8,是Oracle公司发布的Java开发工具包,用于构建和运行Java应用程序。...记得在安装后配置系统环境变量,确保PATH中包含JDK的bin目录,以便系统能够正确识别和执行Java命令。

    core java I (java核心编程)学习笔记

    1. **Java环境搭建**:首先,我们需要安装Java Development Kit (JDK),设置好环境变量,包括JAVA_HOME、PATH和CLASSPATH,确保系统能够正确识别和执行Java程序。 2. **Java语法基础**:Java是一种面向对象的语言,...

    java编程第4版完整版,完整书签,扫描但文字可搜索复制

    《Java编程思想》第四版详细阐述了泛型的概念、泛型类、泛型方法以及通配符的使用,使得读者能够编写更加安全、灵活的代码。 #### 集合框架 Java的集合框架是用于存储和操作数据的高效工具。本书深入讲解了集合...

    Java题库175道选择题

    集合框架是Java中处理数据的重要工具,包括List、Set、Map等接口及其实现类。题目可能会测试你对ArrayList、LinkedList、HashMap、HashSet等的区别和使用场景的理解,以及如何有效地操作和遍历集合。 多线程是Java...

    java解惑java解惑java解惑

    - **ArrayList与LinkedList**:两种常用列表实现,理解它们的性能差异和使用场景。 - **HashMap与TreeMap**:哈希表和有序映射的区别,以及它们的遍历方式。 - **Set接口**:不包含重复元素的集合,如HashSet和...

    java面试宝典pdf

    - HashMap、HashSet、LinkedList等实现类:熟悉它们的内部实现和性能特点。 - 集合操作:如迭代、查找、排序、去重等。 - 泛型:理解泛型的用途和限制。 6. **多线程**: - 线程的创建与运行:掌握Thread类和...

    java课件(PPT)含实例

    2. **环境配置**:讲解如何安装Java Development Kit (JDK) 和设置环境变量,使计算机能够识别并运行Java程序。 3. **语法基础**:包括基本数据类型(如整型、浮点型、字符型、布尔型)、变量、常量的定义与使用,...

    Core-Java-Interview-Questions.rar_core java interview

    - 实现多个接口:理解Java中类如何通过接口实现多重继承。 7. **异常处理** - 异常分类:检查型异常和运行时异常的区别。 - try-catch-finally语句块:异常捕获和处理的基本结构。 8. **集合框架** - List、...

    JAVA程序设计笔试题目复习大纲

    - **内存泄漏**:识别和避免可能导致内存浪费或程序崩溃的问题。 4. **多线程** - **线程创建**:通过Thread类和实现Runnable接口两种方式创建线程。 - **同步机制**:理解synchronized关键字,死锁、活锁、饥饿...

    JAVA技术面试题

    - **泛型**:使用泛型的好处,类型擦除的概念,以及通配符的运用。 5. **内存管理** - **JVM内存模型**:解释堆、栈、方法区、本地方法栈和程序计数器的作用。 - **垃圾回收**:理解垃圾回收的工作原理,GC ...

Global site tag (gtag.js) - Google Analytics