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

时间:2017-06-13 15:42:33

标签: r regex

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

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

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

将返回一个嵌套列表,其中包含两个具有自包含部分的子列表,可以对其进行全面评估。

在pcre(php)grep中有a way来执行此操作,但在R中似乎没有等效项。

2 个答案:

答案 0 :(得分:0)

如果你可以使用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)

答案 1 :(得分:0)

事实证明你可以使用基数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解析器,即。

〜/ test.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
}

解析器功能

这是从testfile解析函数的代码。它将测试文件中的表达式解析为环境,不会使命名空间变为云,然后对它们进行评估并检查每个表达式的模式。然后将每个函数放在一个列表中,并可以通过名称或索引进行调用。正如所示,它将正确处理闭包,而正则表达法则不会。

它只使用基数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的行为。虽然封闭函数通常只是由于其封闭函数使用,但我猜可以有他们的理由。我还没有找到一种解析嵌套函数并将函数中的变量保存到环境的好方法。对于它的价值,我希望这有助于你的目的。