2015-10-25 60 views
2

我試圖從代碼語句和「if」條件中提取變量。我有一個正則表達式,但mymatcher.find()不返回任何匹配的值。 我不知道什麼是錯的。使用正則表達式從代碼語句中提取變量

這裏是我的代碼:

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class test { 
    public static void main(String[] args) { 
     String test="x=y+z/n-10+my5th_integer+201"; 
     Pattern mypattern = Pattern.compile("^[a-zA-Z_$][a-zA-Z_$0-9]*$"); 
     Matcher mymatcher = mypattern.matcher(test);  
     while (mymatcher.find()) { 
      String find = mymatcher.group(1) ; 
      System.out.println("variable:" + find); 
     } 
    } 
} 
+0

字符串中的第二個字符是'=',但是你的正則表達式不允許任何'='。你的正則表達式也沒有任何組。 –

+0

我不知道'='會如何影響正則表達式,因爲我在正則表達式中是全新的。 我用.start()和。end(),但也不起作用,在這個例子中,我期望x,y,z,n和my5th_integer是變量的結果,因爲它們是變量 – user3299062

回答

2

您需要刪除^$錨,在開始和結束字符串repectively斷言位置,並使用mymatcher.group(0),而不是mymatcher.group(1)因爲你沒有任何捕獲組您正則表達式:

String test="x=y+z/n-10+my5th_integer+201"; 
Pattern mypattern = Pattern.compile("[a-zA-Z_$][a-zA-Z_$0-9]*"); 
Matcher mymatcher = mypattern.matcher(test);  
while (mymatcher.find()) { 
    String find = mymatcher.group(0) ; 
    System.out.println("variable:" + find); 
} 

IDEONE demo,結果是:

variable:x 
variable:y 
variable:z 
variable:n 
variable:my5th_integer 
+1

就像一個魅力,謝謝soooo太多 – user3299062

2

通常只用一個正則表達式處理源代碼就會失敗。

如果你想要做的就是挑選出標識符(我們討論變量下文)你有機會用正則表達式(畢竟,這是詞法分析器是如何構建的)。

但是,您可能需要比您擁有的更復雜的版本,即使是其他作者所建議的更正也是如此。

第一個問題是,如果您允許任意語句,它們通常具有看起來像標識符的關鍵字。在你的具體例子中,「if」看起來像一個標識符。所以你的匹配器必須識別類似於標識符的子字符串,並將已知的關鍵字減去,否則正則表達式本身必須表達標識符具有基本形狀但不能看起來像特定關鍵字列表的想法。 (後者被稱爲減色正則表達式,並且在大多數正則表達式引擎都沒有發現它看起來是這樣的:。

[a-zA-Z_$][a-zA-Z_$0-9]* - (if | else | class | ...) 

我們的DMS詞法分析器發電機[查看我的履歷]有消減的正則表達式,因爲這是在語言極其有用-lexing)。

如果「關鍵字」並不總是關鍵字,即 它們可能只是在特定上下文中的關鍵字,這會變得更加複雜。 Java的「關鍵字」枚舉就是:如果你在類型上下文中使用它,它是一個關鍵字;否則它是一個標識符; C#是類似的。現在知道 如果聲明的標識符是關鍵字的唯一方法是實際解析代碼(這是如何檢測控制其關鍵字的上下文)。

接下來,Java中的標識符允許使用各種Unicode字符(拉丁文1,俄文,中文,...)一個正則表達式可以識別出所有字符,這比您簡單的「AZ」風格大得多提出。

對於Java,您需要針對包含似乎是變量名稱的字符串文字進行辯護。考慮(看起來很有趣的,但有效的)聲明:

a = "x=y+z/n-10+my5th_integer+201"; 

這裏有只一個標識符。

/* Tricky: 
    a = "x=y+z/n-10+my5th_integer+201"; 
*/ 

對於Java,你需要擔心的Unicode轉義,太:與包含看起來像報表內容的評論 出現類似的問題。考慮這種有效的Java語句:

\u0061 = \u0062; // means "a=b;" 

或令人討厭:

a\u006bc = 1; // means "akc=1;" not "abc=1;"! 

推這個,沒有Unicode字符解碼,你可能甚至不 通知的字符串。以下是上述的變體:

a = \u0042x=y+z/n-10+my5th_integer+201"; 

要正確提取標識符,你需要建立(或使用)一個完整的Java詞法分析器的等效,而不僅僅是一個簡單的正則表達式匹配。

如果你大部分時間都不在乎,你可以試試你的正則表達式。通常,正則表達式應用於源代碼分析的結果很糟糕,部分原因是由於上述問題(例如過度簡化)。

你很幸運,因爲你正在嘗試爲Java做。如果你必須爲C#做一個非常相似的語言,你必須處理插入的字符串,它允許表達式在字符串中。表達式本身可以包含字符串......它的烏龜一直向下。考慮C#(版本6)聲明:

a = $"x+{y*$"z=${c /* p=q */}"[2]}*q" + b; 

這包含標識符a,b,c和y。其他每個「標識符」實際上只是一個字符串或註釋字符。 PHP有類似的內插字符串。

要從中提取標識符,您需要一些理解字符串元素嵌套的內容。詞庫通常不會遞歸(我們的DMS詞法分析器處理這個,正是出於這個原因),所以爲了正確處理這個問題,你通常需要一個解析器,或者至少是一些跟蹤嵌套的東西。

你有另一個問題:你想提取只是變量名稱? 如果標識符表示方法,類型,類或包,該怎麼辦? 如果沒有完整的解析器和完整的Java名稱和類型解析,就無法解決這個問題,並且您必須在找到該語句的上下文中執行此操作。您會驚訝地發現需要多少代碼才能做到這一點。因此,如果你的目標是簡單的,你不在乎它是否處理了這些複雜問題,那麼你可以通過一個簡單的正則表達式來挑選看起來像標識符的事物 。

如果你想要它(例如,在一些生產代碼中使用這個),單個正則表達式將是完全的災難。你會花一生的時間向用戶解釋他們無法打字的內容,而且這種方式永遠不會起作用。

總結:因爲所有的併發症,通常只用一個正則表達式處理源代碼就會失敗。人們不斷重新學習這一課。這是詞法分析生成器廣泛用於語言處理工具的關鍵原因之一。

+0

多麼好的解釋,你絕對是對的,但爲了我的目的,我只需要上面的正則表達式,因爲我正在對僞代碼進行數據流分析,我只需要提取變量名稱,我只關心的唯一關鍵字就是:if ,否則,elseif,true和false,所以我可以輕鬆地處理它們。 – user3299062

+0

那麼,你*說* Java: - }如果你想做數據流分析(不清楚如何在psuedocode中有用),你*仍然*需要解析和做名稱解析。看到我的文章「解析後的生活」(谷歌或通過生物)。從根本上說,我們回到了「你打算製造一個玩具(用於教育目的)」,這意味着只要你明白你在作弊,或者「你想建立一個嚴肅的工具」,任何作弊都可以,此時你會需要建立/使用嚴重的基礎設施。 –

+0

好吧,我想我需要解釋整個研究項目,以便它可以清楚地告訴你。就像我之前提到的那樣,它是用java實現的,並且涉及在某個點傳遞一個僞代碼作爲字符串,我向你保證,我發佈的內容正是我所需要的。 – user3299062