[英]Verifying syntax - Java - Grammar - Regular expressions
在開始解釋之前,請允許我聲明這不是“請做我的家庭作業”問題。 我將發布我的代碼和假設或猜測,但是由於無法解決此問題,我正在尋求您的幫助,不僅發現此問題很有趣,而且還是學習非常有用的技能的好機會。 該練習是我大學一項家庭作業的一部分,並且截止日期已經結束。 那我為什么要尋求幫助? 好吧,老師只會提供成績分數,而不會提供有關如何解決練習的實際解釋(這是大學的政策),直到下一年,即明年。 我等不了那么久,我對如何解決這個問題很感興趣。 這是演說摘要:“在某些孤立的島上,他們擁有自己的語言,但是大多數人會犯語法錯誤,因此他們的州長決定要求開發人員發布某些軟件,並遵守他們的語言規則,更正語法”。 這些是規則:
這對我們許多人來說還不夠清楚,因此我們向老師詢問了第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";
}
經老師預先批准,我的第一個測試用例是:
示例輸入示例輸出
現在,AXij是有效的,因為A對每個人都有效,並且Xij也有效,因此將Xij添加到A就像向其添加一個單字符有效語句。 而我的朋友們,是我無法處理的部分練習; 我無法學習-如果有辦法-如何連接兩個有效句子。 您可以幫我解決那部分需求嗎?
通過發布的代碼,我得到了以下結果:
示例輸入示例輸出
例如,我無法將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]");
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.