簡體   English   中英

驗證語法-Java-語法-正則表達式

[英]Verifying syntax - Java - Grammar - Regular expressions

在開始解釋之前,請允許我聲明這不是“請做我的家庭作業”問題。 我將發布我的代碼和假設或猜測,但是由於無法解決此問題,我正在尋求您的幫助,不僅發現此問題很有趣,而且還是學習非常有用的技能的好機會。 該練習是我大學一項家庭作業的一部分,並且截止日期已經結束。 那我為什么要尋求幫助? 好吧,老師只會提供成績分數,而不會提供有關如何解決練習的實際解釋(這是大學的政策),直到下一年,即明年。 我等不了那么久,我對如何解決這個問題很感興趣。 這是演說摘要:“在某些孤立的島上,他們擁有自己的語言,但是大多數人會犯語法錯誤,因此他們的州長決定要求開發人員發布某些軟件,並遵守他們的語言規則,更正語法”。 這些是規則:

  1. 該語言中唯一的字符是從'g'到'p'加上'A','F','D','Q','X'的字符。
  2. 從“ g”到“ p”的每個字符都是有效的句子。
  3. 如果“ s”是有效的句子,那么“ As”也有效。
  4. 如果“ s”和“ t”是有效語句,則“ Fst”,“ Dst”,“ Qst”和“ Xst”也是有效語句。
  5. 從1到4的規則是確定正確語法的唯一有效規則。

這對我們許多人來說還不夠清楚,因此我們向老師詢問了第3點和第4點,他解釋說-因為's'實際上不是有效的句子,這只是一個例子-他們想表示'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";
}

經老師預先批准,我的第一個測試用例是:

示例輸入示例輸出

  • Fg NO
  • 西耶是
  • AXij是
  • Dklm NO

現在,AXij是有效的,因為A對每個人都有效,並且Xij也有效,因此將Xij添加到A就像向其添加一個單字符有效語句。 而我的朋友們,是我無法處理的部分練習; 我無法學習-如果有辦法-如何連接兩個有效句子。 您可以幫我解決那部分需求嗎?

通過發布的代碼,我得到了以下結果:

示例輸入示例輸出

  • Fg NO
  • 西耶是
  • 軸號
  • Dklm NO
  • AAg是
  • AA是的
  • 是的
  • 放大器編號
  • 編號

例如,我無法將AXij視為有效語句。 但是我可以成功地驗證Fx為無效,Xij為有效,Dklm為無效等。

在此先感謝您的幫助。 我發布此郵件的原因是,我一直在通過本網站搜索可以解釋此問題的示例,但其中任何一個對我來說都很清楚。

您所描述的語法非常簡單且完全明確,因此,如果您不想深入使用像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)然后查看返回值是否等於原始字符串的長度。 如果返回的值更少,或者引發異常,則原始字符串不是有效的句子。

解析器生成器會為您構建這種邏輯,但是這種情況非常簡單,您可以手動對其進行編碼。

我沒有足夠的理論知識來證明這是上下文無關的語法。 盡管眾所周知的正則表達式風格可以匹配上下文相關的語法,但沒有遞歸(Perl / PCRE)或平衡組(.NET),但正則表達式無法解決上下文無關的簡單問題,例如括號平衡。

順便說一下,這是語法:

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

通常,在這種情況下,最好編寫一個解析器。 但是,對於玩具問題,可以使用正則表達式從最低級別開始進行替換,並將葉子A[gp][FDQX][gp]{2}的結構減小為g (表示有效的句子)。

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]");
}

ideone上的演示

不確定我是否了解所有內容,但這似乎與您的示例相符:

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

演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM