用gsub替换带有重音符号的多个字母

73
当然,我可以像这样替换特定的参数:
    mydata=c("á","é","ó")
    mydata=gsub("á","a",mydata)
    mydata=gsub("é","e",mydata)
    mydata=gsub("ó","o",mydata)
    mydata

但肯定有更简单的方法可以在一行内完成所有操作,对吗? 我觉得gsub函数的帮助文档并不是很全面。


1
如果你想要用相同的东西替换不同的模式,可以使用 lapply 完成,但是因为你想要用不同的字符串替换不同的模式,我认为你仍然必须指定这些方式之一... - juba
2
你可以尝试使用 chartr 来完成这个任务。 - Andrie
31
gsubfn包中的gsubfn函数是gsub函数的一般化,可以在一次调用中完成替换操作:gsubfn(".", list("á"="a", "é"="e", "ó"="o"), c("á","é","ó")) - G. Grothendieck
@G.Grothendieck。太好了,而且适用于所有类型的字符。非常有价值的评论。谢谢! - Joschi
1
对于寻找此问题更一般解决方案的人,以下是更有帮助的答案:https://dev59.com/J2sz5IYBdhLWcg3w47-m#7664655 - Ben
@G.Grothendieck,你能否将这个也发布为答案,这样未来的访客就可以看到它了吗? - Sam Firke
11个回答

84
使用字符转换函数
chartr("áéó", "aeo", mydata)

这对于字符很有用...但是这也适用于特殊字符,例如下划线、点等吗?虽然不在问题范围内,但了解这种情况的信息也很有趣... - Joschi
@Joschi,你的问题没有提到它们。我认为你需要转义它们,因为它们是特殊字符... - Arun

33

一个有趣的问题!我认为最简单的选择是设计一个特殊的函数,类似于“multi” gsub():

mgsub <- function(pattern, replacement, x, ...) {
  if (length(pattern)!=length(replacement)) {
    stop("pattern and replacement do not have the same length.")
  }
  result <- x
  for (i in 1:length(pattern)) {
    result <- gsub(pattern[i], replacement[i], result, ...)
  }
  result
}

这给了我:

> mydata <- c("á","é","ó")
> mgsub(c("á","é","ó"), c("a","e","o"), mydata)
[1] "a" "e" "o"

29
也许这会有用:
iconv('áéóÁÉÓçã', to="ASCII//TRANSLIT")
[1] "aeoAEOca"

在我使用的最新版本的R中,调用iconv('áéóÁÉÓçã', to="ASCII//TRANSLIT")返回"'a'e'o'A'E'Oc~a"。这种行为是随着R版本的变化而改变的,还是与我的默认编码有关? - aaron
@Aaron:不知道是否是编码问题。我在R 3.3.1上尝试过,结果符合预期。 - Rcoster

20
您可以使用stringi软件包来替换这些字符。
> stri_trans_general(c("á","é","ó"), "latin-ascii")

[1] "a" "e" "o"

11

这与@kith非常相似,但以函数形式存在,并涵盖了最常见的变音符情况:

removeDiscritics <- function(string) {
  chartr(
     "ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿ"
    ,"SZszYAAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyy"
    , string
  )
}


removeDiscritics("test áéíóú")

"测试 aeiou"


7

以上某些实现(例如Theodore Lytras的实现)存在问题,即如果模式是多个字符,则可能会在一个模式是另一个子字符串的情况下发生冲突。解决此问题的方法是创建对象的副本,并在该副本中执行模式替换。这在我的包bayesbio中实现,可在CRAN上获得。

mgsub <- function(pattern, replacement, x, ...) {
  n = length(pattern)
  if (n != length(replacement)) {
    stop("pattern and replacement do not have the same length.")
  }
  result = x
  for (i in 1:n) {
    result[grep(pattern[i], x, ...)] = replacement[i]
  }
  return(result)
}

这是一个测试案例:

  asdf = c(4, 0, 1, 1, 3, 0, 2, 0, 1, 1)

  res = mgsub(c("0", "1", "2"), c("10", "11", "12"), asdf)

7

使用Reduce的另一种mgsub实现方式

mystring = 'This is good'
myrepl = list(c('o', 'a'), c('i', 'n'))

mgsub2 <- function(myrepl, mystring){
  gsub2 <- function(l, x){
   do.call('gsub', list(x = x, pattern = l[1], replacement = l[2]))
  }
  Reduce(gsub2, myrepl, init = mystring, right = T) 
}

3

虽不太优雅,但它能发挥作用并实现你的需求

> diag(sapply(1:length(mydata), function(i, x, y) {
+   gsub(x[i],y[i], x=x)
+ }, x=mydata, y=c('a', 'b', 'c')))
[1] "a" "b" "c"

3

和Justin的答案相关:

> m <- c("á"="a", "é"="e", "ó"="o")
> m[mydata]
  á   é   ó 
"a" "e" "o" 

如果您希望的话,您可以使用 names(*) <- NULL 来删除名称。


1
你可以使用match函数。这里的match(x, y)返回x中匹配到y的元素的索引。然后,您可以使用返回的索引来对另一个向量(比如z)进行子集操作,该向量包含与y适当匹配的x值的替换。在你的情况下:
mydata <- c("á","é","ó")
desired <- c('a', 'e', 'o')

desired[match(mydata, mydata)]

在一个更简单的例子中,考虑下面的情况,我试图将a替换为'alpha''b'替换为'beta'等等。
x <- c('a', 'a', 'b', 'c', 'b', 'c', 'e', 'e', 'd')

y <- c('a', 'b', 'c', 'd', 'e')
z <- c('alpha', 'beta', 'gamma', 'delta', 'epsilon')

z[match(x, y)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接