Java中的通配符匹配

时间:2014-06-21 02:11:31

标签: java regex wildcard

我正在编写一个简单的调试程序,该程序将包含星号的简单字符串作为输入,以指示通配符匹配 - 任何

*.wav  // matches <anything>.wav
(*, a) // matches (<anything>, a)

我以为我会简单地使用该模式,转义其中的任何正则表达式特殊字符,然后将任何\\*替换回.*。然后使用正则表达式匹配器。

但我无法找到任何Java函数来逃避正则表达式。我能找到的最佳匹配是Pattern.quote,但只是将\Q\E放在字符串的开头和结尾。

Java中是否有任何内容可以让您简单地进行通配符匹配而无需从头开始实现算法?

6 个答案:

答案 0 :(得分:13)

逃避一切 - 不会有任何伤害。

    String input = "*.wav";
    String regex = ("\\Q" + input + "\\E").replace("*", "\\E.*\\Q");
    System.out.println(regex); // \Q\E.*\Q.wav\E
    System.out.println("abcd.wav".matches(regex)); // true

或者你可以使用角色类:

    String input = "*.wav";
    String regex = input.replaceAll(".", "[$0]").replace("[*]", ".*");
    System.out.println(regex); // .*[.][w][a][v]
    System.out.println("abcd.wav".matches(regex)); // true

通过将字符放入字符类来“转义”字符会更容易,因为在字符类中几乎所有字符都会失去任何特殊含义。除非您期待奇怪的文件名,否则这将起作用。

答案 1 :(得分:12)

使用简单的正则表达式

这种方法的一个好处是我们可以轻松添加除*之外的令牌(请参阅底部的添加令牌)。

搜索:[^*]+|(\*)

  • |的左侧匹配任何不是星星的字符
  • 右侧将所有明星捕获到第1组
  • 如果第1组为空:请替换为\Q +匹配+ E
  • 如果设置了第1组:请替换为.*

以下是一些工作代码(请参阅online demo的输出)。

输入:audio*2012*.wav

输出:\Qaudio\E.*\Q2012\E.*\Q.wav\E

String subject = "audio*2012*.wav";
Pattern regex = Pattern.compile("[^*]+|(\\*)");
Matcher m = regex.matcher(subject);
StringBuffer b= new StringBuffer();
while (m.find()) {
    if(m.group(1) != null) m.appendReplacement(b, ".*");
    else m.appendReplacement(b, "\\\\Q" + m.group(0) + "\\\\E");
}
m.appendTail(b);
String replaced = b.toString();
System.out.println(replaced);

添加代币

假设我们还想用一个点转换代表单个字符的通配符?。我们只是在正则表达式中添加一个捕获组,并将其从左侧的matchall中排除:

搜索:[^*?]+|(\*)|(\?)

在替换功能中,我们添加如下内容:

else if(m.group(2) != null) m.appendReplacement(b, "."); 

答案 2 :(得分:8)

Apache Commons-IO库中有一个小实用工具方法:org.apache.commons.io.FilenameUtils #wildcardMatch(),您可以使用它而不需要复杂的正则表达式。

可以在以下网址找到API文档:https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/FilenameUtils.html#wildcardMatch(java.lang.String,%20java.lang.String)

答案 3 :(得分:1)

您还可以使用引号转义字符:\\Q and \\E - 它们之间的所有内容都被视为文字,并且不被视为要评估的正则表达式的一部分。因此,这段代码应该有效:

    String input = "*.wav";
    String regex = "\\Q" + input.replace("*", "\\E.*?\\Q") + "\\E";

    // regex = "\\Q\\E.*?\\Q.wav\\E"

请注意,您的*通配符也可能只能与使用\ w的单词字符匹配,具体取决于您希望通配符的行为方式(?)

答案 4 :(得分:0)

Lucene拥有提供此功能的类,并且还支持反斜杠作为转义字符。 ?匹配单个字符,1匹配0个或多个字符,\转义后续字符。支持Unicode代码点。假设速度很快,但我没有测试过。

CharacterRunAutomaton characterRunAutomaton;
boolean matches;
characterRunAutomaton = new CharacterRunAutomaton(WildcardQuery.toAutomaton(new Term("", "Walmart")));
matches = characterRunAutomaton.run("Walmart"); // true
matches = characterRunAutomaton.run("Wal*mart"); // false
matches = characterRunAutomaton.run("Wal\\*mart"); // false
matches = characterRunAutomaton.run("Waldomart"); // false
characterRunAutomaton = new CharacterRunAutomaton(WildcardQuery.toAutomaton(new Term("", "Wal*mart")));
matches = characterRunAutomaton.run("Walmart"); // true
matches = characterRunAutomaton.run("Wal*mart"); // true
matches = characterRunAutomaton.run("Wal\\*mart"); // true
matches = characterRunAutomaton.run("Waldomart"); // true
characterRunAutomaton = new CharacterRunAutomaton(WildcardQuery.toAutomaton(new Term("", "Wal\\*mart")));
matches = characterRunAutomaton.run("Walmart"); // false
matches = characterRunAutomaton.run("Wal*mart"); // true
matches = characterRunAutomaton.run("Wal\\*mart"); // false
matches = characterRunAutomaton.run("Waldomart"); // false

答案 5 :(得分:0)

适应DOS / Windows路径时的正则表达式

实施引用转义字符\Q\E可能是最好的方法。但是,由于反斜杠通常用作DOS / Windows文件分隔符,因此&#34; \E&#34;路径中的序列可能会影响\Q\E的配对。在考虑*?通配符令牌的同时,可以通过以下方式解决反斜杠的这种情况:

搜索:[^*?\\]+|(\*)|(\?)|(\\)

在&#34;使用简单正则表达式&#34;的替换功能中添加两个新行。适应新搜索模式的示例。代码仍然是&#34; Linux友好&#34;。作为一种方法,可以这样写:

public String wildcardToRegex(String wildcardStr) {
    Pattern regex=Pattern.compile("[^*?\\\\]+|(\\*)|(\\?)|(\\\\)");
    Matcher m=regex.matcher(wildcardStr);
    StringBuffer sb=new StringBuffer();
    while (m.find()) {
        if(m.group(1) != null) m.appendReplacement(sb, ".*");
        else if(m.group(2) != null) m.appendReplacement(sb, ".");     
        else if(m.group(3) != null) m.appendReplacement(sb, "\\\\\\\\");
        else m.appendReplacement(sb, "\\\\Q" + m.group(0) + "\\\\E");
    }
    m.appendTail(sb);
    return sb.toString();
}

用于演示此方法实现的代码可以这样写:

String s = "C:\\Temp\\Extra\\audio??2012*.wav";
System.out.println("Input: "+s);
System.out.println("Output: "+wildcardToRegex(s));

这将是生成的结果:

Input: C:\Temp\Extra\audio??2012*.wav
Output: \QC:\E\\\QTemp\E\\\QExtra\E\\\Qaudio\E..\Q2012\E.*\Q.wav\E