【问题标题】:R remove redundant parentheses from formula string or expressionR从公式字符串或表达式中删除多余的括号
【发布时间】:2013-06-21 17:09:56
【问题描述】:

我有很多类似这样的公式字符串:

str <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "

有很多括号是不需要的,(A*J - J*G)/Z 就足够了。 R中是否有可以解决这个问题的函数或包?

我尝试了 R 表达式和 as.formula 的函数,但没有找到我需要的。

【问题讨论】:

  • 不确定,但请尝试以下操作:gsub("\\(([[:alnum:]]+)\\)", "\\1", gsub(" ", "", str))。逻辑: 1) 删除所有spaces,两个查找所有(),如果有连续的characters+numerals,则删除paranthesis,否则什么都不做。如果它测试良好,您可以将其写下来作为答案并标记。
  • 这至少删除了 A 和 J 周围的括号:"((A*J)-(J*G))/Z",谢谢!
  • 确定我忽略了一些东西。现在明白了。
  • 在一般情况下,我对此表示怀疑。您可以使用 @Arun 的方法来查找冗余的“配对”集合,例如 ((foo+(bar))) 但由于您的示例中的 J 很容易成为某个表达式,如果您不将其从 G ,您如何确定哪些单组括号可以安全删除?
  • 出于好奇(因为它可能会帮助您获得更好的答案),为什么?我不认为 R 的函数使用公式,如 lmmodel.matrix,关心是否有额外的括号。

标签: string r formula parentheses


【解决方案1】:

我们可以使用 R 解析器来完成这项工作。诀窍是 R 知道什么时候需要括号基于解析树,所以我们可以简单地从树中删除它们:

看这个:

simplify <- function(e)
{
    if( mode(e) %in% c("name","numeric") ) return(e)

    op <- as.character(e[[1]])

    if( op == "(" ) return(simplify(e[[2]]))

    if( op %in% c("+","-","*","/","^") ) return(call(op, simplify(e[[2]]), simplify(e[[3]])))
}

simplifytext <- function(s) deparse(simplify(parse(text=s)[[1]]))

输入:

str <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "
str2 <- gsub("-", "/", gsub("*", "+", str, fixed=TRUE))

结果:

> str2
[1] "( ((  A  ) +  J ) / ((  J  ) +  G  ) ) /  Z "

> simplifytext(str)
[1] "(A * J - J * G)/Z"
> simplifytext(str2)
[1] "(A + J)/(J + G)/Z"

【讨论】:

  • 谢谢!该解决方案适用于我的所有数据!如果可以的话,我会接受这两种解决方案,但 G. Grothendieck 早了 15 分钟......
  • @user1981275,够公平的! :-) 如果您有兴趣,请查看以下答案,并附上一些可以在 R 中象征性地进行进一步简化的示例:stackoverflow.com/questions/15725930/…
【解决方案2】:

这里有几种方法:

R 解析

rmParen <- function(e) {
    if (length(e) > 1) {
        if (identical(e[[1]], as.symbol("("))) e <- e[[2]]
        if (length(e) > 1) for (i in 1:length(e)) e[[i]] <- Recall(e[[i]])
    }
    e
}

s <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "
rmParen(parse(text = s)[[1]])

最后一行返回:

(A * J - J * G)/Z

这在我尝试过的所有情况下都有效,但您可能想进一步测试一下。

如果您想要一个字符串作为返回值,请使用deparse,如deparse(rmParen(parse(text = s)[[1]]))。请注意,deparse 有一个 width.cutoff 参数,默认设置为 60,但如果实际表达式超过该长度,则可以设置为更大。

里亚卡斯

library(Ryacas)

s <- "( ((  A  ) *  J ) - ((  J  ) *  G  ) ) /  Z "
Simplify(s)

最后一行返回:

expression((A - G) * J/Z)

请注意,它实际上是调用计算的 print 方法,因此如果您想保存它,请尝试 yacas(Simplify(s))$textas.character(yacas(Simplify(s)))

添加:Ryacas 解决方案。

【讨论】:

  • 谢谢!第一个解决方案效果很好,我制作了一个适用于我的数据的包装器:rmp &lt;- function(s){paste(deparse(rmParen(parse(text = s)[[1]])), collapse="")}。我还没有让 Ryacas 解决方案发挥作用,但第一个解决方案正是我想要的!
  • 如果您在让 Ryacas 工作时遇到问题,请参阅主页上的故障排除部分:ryacas.googlecode.com
  • 第一种方案有bug;它在某些情况下删除了太多括号。例如,尝试使用s &lt;- "((a + b) * (c + d))/2" 我猜这是因为它不了解 R 的运算符优先规则。不过,Ryacas 解决方案应该对此免疫。
  • @Hong, rmParens(parse(text = "((a + b) * (c + d))/2")[[1]]) 返回(a + b) * (c + d)/2 这是正确的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多