验证语法 - Java - 语法 - 正则表达式

时间:2014-10-30 16:42:12

标签: java regex validation junit

在我开始解释之前,请允许我说这不是“请做我的功课”问题。我会发布我的代码和假设或猜测,但我要求你的帮助,因为我无法解决这个问题,并且发现这个问题不仅有趣,而且是学习非常有用的技能的好机会。 这项练习是我大学家庭作业的一部分,截止日期已经结束。那我为什么要求帮助呢?那么,教师只会提供结果分数,但不会提供关于如何解决练习(这是大学政策)的实际解释,直到明年的下一个时期。我等不了多久,我对如何解决这个问题非常感兴趣。 这是演习演讲的摘要:“有一些孤立的岛屿,他们有自己的语言,但大多数人犯语法错误,所以他们的州长决定要求开发人员发布一些软件,遵守他们的语言规则,纠正语法“。 这些是规则:

  1. 该语言中唯一的字符是从'g'到'p'加上'A','F','D','Q','X'的字符。
  2. 从'g'到'p'的每个字符都是有效的句子。
  3. 如果's'是有效句子,那么'As'也是有效的。
  4. 如果's'和't'是有效句子,那么'Fst','Dst','Qst'和'Xst'也是有效的句子。
  5. 从1到4的规则是确定正确语法的唯一有效规则。
  6. 这对我们很多人来说还不够清楚,所以我们向老师询问了第3点和第4点,并且他解释说 - 这不是一个有效的句子,这只是一个例子 - 他们想说的意思'A'只能跟随1个小写字符,而F,D,Q和X只能跟2个有效的小写字符。

    好吧,对于很多了解正则表达式的人来说,这听起来可能并不那么复杂。实际上我们没有教过正则表达式,只有JUnit - 与它无关?好吧,事实上这个练习实际上是JUnit研讨会的一部分,是的,我和你一样惊讶。那么,为什么我提出正常的表达主题呢?好吧,老师评论说有些学生建议他这个练习可以用正则表达式轻松解决。

    我正在使用NetBeans开发Java,我将发布迄今为止最重要的代码部分:

    Pattern patronUno = Pattern.compile("[ghijklmnop]");
    Pattern patronDos = Pattern.compile("A*[ghijklmnop]|A*");
    Pattern patronTres = Pattern.compile("([FDQX]+([ghijklmnop]{2,2}))");
    Pattern patronCuatro = Pattern.compile("[A][FDQX]");
    
    public String validar(String sentencia){        
        Matcher coincidenciaUno = patronUno.matcher(sentencia);
        Matcher coincidenciaDos = patronDos.matcher(sentencia);
        Matcher coincidenciaTres = patronTres.matcher(sentencia);
        Matcher coincidenciaCuatro = patronCuatro.matcher(sentencia);
    
        if(coincidenciaUno.matches() || coincidenciaDos.matches() || 
                    coincidenciaTres.matches() || coincidenciaCuatro.matches())
            return "YES";
        else
            return "NO";
    }
    

    我的第一个测试用例,经老师预先批准,是:

    示例IN示例OUT

    • Fg NO
    • Xij YES
    • AXij YES
    • Dklm NO

    现在,AXij是有效的,因为A对于sè是有效的,并且Xij也是有效的,所以将Xij添加到A就像向它添加单个一个字符有效句子。 我的朋友们,这是我无法处理的演习的一部分;因为我无法学习 - 如果有办法如何加入两个有效的句子。 你可以帮我解决这部分要求吗?

    根据我发布的代码,我得到了这些结果:

    示例IN示例OUT

    • Fg NO
    • Xij YES
    • AXij NO
    • Dklm NO
    • AAg YES
    • AA YES
    • 是的
    • Amp NO
    • Amng NO

    例如,我无法将AXij视为有效句子。但是我可以成功验证Fx无效,Xij有效,Dklm无效等等。

    提前感谢您的帮助。我发布这个,因为我一直在搜索这个可以解释这个问题的例子,但是其中任何一个对我都很清楚。

3 个答案:

答案 0 :(得分:1)

您所描述的语法非常简单且完全明确,因此如果您不想使用像antlr或JavaCC这样的完整解析器生成器,那么这样的单个递归方法就可以了做这个工作:

public int consumeSentence(String str, int startOffset) {
  char c = str.charAt(startOffset);
  if(c >= 'g' && c <= 'p') {
    return 1;
  } else if(c == 'A') {
    // A<s>
    return 1 + consumeSentence(str, startOffset + 1);
  } else if(c == 'F' || c == 'D' || c == 'Q' || c == 'X') {
    // F<s><t>
    int s1 = consumeSentence(str, startOffset + 1); // s
    int s2 = consumeSentence(str, startOffset + 1 + s1); // t
    return 1 + s1 + s2;
  } else {
    throw new IllegalArgumentException("illegal sentence");
  }
}

这会尝试使用从给定位置开始的字符串中的内容,直到它到达有效句子的末尾,并返回消耗的字符数。要检查字符串s是否是有效句子,请调用consumeSentence(s, 0)并查看返回值是否等于原始字符串的长度。如果它返回任何更少,或者它抛出异常,那么原始字符串不是一个有效的句子。

这是解析器生成器为您构建的逻辑,但这种情况很简单,您可以手动编写它。

答案 1 :(得分:1)

我没有足够的理论知识来证明这是无语境的语法。虽然已知野外的正则表达式风格与上下文敏感的语法匹配,但没有递归(Perl / PCRE)或平衡组(.NET),正则表达式无法解决无上下文中的简单问题,例如括号平衡。

顺便说一下,这就是语法:

S -> 'g' | 'h' | ... | 'p'
S -> 'A'  S
S -> ( 'F' | 'D' | 'Q' | 'X' )  S  S

通常,对于这种情况,最好编写一个解析器。但是,对于玩具问题,您可以使用正则表达式从最低级别替换,并减少叶子A[g-p][FDQX][g-p]{2}g(表示有效句子)的结构。< / p>

public static boolean checkGrammar(String input) {
    String prev = input;
    while (!(input = input.replaceAll("A[g-p]|[FDQX][g-p]{2}", "g")).equals(prev)) {
        prev = input;
    }

    return input.matches("[g-p]");
}

Demo on ideone

答案 2 :(得分:-2)

我不确定我是否了解所有内容,但这似乎与您的示例相符:

^[A]?((A[g-p])|([FDQX][g-p]{2}))$

demo