R:替换字符串中的外来字符

Posted

技术标签:

【中文标题】R:替换字符串中的外来字符【英文标题】:R: Replacing foreign characters in a string 【发布时间】:2013-07-05 05:38:55 【问题描述】:

我正在处理大量数据,主要是包含非英文字符的名称。我的目标是将这些名称与在美国收集的有关它们的一些信息进行匹配。

即,我可能想将名称“Sølvsten”(来自一些名称列表)与“Soelvsten”(存储在某些美国数据库中的名称)匹配。这是我为此编写的一个函数。它显然很笨重而且有些武断,但我想知道是否有一个简单的 R 函数可以将这些外来字符翻译成它们最近的英语邻居。我知道可能没有任何标准的方法来进行这种转换,但我只是好奇是否存在以及是否可以通过 R 函数完成这种转换。

# a function to replace foreign characters
replaceforeignchars <- function(x)

    require(gsubfn);
    x <- gsub("š","s",x)
    x <- gsub("œ","oe",x)
    x <- gsub("ž","z",x)
    x <- gsub("ß","ss",x)
    x <- gsub("þ","y",x)
    x <- gsub("à","a",x)
    x <- gsub("á","a",x)
    x <- gsub("â","a",x)
    x <- gsub("ã","a",x)
    x <- gsub("ä","a",x)
    x <- gsub("å","a",x)
    x <- gsub("æ","ae",x)
    x <- gsub("ç","c",x)
    x <- gsub("è","e",x)
    x <- gsub("é","e",x)
    x <- gsub("ê","e",x)
    x <- gsub("ë","e",x)
    x <- gsub("ì","i",x)
    x <- gsub("í","i",x)
    x <- gsub("î","i",x)
    x <- gsub("ï","i",x)
    x <- gsub("ð","d",x)
    x <- gsub("ñ","n",x)
    x <- gsub("ò","o",x)
    x <- gsub("ó","o",x)
    x <- gsub("ô","o",x)
    x <- gsub("õ","o",x)
    x <- gsub("ö","o",x)
    x <- gsub("ø","oe",x)
    x <- gsub("ù","u",x)
    x <- gsub("ú","u",x)
    x <- gsub("û","u",x)
    x <- gsub("ü","u",x)
    x <- gsub("ý","y",x)
    x <- gsub("ÿ","y",x)
    x <- gsub("ğ","g",x)

    return(x)

注意:我知道存在名称匹配算法,例如 Jaro Winkler 距离匹配,但我宁愿进行精确匹配。

【问题讨论】:

【参考方案1】:

尝试使用chartr R 函数进行一个字符替换(应该很快),然后使用一系列gsub 调用对每个一对二字符替换(大概是会慢一些,但数量不多)。

to.plain <- function(s) 

   # 1 character substitutions
   old1 <- "šžþàáâãäåçèéêëìíîïðñòóôõöùúûüý"
   new1 <- "szyaaaaaaceeeeiiiidnooooouuuuy"
   s1 <- chartr(old1, new1, s)

   # 2 character substitutions
   old2 <- c("œ", "ß", "æ", "ø")
   new2 <- c("oe", "ss", "ae", "oe")
   s2 <- s1
   for(i in seq_along(old2)) s2 <- gsub(old2[i], new2[i], s2, fixed = TRUE)

   s2

根据需要添加到old1new1old2new2

这是一个测试:

> s <- "æxš"
> to.plain(s)
[1] "aexs"

更新:更正了 chartr 中的变量名称。

【讨论】:

谢谢,Gabor(我假设你和r.789695.n4.nabble.com/template/…一样)。我测试了迄今为止发布的所有三个解决方案,这看起来是最快的(尽管我只是观察了执行时间,实际上并没有时间并且它是在笔记本电脑上没有插电所以谁知道什么是驱动效率:-)) 不应该是s1 &lt;- chatr(old1,new1,s)吗? 谢谢。是的。现已修复。 周一,我在这里遇到了编码问题。在 windows 上使用chartr::base 处理单个字符有效,但循环多字符替换连字不适用于包含UTF-8 内容“–”的向量。 (其余的连字都可以正常工作。)我的解决方法 (cough iconv(s, "UTF-8", "latin1") cough) 产生了一个伪像:“œ " 被转换为 "o" (通过 iconv::base),而不是循环中的 "oe"。我猜这是由于 ISO-8859-1 中的遗漏造成的,但我找不到解决方案。有什么想法吗? 使用 stringi::stri_trans_general("œ", "Latin-ASCII") 解决,它做了 iconv() 和 gsub() 做不到的事情。【参考方案2】:

