【问题标题】:Making a string concatenation operator in R在R中制作字符串连接运算符
【发布时间】:2011-06-11 11:03:38
【问题描述】:

我想知道如何在 R 中编写字符串连接运算符,例如 ||在 SAS 中,在 Java/C# 中为 + 或在 Visual Basic 中为 &。

最简单的方法是使用 % 创建一个特殊的运算符,例如

`%+%` <- function(a, b) paste(a, b, sep="")

但这会导致代码中有很多丑陋的%

我注意到+ 是在 Ops 组中定义的,您可以为该组编写 S4 方法,所以也许这样的方法是可行的。但是,我完全没有使用 S4 语言功能的经验。如何修改上述函数以使用 S4?

【问题讨论】:

标签: string r string-concatenation


【解决方案1】:

我会试试这个(相对更干净的 S3 解决方案)

`+` <- function (e1, e2) UseMethod("+")
`+.default` <- function (e1, e2) .Primitive("+")(e1, e2)
`+.character` <- function(e1, e2) 
    if(length(e1) == length(e2)) {
           paste(e1, e2, sep = '')
    } else stop('String Vectors of Different Lengths')

上面的代码会将+改为泛型,并将+.default设置为原来的+,然后将新方法+.character添加到+

【讨论】:

  • 不好意思问,为什么要求两个字符串的长度一样呢?
  • 测试不是字符串具有相同的长度。它测试向量是否具有相同的长度。即,"baz" + "foobar" 可以,"baz" + c("foo", "bar") 不行。
【解决方案2】:

正如其他人所提到的,您不能覆盖密封的 S4 方法“+”。但是,您无需定义新类即可为字符串定义加法函数;这并不理想,因为它迫使您转换字符串类,从而导致更丑陋的代码。相反,可以简单地覆盖“+”函数:

"+" = function(x,y) {
    if(is.character(x) || is.character(y)) {
        return(paste(x , y, sep=""))
    } else {
        .Primitive("+")(x,y)
    }
}

那么以下应该都按预期工作:

1 + 4
1:10 + 4 
"Help" + "Me"

这个解决方案感觉有点像 hack,因为您不再使用正式的方法,而是获得您想要的确切行为的唯一方法。

【讨论】:

  • 我对 S3/4 不太熟悉 - 这到底是什么鬼?似乎工作得很好。
  • 这是一篇老帖子,但我感觉很多人还在看。我会提出一个建议,让这个功能的使用更加受限。将 if 语句中的逻辑运算符更改为 &。如果您只确定其中一个是字符串,我想不出为什么要连接两个对象的充分理由。与您从原始 + 获得的错误消息相比,生成的错误消息不会那么直观。
  • @JoshBradley:我恢复了您的编辑,因为如果连接不同的对象类型没有错误。非字符参数被提升为字符,这与许多其他 R 函数一致。 R 不是强类型语言,Primitive("+") 确实允许混合类型(例如TRUE+1L1L+1.0)。我建议您添加自己的答案,而不是更改接受的答案。
  • 这个答案破坏了其他几个为加号运算符定义自己的方法的包。最突出的是ggplot2。我建议不要使用它
  • 对我来说它不会破坏 ggplot2。 ggplot2 将其“+”定义为“gg”类的 S3 方法。见?ggplot2::%+%``。
【解决方案3】:

如果 R 完全符合 S4,那么以下内容就足够了:

setMethod("+",
          signature(e1 = "character", e2 = "character"),
          function (e1, e2) {
              paste(e1, e2, sep = "")
      })

但这会导致方法被密封的错误:((。希望这会在 R 的功能版本中改变。

你能做的最好的就是定义一个新的类“字符串”,它的行为与“字符”类完全一样:

setClass("string", contains="character")
string <- function(obj) new("string", as.character(obj))

并定义 R 允许的最通用方法:

setMethod("+", signature(e1 = "character", e2 = "ANY"),
          function (e1, e2) string(paste(e1, as.character(e2), sep = "")))

现在试试:

tt <- string(44444)

tt
#An object of class "string"
#[1] "44444"
tt + 3434
#[1] "444443434"
"sfds" + tt
#[1] "sfds44444"
tt +  tt
#[1] "4444444444"
343 + tt
#Error in 343 + tt : non-numeric argument to binary operator
"sdfs" + tt + "dfsd"
#An object of class "string"
#[1] "sdfs44444dfsd"

【讨论】:

    【解决方案4】:

    您也可以为此使用 S3 类:

    String <- function(x) {
      class(x) <- c("String", class(x))
      x
    }
    
    "+.String" <- function(x,...) {
      x <- paste(x, paste(..., sep="", collapse=""), sep="", collapse="")
      String(x)
    }
    
    
    print.String <- function(x, ...) cat(x)
    
    x <- "The quick brown "
    y <- "fox jumped over "
    z <- "the lazy dog"
    
    String(x) + y + z
    

    【讨论】:

      【解决方案5】:

      你已经给了自己正确的答案——R 中的一切都是函数,你不能定义新的运算符。所以%+% 是最好的。

      【讨论】:

      • 但是您可以重新定义现有运算符的行为。但在这种情况下不是,因为“+”方法是为签名 c(“character”,“character”) 密封的。
      猜你喜欢
      • 2014-02-27
      • 2016-07-19
      • 2015-08-28
      • 2010-09-08
      • 1970-01-01
      • 2020-11-07
      • 1970-01-01
      • 2012-05-07
      • 2015-01-11
      相关资源
      最近更新 更多