【问题标题】:Partial Matching of Regular Expressions正则表达式的部分匹配
【发布时间】:2017-06-23 17:33:32
【问题描述】:

在 NFA 中,很容易使所有以前的非最终状态接受以使其匹配给定语言的所有子字符串的语言。

在 Java 正则表达式引擎中, 有没有办法找出一个字符串是否是与给定正则表达式匹配的字符串的起始子字符串?

regexX = "any start of", regexA - 任何给定的正则表达式

“regexXregexA”结果表达式匹配匹配“regexA”的所有子字符串:

示例:

regexA = a*b

“a”匹配

"regexXa*b"

因为它是“ab”(和“aab”)的开头
编辑:

由于有些人还是看不懂,下面就这道题做一个程序测试:

import java.util.regex.*;
public class Test1 {
    public static void main(String args[]){
       String regex = "a*b";
       System.out.println(
       partialMatch(regex, "aaa");
       );
     }
public boolean partialMatch(String regex, String begining){
//return true if there is a string which matches the regex and    
//startsWith(but not equal) begining, false otherwise 
}
}

结果为真。

【问题讨论】:

  • 您能解释一下您的问题吗?
  • 您在寻找word boundary吗?
  • 不,问题的文字中解释得很清楚。什么是正则表达式?
  • “非常清楚”是主观的恕我直言。至少还有一位用户不理解您的问题。
  • 什么是 regexX?测试是否有第二部分的条件?并找到你的模式是否会存在?

标签: java regex


【解决方案1】:

在 NFA 中,很容易让所有以前的非最终状态接受以使其匹配给定语言的所有子字符串的语言。

确实,它可以通过添加一个新的最终状态和从每个状态(最终或非最终状态)到新的最终状态的 ε-move 来完成。

Afaik 没有与此操作等效的正则表达式。

有些正则表达式库可能提供了一种方法来验证字符串是否是正则表达式的部分匹配,我不知道。我不懂Java,我主要在PHP 中工作,它不提供这样的功能。也许有图书馆可以做到这一点,但我从来不需要。

对于一个小的、特定的正则表达式,您可以尝试构建一个新的正则表达式,通过组合以下简单规则来匹配部分匹配原始正则表达式的字符串:

  • a -> a?
  • ab -> ab?
  • a* -> a*
  • a+ -> a*
  • a|b -> (a|b)?

ab 以上是原始正则表达式的子正则表达式。根据需要使用括号。

【讨论】:

  • 感谢 axiac 的尝试!不幸的是,我不能使用小的和/或特定的正则表达式:我正在构建解析器生成器(这部分用于 Lexer 生成器)(所以我不知道语法输入会是什么)。我需要知道到目前为止的字符串是否匹配任何正则表达式。(因为最终完全匹配它的字符串可以是“无限”长(或非常长))。
  • 好吧,如果你正在构建一个词法分析器,你应该比我更了解如何将 NFA 转换为正则表达式,反之亦然。
  • 是的,这是一个解决方案:将所有运行时正则表达式转换为 NFA,进行该操作,转换回来并进行匹配。我完全出乎意料地偶然发现了这个问题,觉得它应该不超过 3 行代码。我不知道 java 标准包中是否有 NFA 的完整实现。我只是为了这个场合觉得不合适,所以我在这里问。底线我认为 java 正则表达式应该为 FA 做任何事情,这就是我问的原因。
  • 我没有标记您的答案,因为它实际上不正确。如果您尝试推断它(“上面的 a 和 b 是原始正则表达式的子正则表达式”)。您可以看到,在第二条规则中,我们将正则表达式分为两个子正则表达式:a 和 b。然后将(按顺序)第一个规则应用于 a -> a?会导致 a?b?这是不正确的,因为它匹配“b”,它不应该匹配。所以 a 和 b 不能是其他正则表达式。(即集合不起作用)。应该做的规则是找到所有可能的后缀并将它们标记为“?”
  • 我同意你的回答。您会注意到最后一项是“等”;我没有很努力地写它,我知道它对你没有多大帮助。特别是因为您没有可以轻松转换的小型已知正则表达式。第二个转换规则应为:Ab -> Ab? 其中b 是一个字符,A 是一个子表达式。其他的也应该重新制定以使其可用。最初我不打算写答案,但评论太长了。
【解决方案2】:

您要查找的内容称为部分匹配,Java regex API 本身就支持它(作为记录,提供此功能的其他引擎包括 PCRE 和 boost::regex)。

您可以通过检查 Matcher.hitEnd 函数的结果来判断输入字符串是否部分匹配,该函数会判断匹配是否因为到达输入字符串的末尾而失败。

Pattern pattern = Pattern.compile("a*b");
Matcher matcher = pattern.matcher("aaa");
System.out.println("Matches: " + matcher.matches());
System.out.println("Partial match: " + matcher.hitEnd());

这个输出:

Matches: false
Partial match: true

【讨论】:

  • 谢谢,这实际上是 NFA 思想的一对一映射。您能否详细说明matches() 是如何实现的?是否只是一个底层 NFA,如果输入端在非最终状态下被击中(既不接受也不拒绝)“hitEnd”标志升起?
  • @bedbad 我不知道实现细节,但它背后的想法就像你描述的那样:如果你最终处于非最终状态,没有更多可能的转换(因为没有更多的输入),然后hitEnd 将返回true
  • @bedbad 顺便说一句,我最近回答了一个与 JavaScript here 非常相似的问题,您可能会感兴趣,因为 JS 没有提供开箱即用的功能,解决方法是(大致)重写模式以在正则表达式的每个“点”处包含 $,这相当于将所有可能的 NFA 状态标记为最终状态(如果达到输入的末尾)。
  • 这是您的赏金,先生。我找不到那个,我认为这个问题被低估了。是否也可以在 java 和 C/C++ 中进行操作?您可以链接源代码 boost:regex 在哪里实现?
  • 是的,C 和 C++ 可以使用 PCRE,C++ 可以使用 boost::regex。这是boost partial match doc,这是PCRE2 doc about partial matching
猜你喜欢
  • 2011-06-13
  • 1970-01-01
  • 2017-11-29
  • 2015-04-12
  • 2020-01-02
  • 1970-01-01
  • 2013-07-20
  • 1970-01-01
相关资源
最近更新 更多