【问题标题】:R: Converting "special" letters into UTF-8?R:将“特殊”字母转换为 UTF-8?
【发布时间】:2018-05-24 03:37:58
【问题描述】:

我遇到了匹配表的问题,其中一个数据帧包含特殊字符而另一个不包含。示例:Do-安娜县 vs. 多纳安娜县

这是一个可以重现输出的脚本:

library(tidyverse)
library(acs)
tbl_df(acs::fips.place)    # contains "Do\xf1a Ana County"
tbl_df(tigris::fips_codes) # contains "Dona Ana County"

示例:

tbl_df(tigris::fips_codes) %>% filter(county == "Dona Ana County")

返回:

# A tibble: 1 x 5
  state state_code state_name county_code          county
  <chr>      <chr>      <chr>       <chr>           <chr>
1    NM         35 New Mexico         013 Dona Ana County

很遗憾,以下查询没有返回任何内容:

tbl_df(acs::fips.place) %>% filter(COUNTY == "Do\xf1a Ana County")
tbl_df(acs::fips.place) %>% filter(COUNTY == "Doña Ana County")
tbl_df(acs::fips.place) %>% filter(COUNTY == "Dona Ana County")

# A tibble: 0 x 7
# ... with 7 variables: STATE <chr>, STATEFP <int>, PLACEFP <int>, PLACENAME <chr>, TYPE <chr>, FUNCSTAT <chr>, COUNTY <chr>

但是,在 R Studio 中打开数据框时,会显示:

问题一:为什么第二个查询没有返回,但数据库中出现了“Do\xf1a Ana County”?

问题 2: 如何将所有“特殊”字符(例如 ñ)转换为 n 或类似字符(UTF-8?) ?是否有为此的库或 sn-p,或标题中的定义,而不是为每个字符定义规则?无论如何,我都必须这样做才能匹配两个表中的某些列。

谢谢!

【问题讨论】:

  • 问题是acs::fips.place 被严重破坏。 \\xf1a 没有任何意义; \xf1a 确实(在latin1 编码中),但是从一种转换到另一种很困难。如果我是你,我会向 acs 软件包维护者报告错误。

标签: r utf-8 character string-formatting


【解决方案1】:

使用

 tbl_df(acs::fips.place) %>% filter(COUNTY == "Do\\xf1a Ana County")

在您的数据集中,您真正拥有的是Do\\xf1a,您可以在 R 控制台中使用例如:

acs::fips.place[grep("Ana",f$COUNTY),]

要使用的函数是iconv(x, from = "", to = "")enc2utf8enc2native 不接受“来自”参数。 在大多数情况下,要构建一个包,您需要将数据转换为 UTF-8(构建包时我必须对所有法语字符串进行转码)。这里我认为是latin1,但是\已经被转义了。

x<-"Do\\xf1a Ana County"
Encoding(x)<-"latin1"
charToRaw(x)
#  [1] 44 6f f1 61 20 41 6e 61 20 43 6f 75 6e 74 79
xx<-iconv(x, "latin1", "UTF-8")
charToRaw(xx)
# [1] 44 6f c3 b1 61 20 41 6e 61 20 43 6f 75 6e 74 79

最后,如果您需要清理输出以获得可比较的字符串,您可以使用此函数(直接来自我自己的编码地狱)。

to.plain <- function(s) {   
   #old1 <- iconv("èéêëù","UTF8") #use this if your console is in LATIN1
   #new1 <- iconv("eeeeu","UTF8") #use this if your console is in LATIN1
  old1 <- "èéêëù"
  new1 <- "eeeeu"
  s1 <- chartr(old1, new1, s)      
}

【讨论】:

  • 一旦我知道没有更好的方法,我将标记为已解决。我有点惊讶它需要这么多步骤来解决问题。
  • 一些关于编码rstudioencoding hellEncodings in R 2.1.0的来源
  • gsub("\\\\\\\\","\\", "Do\\xf1a Ana County") 什么都不做。 stringi::stri_trans_general 提供强大而通用的音译;无需编写自己的to.plain 函数。
  • +1 你是绝对正确的,我花了一些时间阅读以弄清楚 \\ 与 R 中的 \ 相似,我不需要这样做。像往常一样,我回答得太快了,我将删除此行。还要感谢您指出 stringi::stri_trans_general 我将从现在开始使用它,但我自己的函数(和编码问题)比这个包要老得多......
【解决方案2】:

第一个问题是acs::fips.place 被严重破坏;如果提供例如\\xf1a,它的意思是\xf1a。应将错误报告给软件包管理员。与此同时,这里有一种解决方法:

tbl_df(acs::fips.place) %>%
    mutate(COUNTY = scan(text = str_c(COUNTY, collapse = "\n"),
                         sep = "\n",
                         what = "character",
                         allowEscapes = TRUE)) -> fp

Encoding(fp$COUNTY) <- "latin1"

fp %>%
    filter(COUNTY == "Doña Ana County")

清除转义后,您可以将非 ascii 字符音译为 ascii 替换。 stringi 包很容易:

library(stringi)
fp$COUNTY <- stri_trans_general(fp$COUNTY, "latin-ascii")

fp %>%
    filter(COUNTY == "Dona Ana County") 

【讨论】:

  • 这会创建“Doa Ana County”吗?
  • 这可能是一个不同的错误(在 R 本身中)。您可以忽略它(它只影响打印的表示)或跳过iconv 步骤。 (正是出于这个原因,我将iconv 步骤标记为可选。)
  • 我现在删除了iconv 部分并添加了第二个问题的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多