如何从表达式中提取对象名称

如何解决如何从表达式中提取对象名称

给出一个rlang表达式:

expr1 <- rlang::expr({
  d <- a + b
})

如何检索表达式中引用的对象的名称?

> extractObjects(expr1)
[1] "d" "a" "b"

更好的方法是如何检索对象名称并按“必需”(输入)和“创建”(输出)对它们进行分类?

> extractObjects(expr1)
$created
[1] "d"

$required
[1] "a" "b"

解决方法

基本功能all.vars做到了:

〉all.vars(expr1)
[1] "d" "a" "b"

或者,您可以使用all.names来获取表达式中的所有名称,而不仅仅是不用作调用或运算符的名称:

〉all.names(expr1)
[1] "{"  "<-" "d"  "+"  "a"  "b"

别误导:这个结果是正确的! 所有这些不仅出现在abd

但这可能不是您想要的。

事实上,我假设您想要的对应于抽象语法树(AST)中的叶子标记-换句话说,除了函数调用(以及运算符,它们也是函数调用)之外的所有内容。

表达式的语法树如下所示: 1

   {
   |
   <-
   /\
  d  +
    / \
   a   b

获取此信息意味着要进行AST:

leaf_nodes = function (expr) {
    if(is.call(expr)) {
        unlist(lapply(as.list(expr)[-1L],leaf_nodes))
    } else {
        as.character(expr)
    }
}
〉leaf_nodes(expr1)
[1] "d" "a" "b"

借助AST表示,我们还可以找到输入和输出:

is_assignment = function (expr) {
    is.call(expr) && as.character(expr[[1L]]) %in% c('=','<-','<<-','assign')
}

vars_in_assign = function (expr) {
    if (is.call(expr) && identical(expr[[1L]],quote(`{`))) {
        vars_in_assign(expr[[2L]])
    } else if (is_assignment(expr)) {
        list(created = all.vars(expr[[2L]]),required = all.vars(expr[[3L]]))
    } else {
        stop('Expression is not an assignment')
    }
}
 〉vars_in_assign(expr1)
$created
[1] "d"

$required
[1] "a" "b"

请注意,此函数不能很好地处理复杂的分配(例如d[x] <- a + bf(d) <- a + b之类的东西。


1 lobstr::ast以不同的方式显示语法树,即为

█─`{`
└─█─`<-`
  ├─d
  └─█─`+`
    ├─a
    └─b

…,但是上面的表示在R之外更常规,我发现它更直观。

,

另一种解决方法是extract the abstract symbolic tree explicitly

getAST <- function(ee) purrr::map_if(as.list(ee),is.call,getAST)

str(getAST(expr1))
#  List of 2
#   $ : symbol {
#   $ :List of 3
#    ..$ : symbol <-
#    ..$ : symbol d
#    ..$ :List of 3
#    .. ..$ : symbol +
#    .. ..$ : symbol a
#    .. ..$ : symbol b

然后遍历AST以查找分配:

extractObjects <- function(ast)
{
    ## Ensure that there is at least one node
    if( length(ast) == 0 ) stop("Provide an AST")

    ## If we are working with the assigment
    if( identical(ast[[1]],as.name("<-")) ) {
        ## Separate the LHS and RHS
        list(created = as.character(ast[[2]]),required = sapply(unlist(ast[[3]]),as.character))
    } else {
        ## Otherwise recurse to find all assignments
        rc <- purrr::map(ast[-1],extractObjects)

        ## If there was only one assignment,simplify reporting
        if( length(rc) == 1 ) purrr::flatten(rc)
        else rc
    }
}

extractObjects( getAST(expr1) )
# $created
# [1] "d"
#
# $required
# [1] "+" "a" "b"

然后您可以根据需要filter math operators out

,

这很有趣。我认为从概念上讲,在所有可能的表达式中可能不清楚输入和输出的确切含义。如果您查看可以用lobstr::ast()进行可视化的所谓抽象语法树(AST),则它看起来像这样。

asbtract_tree

因此,在简单的情况下,当您始终拥有LHS <- operations on RHS variables时,如果您迭代AST,则总是在<-运算符之后立即获得LST。如果您分配z <- rlang::expr(d <- a+b),则z的行为类似于列表,例如,您可以执行以下操作:

z <- rlang::expr(d <- a+b)

for (i in 1:length(z)) {
  if (is.symbol(z[[i]])) {
    print(paste("Element",i,"of z:",z[[i]],"is of type",typeof(z[[i]])))
    if (grepl("[[:alnum:]]",z[[i]])) {print(paste("Seems like","is a variable"))}
  } else {
    for (j in 1:length(z[[i]])){
      print(paste("Element",j,paste0("of z[[","]]:"),z[[i]][[j]],typeof(z[[i]][[j]])))
      if (grepl("[[:alnum:]]",z[[i]][[j]])) {print(paste("Seems like","is a variable"))}
    }
  }
}
#> [1] "Element 1 of z: <- is of type symbol"
#> [1] "Element 2 of z: d is of type symbol"
#> [1] "Seems like d is a variable"
#> [1] "Element 1 of z[[3]]: + is of type symbol"
#> [1] "Element 2 of z[[3]]: a is of type symbol"
#> [1] "Seems like a is a variable"
#> [1] "Element 3 of z[[3]]: b is of type symbol"
#> [1] "Seems like b is a variable"

由reprex程序包(v0.3.0)于2020-09-03创建

如您所见,这些树很快就会变得复杂和嵌套。因此,在像您的示例这样的简单情况下,假设变量使用字母数字表示形式,我们可以识别“对象”(如您所说的)是什么以及什么是运算符(与{{1}不匹配) }正则表达式)。如您所见,由于类型始终为[[:alnum:]](下面的symbolz一样,language不能用来区分对象和运算符,所以我们可以确定z[[3]]是否为z[[i]],如果不是,请更深入地研究。)然后,您可能(冒着险)尝试将symbol之后立即出现的对象归类为“输出”,其余的归类为“输入”,但是我对此没有太大的信心,尤其是对于更多复杂的表达式。

简而言之,这都是推测性的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-