编辑以获得可能更好的结果...

这可能不适用于所有情况,但iconv 可能值得研究。来自?iconv

说明:

 This uses system facilities to convert a character vector between
 encodings: the ‘i’ stands for ‘internationalization’.

例子:

test <- c("Sølvsten", "Günther")
iconv(test, "latin1", "ASCII//TRANSLIT")
#[1] "Solvsten" "Gunther" 

这并没有大大简化,但我认为将数据与代码分开是有道理的。这与这个问题非常相似:

R: replace characters using gsub, how to create a function?

定义从和到:

fromto <- read.table(text="
from to
š s
œ oe
ž z
ß ss
þ y
à a
á a
â a
ã a
ä a
å a
æ ae
ç c
è e
é e
ê e
ë e
ì i
í i
î i
ï i
ð d
ñ n
ò o
ó o
ô o
õ o
ö o
ø oe
ù u
ú u
û u
ü u
ý y
ÿ y
ğ g",header=TRUE)

然后是函数:

replaceforeignchars <- function(dat,fromto) 
  for(i in 1:nrow(fromto) ) 
    dat <- gsub(fromto$from[i],fromto$to[i],dat)
  
  dat


test <- c("Sølvsten", "Günther")
replaceforeignchars(test,fromto)
#[1] "Soelvsten" "Gunther"

【讨论】:

【参考方案3】:

您可以安装uni2ascii C 程序并从 R 中调用它。

uni2ascii <- function(string) 
    cmd <- sprintf("echo %s | uni2ascii -B", string)
    system(cmd, intern = TRUE, ignore.stderr = TRUE)


uni2ascii <- Vectorize(uni2ascii, USE.NAMES = FALSE)

uni2ascii(c("Sølvsten", "ğ", "œ"))
## [1] "Solvsten" "g"        "oe"

【讨论】:

【参考方案4】:

同时,您还可以使用stringi 包中的stri_trans_general()

library(stringi)

x <- c("š", "ž", "ğ", "ß", "þ", "à", "á", "â", "ã", "ä", "å", "æ", 
       "ç", "è", "é", "ê", "ë", "ì", "í", "î", "ï", "ð", "ñ", "ò", 
       "ó", "ô", "õ", "ö", "ø", "œ", "ù", "ú", "û", "ü", "ý", "ÿ")
y <- stri_trans_general(x, "Latin-ASCII")

data.frame(x, y, stringsAsFactors = FALSE)
#>    x  y
#> 1  š  s
#> 2  ž  z
#> 3  ğ  g
#> 4  ß ss
#> 5  þ th
#> 6  à  a
#> 7  á  a
#> 8  â  a
#> 9  ã  a
#> 10 ä  a
#> 11 å  a
#> 12 æ ae
#> 13 ç  c
#> 14 è  e
#> 15 é  e
#> 16 ê  e
#> 17 ë  e
#> 18 ì  i
#> 19 í  i
#> 20 î  i
#> 21 ï  i
#> 22 ð  d
#> 23 ñ  n
#> 24 ò  o
#> 25 ó  o
#> 26 ô  o
#> 27 õ  o
#> 28 ö  o
#> 29 ø  o
#> 30 œ oe
#> 31 ù  u
#> 32 ú  u
#> 33 û  u
#> 34 ü  u
#> 35 ý  y
#> 36 ÿ  y

但是请注意,这会将“ø”转换为“o”。

stri_trans_general("Sølvsten", "Latin-ASCII")
#> [1] "Solvsten"

【讨论】:

【参考方案5】:

扩展thelatemail的答案:原来的replaceforeignchars函数包含一个循环,对于大文本会消耗资源。 这是一个应用函数,它在没有显式循环的情况下完全一样。就目前而言,它适用于单个字符串(例如,不是字符串向量)。

replaceforeignchars <- function(dat,fromto) 
   paste0(apply(matrix(unlist(strsplit(dat,""))),1,FUN=function(x) ifelse(x %in% fromto$from, as.character( fromto[fromto$from==x, 'to']),  x)), collapse="") 
 
test <- c("Sølvsten")
replaceforeignchars(test,fromto)
[1] "Solvsten"

【讨论】:

以上是关于R:替换字符串中的外来字符的主要内容,如果未能解决你的问题,请参考以下文章

替换列表列表中的字符串

在 R 中的一个 gsub() 或 chartr() 语句中替换多个字符串?

替换R中的特殊字符

使用R函数将数据框列中的字符串替换为“”

量词可以用于R中的正则表达式替换吗?

替换数据框R列中的字符