【问题标题】:regular expression matching in java without using regexjava中的正则表达式匹配而不使用正则表达式
【发布时间】:2019-07-03 21:57:48
【问题描述】:

我最近收到一个面试问题,我需要在不使用正则表达式匹配的情况下在 Java 中实现正则表达式匹配。

给定一个输入字符串 (s) 和一个模式 (p),实现正则 支持“.”、“+”、“*”和“?”的表达式匹配。


// (pattern, match) --> bool does it match
// operators:
// . --> any char
// + --> 1 or more of prev char
// * --> 0 or more of prev char
// ? --> 0 or 1 of prev char

// (abc+c, abcccc) --> True
// (abcd*, abc) --> True
// (abc?c, abc) --> True
// (abc.*, abcsdfsf) --> True

我想出了下面的代码,它只实现了“。”和 '*' 但无法弄清楚如何实现其他人:

  public static boolean isMatch(String s, String p) {
    if (p.length() == 0) {
      return s.length() == 0;
    }
    if (p.length() > 1 && p.charAt(1) == '*') { // second char is '*'
      if (isMatch(s, p.substring(2))) {
        return true;
      }
      if (s.length() > 0 && (p.charAt(0) == '.' || s.charAt(0) == p.charAt(0))) {
        return isMatch(s.substring(1), p);
      }
      return false;
    } else { // second char is not '*'
      if (s.length() > 0 && (p.charAt(0) == '.' || s.charAt(0) == p.charAt(0))) {
        return isMatch(s.substring(1), p.substring(1));
      }
      return false;
    }
  }

还有什么是解决这个问题的最佳方法?

【问题讨论】:

  • 经常用(a的变体)标记dfa的github.com/samrushing/irken-tdfa实现正则表达式
  • 在长达一个小时的采访中,递归匹配器无疑是预期的解决方案(在讨论了这在生产系统中这将是多么糟糕的想法之后)。您可以通过检查xetc || 重写和匹配xx*x?etc 来使用现有代码轻松实现x+ etc.
  • 如果您希望匹配大多数实现支持的“最左边最长”规则,那么回溯就会成为一个问题。例如,给定"abcdefxwvutsrqx""ab.*x" 是否应该匹配整个字符串?如果是这样,那么".*" 意味着您必须始终扫描整个字符串才能找到最后一个'x' 字符。
  • @JimMischel 如果它只返回一个布尔值,那么您无需担心哪个匹配。这使它更容易。虽然你仍然可以编写灾难性的正则表达式。
  • Relevant:动态规划方案,例如。 stackoverflow.com/questions/49572289/…

标签: java algorithm data-structures


【解决方案1】:

这是未经测试的代码。这个想法是我们跟踪我们在字符串和模式中的位置。这不是尝试扩展到完整的 RE 引擎的好方法(只需考虑添加括号会采取什么措施),但在这种情况下很好:

public static boolean isMatch (String p, String s, int pos_p, int pos_s) {
    if (pos_p == p.length()) {
        // We matched the whole pattern.
        return true;
    }
    else if (pos_s == s.length()) {
        // We reached the end of the string without matching.
        return false;
    }
    else if (pos_p == -1) {
        // Do we match the pattern starting next position?
        if (isMatch(p, s, pos_p + 1, pos_s + 1)) {
            return true;
        }
        else {
            // Try to match the pattern starting later.
            return isMatch(p, s, pos_p, pos_s + 1);
        }
    }
    else {
        char thisCharP = p.charAt(pos_p);
        char nextCharP = pos_p + 1 < p.length() ? p.charAt(pos_p + 1) : 'x';

        // Does this character match at this position?
        boolean thisMatch = (thisCharP == s.charAt(pos_s));
        if (thisCharP == '.') {
            thisMatch = true;
        }

        if (nextCharP == '*') {
            // Try matching no times - we don't need thisMatch to be true!
            if (isMatch(p, s, pos_p + 2, pos_s)) {
                return true;
            }
            else {
                // Try matching 1+ times, now thisMatch is required.
                return thisMatch && isMatch(p, s, pos_p, pos_s + 1);
            }
        }
        else if (nextCharP == '+') {
            if (! thisMatch) {
                // to match 1+, we have to match here.
                return false;
            }
            else if (isMatch(p, s, pos_p + 2, pos_s + 1)) {
                // We matched once.
                return true;
            }
            else {
                // Can we match 2+?
                return isMatch(p, s, pos_p, pos_s + 1);
            }
        }
        else if (thisMatch) {
            // Can we match the rest of the pattern?
            return isMatch(p, s, pos_p + 1, pos_s + 1);
        }
        else {
            // We didn't match here, this is a fail.
            return false;
        }
    }
}

public static boolean isMatch (String p, String s) {
    // Can we match starting anywhere?
    return isMatch(p, s, -1, -1);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-03
    • 1970-01-01
    • 2011-03-30
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多