通过平衡括号递归拆分 R 中的脚本



有没有办法根据平衡括号将任何 R 脚本拆分为嵌套列表(控制嵌套深度)

function(x){
x_identity=sapply(x, function(i) i*2)
x_squared=sapply(x, function(i){
i^2
}
)
}

将返回一个包含两个子列表的嵌套列表,这两个子列表具有可以完全评估的独立部分。

PCRE(PHP)grep中有一种方法可以做到这一点,但在R中似乎没有等效的方法。

如果你可以使用Perl或PCRE,你可以使用它来开始

((w*)s*(((?:(?>[^(){}]+)|(?1))*))|{((?:(?>[^(){}]+)|(?1))*)})

https://regex101.com/r/F1zkKe/1

就像我说的,你每场比赛只能得到巢。

它的工作方式是制作一个解析外部形式的递归语言函数

在该函数中,您将调用相同的函数来解析每个内部内容
(即。核心)。

伪代码

function parse( core )
{
if ( core =~ /regex/ )
{
// store the outer info
if ( group2 matched )
{
// store group2 function name
// then recurse the function core
parse( group3 );
}
else
if ( group4 matched )
{
// store info about the beginning of a block
// then recurse the block core
parse( group4 );
}
else
if ( groupX matched )
// Content
else
// Error, unwind
return FALSE;
}
return TRUE;
}

当然,还有更多内容,例如内容和错误处理。
既不是函数启动也不是块启动的东西。
或者,由非平衡文本引起的错误。

这需要在正则表达式中进行额外的交替。
但是,如果执行内容和错误,则正则表达式应该比此处使用的更正则表达式更具结构。

重要的是要知道,在核心中,一切都必须得到考虑。
这包括内容和错误。

我可以做到,但这需要一些我没有时间的额外努力。

不过,这应该可以让您开始。

正则表达式解释

(                             # (1 start), Recursion group
( w* )                       # (2), Function name, optional
s* 
(                            # (
(                             # (3 start), Function core
(?:
(?> [^(){}]+ )         # Not anything that starts recursion
|  (?1)                   # or, recurse a core
)*
)                             # (3 end)
)                            # )
|                              # or,
{                            # {
(                             # (4 start), Block core
(?:
(?> [^(){}]+ )         # Not anything that starts recursion
|  (?1)                   # or, recurse a core
)*
)                             # (4 end)
}                            # }
)                             # (1 end)

事实证明,您可以使用基本 R 完成大部分工作。如果你想评估函数,你真的不应该为此使用正则表达式。你将需要编写一个完整的 R 分析器。

请考虑以下事项

R 脚本文件

any syntactical element of the R language
anyfunction = function(args){
access any symbol constructed from any of the outer syntactical elements
in enclosing scope and calculate something
return result
}

编写正则表达式来捕获函数,如果函数访问文件中函数之外的任何内容,则对您没有任何帮助。您还需要匹配它,并在评估函数之前使用 R 对其进行评估。一个家庭编写的R解析器,就是这样。

~/测试。R

这是要解析的代码的示例文件

v = c(1,2,3)
d = 1
increment = function(v, d) {
sapply(v, function(v) v+d)
}
decrement = function(v, d) {
increment(v,d)
v-2*d
increment2 = function(v, d) {
v+d
}
}
closure = function(){
d
}

解析器函数

这是从测试文件解析函数的代码。它将表达式从测试文件解析到环境,以免使命名空间变得模糊,然后计算它们并检查每个表达式的模式。然后,每个函数都放在一个列表中,可以按名称或索引调用。它将正确处理显示的闭包,而正则表达式方法则不会。

它仅使用基 R,因此对于 R 中的任何更新都是稳定的,这些更新不会从基库中删除这些函数,并且将处理最终的语法构造,例如中缀声明的函数。

当您可以使用 R 解析自身时,为什么要编写正则表达式解析器?

env = new.env()
#to not pollute namespace
src.expression = parse(file='~/test.R')
#get expressions
eval(src.expression, envir = env)
#move expressions in to environment
src.modes = sapply(ls(env), function(exp) {
mode(get(exp, envir = env))
}
)
funs.idx = grepl("function", src.modes)
funs.names = names(src.modes[funs.idx])
funs = lapply(funs.names, function(fun) {
get(fun, envir = env)
}
)
names(funs) = funs.names
funs[[2]](v=c(1,2,3), 1) == funs[["increment"]](v=c(1,2,3), 1)
#TRUE TRUE TRUE
funs$closure() == 1
#TRUE

不幸的是,我还没有解决如何递归地做到这一点。必须捕获每个函数中的封闭顶级变量和其他变量,并评估该环境中的嵌套函数以保持标准 R 的行为。虽然,封闭函数通常只是因为被它的封闭函数使用,但我想人们可能有他们的理由。我还没有找到解析嵌套函数并将变量从函数保存到环境的好方法。对于它的价值,我希望这有助于您的目的。

最新更新