如何与java.util.regex执行部分匹配。*?

时间:2010-03-18 11:01:20

标签: java regex

到目前为止,我一直在Java中使用java.util.regex。*类来表示正则表达式。但今天我有不同的要求。例如,将模式视为“aabb”。现在,如果输入字符串是aa肯定不匹配,但是如果我追加bb它仍然有可能变成aabb并且它匹配。但是,如果我开始使用cc,无论我追加什么,它都永远不会匹配。

我已经探索过Pattern和Matcher类,但没有找到任何方法来实现这一目标。

输入将来自用户,系统必须等到模式匹配,否则无论输入是什么都不会匹​​配。

有任何线索吗?

感谢。

7 个答案:

答案 0 :(得分:35)

您应该更仔细地查看Matcher API; hitEnd()方法完全按照您的描述工作:

import java.util.regex.*;

public class Test
{
  public static void main(String[] args) throws Exception
  {
    String[] ss = { "aabb", "aa", "cc", "aac" };
    Pattern p = Pattern.compile("aabb");
    Matcher m = p.matcher("");

    for (String s : ss) {
      m.reset(s);
      if (m.matches()) {
        System.out.printf("%-4s : match%n", s);
      }
      else if (m.hitEnd()) {
        System.out.printf("%-4s : partial match%n", s);
      }
      else {
        System.out.printf("%-4s : no match%n", s);
      }
    }
  }
}

输出:

aabb : match
aa   : partial match
cc   : no match
aac  : no match

据我所知,Java是唯一公开此功能的语言。还有requireEnd()方法,它告诉您更多输入是否可以将匹配变为不匹配,但我不认为它与您的情况相关。

添加了两种方法以支持Scanner类,因此它可以将正则表达式应用于流,而无需将整个流读入内存。

答案 1 :(得分:11)

Pattern p = Pattern.compile(expr);
Matcher m = p.matcher(string);
m.find();

答案 2 :(得分:1)

所以你想知道String是否与正则表达式匹配,但是是否可能有更长的String以匹配的s开头?抱歉,Regexes无法帮助您,因为您无法访问匹配器的内部状态;你只得到布尔结果和你定义的任何组,所以你永远不会知道为什么匹配失败。

如果您愿意破解JDK库,可以扩展(或可能分叉)java.util.regex并提供有关匹配过程的更多信息。如果匹配失败,因为输入已“用完”,答案将是 true ;如果由于字符歧视或其他检查而失败,那将是 false 。这似乎是很多工作,因为你的问题完全与正则表达式应该做的相反。

另一种选择:也许您可以简单地重新定义任务,以便将输入视为正则表达式并将 aabb 与* aa匹配。**?但是,你必须小心正则表达式元字符。

答案 3 :(得分:0)

对于您给出的示例,您可以尝试使用反模式取消无效结果的资格。例如“^ [^ a]”会告诉您输入“c ...”与“aabb”的示例模式不匹配。

根据您的模式,您可以将其分解为较小的模式以检查和使用多个匹配器,然后在发生一次匹配时设置其边界,然后移动到下一个。这种方法可能有效但如果你的模式很复杂并且可以有可变长度的子部分,你最终可能会在你自己的代码中重新实现匹配器的一部分,以调整匹配的可能范围,使其或多或少贪婪。伪代码的一般概念是:

boolean match(String input, Matcher[] subpatterns, int matchStart, int matchEnd){
  matcher = next matcher in list;
  int stop = matchend;
  while(true){
    if matcher.matches input from matchstart -> matchend{
      if match(input, subpatterns, end of current match, end of string){
        return true;
      }else{
        //make this match less greedy
        stop--;
      }
    }else{
      //no match
      return false;
    }
  }
}

然后你可以将这个想法与反模式合并,并且具有反子模式,并且在每个子模式匹配之后检查下一个反模式,如果匹配则知道你已经失败,否则继续匹配模式。您可能希望返回类似枚举的内容而不是布尔值(即ALL_MATCHED,PARTIAL_MATCH,ANTI_PATTERN_MATCH,......)

再次根据您尝试匹配的实际模式的复杂程度,相应的子模式/反模式可能很难,如果不是不可能的话。

答案 4 :(得分:0)

执行此操作的一种方法是将正则表达式解析为一系列子正则表达式,然后以允许您进行部分匹配的方式重新组合它们;例如“ab c”有3个子正则表达式“a”,“b ”和“c”,然后你可以将它们重组为“a(b *(c)?)?”。

当输入正则表达式包含交替和组时,事情变得更复杂,但是相同的一般方法应该有效。

这种方法的问题在于,由此产生的正则表达式更复杂,并且可能导致复杂输入正则表达式的过度回溯。

答案 5 :(得分:0)

如果你使正则表达式的每个字符都是可选的并放宽了多重约束,你就会得到你想要的东西。例如,如果你有一个匹配的模式“aa(abc)+ bbbb”,你可以有一个'可能的匹配'模式'a?a?(a?b?c?)* b?b?b?b?'。

这种产生可能匹配模式的机制方法虽然不包括前向和后向引用等高级构造。

答案 6 :(得分:-1)

您可以使用状态机(http://en.wikipedia.org/wiki/State_machine)完成此操作。让状态/转换表示有效输入和一个错误状态。然后,您可以一次向状态机提供一个字符(可能是子字符串,具体取决于您的数据)。您可以随时检查状态机是否处于错误状态。如果它不处于错误状态,那么您知道未来的输入可能仍然匹配。如果它处于错误状态,那么你知道以前失败的东西,任何将来的输入都不会使字符串有效。