2014-06-30 31 views
0

請考慮read.table身體爲文本文件,用下面的代碼創建:正則表達式查找功能的函數體調用

sink("readTable.txt") 
body(read.table) 
sink() 

使用正則表達式,我想找到所有的函數調用的形式foo(a, b, c)(但有任何數量的參數)在"readTable.txt"。也就是說,我希望結果包含read.table正文中所有被調用函數的名稱。這包括
foo(a, bar(b, c))的嵌套功能。保留字(return,forfor等)和使用反標記的功能('=='()'+'()等)可以包含在內,因爲我可以稍後刪除它們。

所以在一般情況下,我在尋找的模式text(text (那麼可能的嵌套功能,如text1(text2(,但跳過文本如果它的參數,而不是功能。這是迄今爲止我所在的地方。這很接近,但並不完全。

x <- readLines("readTable.txt") 
regx <- "^(([[:print:]]*)\\(+.*\\))" 
mat <- regexpr(regx, x) 
lines <- regmatches(x, mat) 
fns <- gsub(".*(|(=|(<-)))", "", lines) 
head(fns, 10) 
# [1] "default.stringsAsFactors()" "!missing(text))" 
# [3] "\"UTF-8\")" "on.exit(close(file))" "(is.character(file))" 
# [6] "(nzchar(fileEncoding))" "fileEncoding)" "\"rt\")" 
# [9] "on.exit(close(file))" "\"connection\"))" 

例如,在上述[9],來電是有的,但我不希望在結果file。理想情況下,它將是on.exit(close(

我該如何去改善這個正則表達式?

+2

如果它不一定是一個正則表達式的解決方案,請考慮'codetools :: walkCode'。 http://stackoverflow.com/questions/11872879/finding-out-which-functions-are-called-within-a-given-function/11878961#11878961 – GSee

+0

@GSee,現在很有趣,也很有用。對於這個問題,我想堅持使用正則表達式方法。這是我爲本科生開設的一個問題,我只是想改善我之前的回答。儘管發佈該功能作爲答案,但它非常酷。 –

+0

您可以提供您搜索的匹配樣本輸入數據嗎? – hwnd

回答

6

如果你曾經嘗試過用你知道它是怎樣一場噩夢正則表達式解析HTML。使用一些HTML解析器並以這種方式提取信息總是更好。我對R代碼有同樣的感受。 R的優點在於它的功能強大,您可以通過代碼檢查任何功能。

喜歡的東西

call.ignore <-c("[[", "[", "&","&&","|","||","==","!=", 
    "-","+", "*","/", "!", ">","<", ":") 

find.funcs <- function(f, descend=FALSE) { 
    if(is.function(f)) { 
     return(find.funcs(body(f), descend=descend)) 
    } else if (is(f, "name") | is.atomic(f)) { 
     return(character(0)) 
    } 
    v <- list() 
    if (is(f, "call") && !(deparse(f[[1]]) %in% call.ignore)) { 
     v[[1]] <- deparse(f) 
     if(!descend) return(v[[1]]) 
    } 
    v <- append(v, lapply(as.list(f), find.funcs, descend=descend)) 
    unname(do.call(c, v)) 
} 

可以工作。在這裏,我們遍歷函數中的每個對象,尋找call,忽略那些你不關心的對象。你會在功能上運行它像

find.funcs(read.table) 

# [1] "default.stringsAsFactors()"     
# [2] "missing(file)"        
# [3] "missing(text)"        
# [4] "textConnection(text, encoding = \"UTF-8\")" 
# [5] "on.exit(close(file))"      
# [6] "is.character(file)" 
# ... 

你可以,如果你想在調用其他功能的功能看descend=參數設置爲TRUE

我確定有很多軟件包可以使這更容易,但我只是想展示它的真實性。

3

遞歸正則表達式在Perl模式

在一般情況下,我相信你是知道的,設法滿足這種結構的危害:如果你的文件中包含類似if()的東西,你不想要匹配?

話雖這麼說,我相信這個遞歸正則表達式符合要求,我理解他們

[a-z]+(\((?:`[()]|[^()]|(?1))*\)) 

demo

我不能完全達到標準的R語法,但這樣的事情應該工作,你可以調整函數名和參數,以滿足您的需求:

grepl("[a-z]+(\\((?:`[()]|[^()]|(?1))*\\))", subject, perl=TRUE); 

說明

  • [a-z]+與開括號前的字母匹配
  • (開始組1
  • \(匹配開括號
  • (?:開始一個將被重複的非捕獲組。捕獲小組賽幾種可能性:
  • BACKTICK[()]匹配反引號+ ()(對不起,不知道如何使反引號出現在此編輯器
  • |[^()]或匹配一個字符不是一個括號
  • |(?1)或匹配
  • )*緊密的,非捕獲組由組1個括號(遞歸)中定義的圖案,重複零次或多次
  • \)閉括號匹配
  • )結束第1組