从文本文件中可靠地提取 R 函数的名称
Reliably extract names of R functions from a text file
我想找到我在 R 脚本中经常使用的命名函数(忽略“+”、“$”和“[”等运算符)。如何编写优雅可靠的正则表达式来匹配函数名称难倒我了。这里是一个小例子和我到目前为止笨拙的代码。我欢迎更干净、更可靠、更全面的代码。
test1 <- "colnames(x) <- subset(df, max(y))"
test2 <- "sat <- as.factor(gsub('International', 'Int'l', sat))"
test3 <- "score <- ifelse(str_detect(as.character(sat), 'Eval'), 'Importance', 'Rating')"
test <- c(test1, test2, test3)
测试对象包括八个函数(colnames、subset、max、as.factor、gsub、ifelse、str_detect、as.character),前两个两次。匹配它们的迭代一是:
(result <- unlist(strsplit(x = test, split = "\(")))
[1] "colnames" "x) <- subset"
[3] "df, max" "y)"
[5] "sat <- as.factor" "gsub"
[7] "'International', 'Int'l', sat)))" "score <- ifelse"
[9] "str_detect" "as.character"
[11] "sat), 'Eval'), 'Importance', 'Rating')"
然后,一系列手工制作的 gsubs 清理这个特定测试集的结果,但这些手动步骤无疑会达不到其他不那么人为的字符串(我在下面提供了一个)。
(result <- gsub(" <- ", " ", gsub(".*\)", "", gsub(".*,", "", perl = TRUE, result))))
[1] "colnames" " subset" " max" "" "sat as.factor" "gsub" ""
[8] "score ifelse" "str_detect" "as.character"
下面的对象 test4 包括函数 lapply、function、setdiff、unlist、sapply 和 union。它也有缩进,所以有内部间距。我把它包括在内,以便读者可以尝试更困难的情况。
test4 <- "contig2 <- lapply(states, function(state) {
setdiff(unlist(sapply(contig[[state]],
function(x) { contig[[x]]})), union(contig[[state]], state))"
(result <- unlist(strsplit(x = test4, split = "\(")))
(result <- gsub(" <- ", " ", gsub(".*\)", "", gsub(".*,", "", perl = TRUE, result))))
顺便说一句,这个 SO 问题与提取整个函数以创建包有关。
A better way to extract functions from an R script?
第一个答案后编辑
test.R <- c(test1, test2, test3) # I assume this was your first step, to create test.R
save(test.R,file = "test.R") # saved so that getParseData() could read it
library(dplyr)
tmp <- getParseData(parse("test.R", keep.source=TRUE))
tmp %>% filter(token=="SYMBOL") # token variable had only "SYMBOL" and "expr" so I shortened "SYMBOL_FUNCTION_CALL"
line1 col1 line2 col2 id parent token terminal text
1 1 1 1 4 1 3 SYMBOL TRUE RDX2
2 2 1 2 1 6 8 SYMBOL TRUE X
所有文本都出现了问题。我应该怎么做?
正则表达式可能有用,但您可以使用 R 本身来帮助您。我将你的四行代码放入一个文件 test.R
,修复了语法问题 & 运行 以下内容:
library(dplyr)
tmp <- getParseData(parse("test.R", keep.source=TRUE))
tmp %>% filter(token=="SYMBOL_FUNCTION_CALL")
## line1 col1 line2 col2 id parent token terminal text
## 1 1 1 1 8 1 3 SYMBOL_FUNCTION_CALL TRUE colnames
## 2 1 16 1 21 11 13 SYMBOL_FUNCTION_CALL TRUE subset
## 3 1 27 1 29 19 21 SYMBOL_FUNCTION_CALL TRUE max
## 4 2 8 2 16 39 41 SYMBOL_FUNCTION_CALL TRUE as.factor
## 5 2 18 2 21 42 44 SYMBOL_FUNCTION_CALL TRUE gsub
## 6 3 10 3 15 72 74 SYMBOL_FUNCTION_CALL TRUE ifelse
## 7 3 17 3 26 75 77 SYMBOL_FUNCTION_CALL TRUE str_detect
## 8 3 28 3 39 78 80 SYMBOL_FUNCTION_CALL TRUE as.character
## 9 5 12 5 17 119 121 SYMBOL_FUNCTION_CALL TRUE lapply
## 10 6 3 6 9 134 136 SYMBOL_FUNCTION_CALL TRUE setdiff
## 11 6 11 6 16 137 139 SYMBOL_FUNCTION_CALL TRUE unlist
## 12 6 18 6 23 140 142 SYMBOL_FUNCTION_CALL TRUE sapply
## 13 8 11 8 15 191 193 SYMBOL_FUNCTION_CALL TRUE union
如您所见,text
列包含您调用的函数的名称。这应该适用于所有语法正确的 R 文件。
请注意,它不会评估代码,只是对其进行解析。
编辑 test.R
看起来像这样:
colnames(x) <- subset(df, max(y))
sat <- as.factor(gsub('International', 'Int\'l', sat))
score <- ifelse(str_detect(as.character(sat), 'Eval'), 'Importance', 'Rating')
contig2 <- lapply(states, function(state) {
setdiff(unlist(sapply(contig[[state]],
function(x) { contig[[x]]})),
union(contig[[state]], state))})
问题中的代码没有有效的语法,但如果我们更正它:
test1 <- "colnames(x) <- subset(df, max(y))"
test2 <- "sat <- as.factor(gsub('International', 'Intl', sat))"
test3 <- "score <- ifelse(str_detect(as.character(sat), 'Eval'), 'Importance', 'Rating')"
test <- c(test1, test2, test3)
那么我们可以使用codetools包中的findGlobals
:
library(codetools)
f.text <- c("function(){", test, "}")
f <- eval(parse(text = f.text))
funs <- findGlobals(f, merge = FALSE)$functions
给予:
> funs
[1] "{" "<-" "as.character" "as.factor" "colnames<-"
[6] "gsub" "ifelse" "max" "str_detect" "subset"
不清楚您希望排除哪些函数,但如果 F
是包含它们的字符向量,那么 setdiff(funs, F)
将给出除那些之外的所有函数。
另见 Finding out which functions are called within a given function and: Generating a Call Graph in R
我想找到我在 R 脚本中经常使用的命名函数(忽略“+”、“$”和“[”等运算符)。如何编写优雅可靠的正则表达式来匹配函数名称难倒我了。这里是一个小例子和我到目前为止笨拙的代码。我欢迎更干净、更可靠、更全面的代码。
test1 <- "colnames(x) <- subset(df, max(y))"
test2 <- "sat <- as.factor(gsub('International', 'Int'l', sat))"
test3 <- "score <- ifelse(str_detect(as.character(sat), 'Eval'), 'Importance', 'Rating')"
test <- c(test1, test2, test3)
测试对象包括八个函数(colnames、subset、max、as.factor、gsub、ifelse、str_detect、as.character),前两个两次。匹配它们的迭代一是:
(result <- unlist(strsplit(x = test, split = "\(")))
[1] "colnames" "x) <- subset"
[3] "df, max" "y)"
[5] "sat <- as.factor" "gsub"
[7] "'International', 'Int'l', sat)))" "score <- ifelse"
[9] "str_detect" "as.character"
[11] "sat), 'Eval'), 'Importance', 'Rating')"
然后,一系列手工制作的 gsubs 清理这个特定测试集的结果,但这些手动步骤无疑会达不到其他不那么人为的字符串(我在下面提供了一个)。
(result <- gsub(" <- ", " ", gsub(".*\)", "", gsub(".*,", "", perl = TRUE, result))))
[1] "colnames" " subset" " max" "" "sat as.factor" "gsub" ""
[8] "score ifelse" "str_detect" "as.character"
下面的对象 test4 包括函数 lapply、function、setdiff、unlist、sapply 和 union。它也有缩进,所以有内部间距。我把它包括在内,以便读者可以尝试更困难的情况。
test4 <- "contig2 <- lapply(states, function(state) {
setdiff(unlist(sapply(contig[[state]],
function(x) { contig[[x]]})), union(contig[[state]], state))"
(result <- unlist(strsplit(x = test4, split = "\(")))
(result <- gsub(" <- ", " ", gsub(".*\)", "", gsub(".*,", "", perl = TRUE, result))))
顺便说一句,这个 SO 问题与提取整个函数以创建包有关。 A better way to extract functions from an R script?
第一个答案后编辑
test.R <- c(test1, test2, test3) # I assume this was your first step, to create test.R
save(test.R,file = "test.R") # saved so that getParseData() could read it
library(dplyr)
tmp <- getParseData(parse("test.R", keep.source=TRUE))
tmp %>% filter(token=="SYMBOL") # token variable had only "SYMBOL" and "expr" so I shortened "SYMBOL_FUNCTION_CALL"
line1 col1 line2 col2 id parent token terminal text
1 1 1 1 4 1 3 SYMBOL TRUE RDX2
2 2 1 2 1 6 8 SYMBOL TRUE X
所有文本都出现了问题。我应该怎么做?
正则表达式可能有用,但您可以使用 R 本身来帮助您。我将你的四行代码放入一个文件 test.R
,修复了语法问题 & 运行 以下内容:
library(dplyr)
tmp <- getParseData(parse("test.R", keep.source=TRUE))
tmp %>% filter(token=="SYMBOL_FUNCTION_CALL")
## line1 col1 line2 col2 id parent token terminal text
## 1 1 1 1 8 1 3 SYMBOL_FUNCTION_CALL TRUE colnames
## 2 1 16 1 21 11 13 SYMBOL_FUNCTION_CALL TRUE subset
## 3 1 27 1 29 19 21 SYMBOL_FUNCTION_CALL TRUE max
## 4 2 8 2 16 39 41 SYMBOL_FUNCTION_CALL TRUE as.factor
## 5 2 18 2 21 42 44 SYMBOL_FUNCTION_CALL TRUE gsub
## 6 3 10 3 15 72 74 SYMBOL_FUNCTION_CALL TRUE ifelse
## 7 3 17 3 26 75 77 SYMBOL_FUNCTION_CALL TRUE str_detect
## 8 3 28 3 39 78 80 SYMBOL_FUNCTION_CALL TRUE as.character
## 9 5 12 5 17 119 121 SYMBOL_FUNCTION_CALL TRUE lapply
## 10 6 3 6 9 134 136 SYMBOL_FUNCTION_CALL TRUE setdiff
## 11 6 11 6 16 137 139 SYMBOL_FUNCTION_CALL TRUE unlist
## 12 6 18 6 23 140 142 SYMBOL_FUNCTION_CALL TRUE sapply
## 13 8 11 8 15 191 193 SYMBOL_FUNCTION_CALL TRUE union
如您所见,text
列包含您调用的函数的名称。这应该适用于所有语法正确的 R 文件。
请注意,它不会评估代码,只是对其进行解析。
编辑 test.R
看起来像这样:
colnames(x) <- subset(df, max(y))
sat <- as.factor(gsub('International', 'Int\'l', sat))
score <- ifelse(str_detect(as.character(sat), 'Eval'), 'Importance', 'Rating')
contig2 <- lapply(states, function(state) {
setdiff(unlist(sapply(contig[[state]],
function(x) { contig[[x]]})),
union(contig[[state]], state))})
问题中的代码没有有效的语法,但如果我们更正它:
test1 <- "colnames(x) <- subset(df, max(y))"
test2 <- "sat <- as.factor(gsub('International', 'Intl', sat))"
test3 <- "score <- ifelse(str_detect(as.character(sat), 'Eval'), 'Importance', 'Rating')"
test <- c(test1, test2, test3)
那么我们可以使用codetools包中的findGlobals
:
library(codetools)
f.text <- c("function(){", test, "}")
f <- eval(parse(text = f.text))
funs <- findGlobals(f, merge = FALSE)$functions
给予:
> funs
[1] "{" "<-" "as.character" "as.factor" "colnames<-"
[6] "gsub" "ifelse" "max" "str_detect" "subset"
不清楚您希望排除哪些函数,但如果 F
是包含它们的字符向量,那么 setdiff(funs, F)
将给出除那些之外的所有函数。
另见 Finding out which functions are called within a given function and: Generating a Call Graph in R