阅读外文字符

6

我有一个包含英超足球运动员姓名的数据库,我正在将其读入R(3.02)中,但是当涉及到名字中带有外国字符(umlauts、accents等)的球员时遇到了困难。下面的代码说明了这一点:

PlayerData<-read.table("C:\\Users\\Documents\\Players.csv",quote=NULL, dec = ".",,sep=",", stringsAsFactors=F,header=T,fill=T,blank.lines.skip = TRUE)
Test<-PlayerData[c(33655:33656),] #names of the players here are "Cazorla" "Özil"

Test[Test$Player=="Cazorla",] #Outputs correct details
Test[Test$Player=="Ozil",] # Can not find data '0 rows> (or 0-length row.names)'
<

#Example of how the foreign character is treated:
substr("Özil",1,1)
[1] "Ã"
substr("Özil",1,2)
[1] "Ö"
substr("Özil",2,2)
[1] "
substr("Özil",2,3)
[1] "z

我尝试了根据这里描述的方法替换字符:R: 替换字符串中的特殊字符,但是由于我的示例中的重音字符似乎被视为两个单独的字符,所以我认为它不起作用。

如果有任何建议或解决方法,我将不胜感激。

该文件可在此处下载:这里


你能把你的CSV文件中的这两行放到网络上吗?也许iconv可以帮忙。 - Karsten W.
1
这需要一个更长的答案(大部分超出了我的专业知识),但是尝试将所有内容转换为UTF-8:Test$Player <- iconv(Test$Player, to='UTF-8')。看看索引是否按预期工作。如果不强制编码,字符字符串将根据您的系统区域设置进行解释(您提供的示例在我的系统上按预期工作)。 - ilir
2个回答

4

编辑:看起来您提供的文件使用的编码方式与您系统的本地编码方式不同。

stri_enc_detect 函数通过 stringi 包执行的(实验性)编码检测结果如下:

library('stringi')
PlayerDataRaw <- stri_read_raw('~/Desktop/PLAYERS.csv')
stri_enc_detect(PlayerDataRaw)
## [[1]]
## [[1]]$Encoding
## [1] "ISO-8859-1" "ISO-8859-2" "ISO-8859-9" "IBM424_rtl"
## 
## [[1]]$Language
## [1] "en" "ro" "tr" "he"
## 
## [[1]]$Confidence
## [1] 0.25 0.14 0.09 0.02

很可能这个文件是用ISO-8859-1,即latin1编码格式。幸运的是,R在读取该文件时不需要重新编码输入,它只需设置与默认(==本地)编码标记不同的编码标记即可。您可以使用以下代码加载该文件:

PlayerData<-read.table('~/Desktop/PLAYERS.csv',
    quote=NULL, dec = ".", sep=",", 
    stringsAsFactors=FALSE, header=TRUE, fill=TRUE,
    blank.lines.skip=TRUE, encoding='latin1')

现在您可以正确访问单个字符,例如使用stri_sub函数:

Test<-PlayerData[c(33655:33656),]
Test
##           T          Away H.A    Home  Player Year
## 33655 33654 CrystalPalace   1 Arsenal Cazorla 2013
## 33656 33655 CrystalPalace   1 Arsenal    Özil 2013

stri_sub(Test$Player, 1, length=1)
## [1] "C" "Ö"
stri_sub(Test$Player, 2, length=1)
## [1] "a" "z"

在比较字符串方面,以下是使用“压平”的重音字符进行字符串相等性测试的结果:

stri_cmp_eq("Özil", "Ozil", stri_opts_collator(strength=1))
## [1] TRUE

您也可以使用iconv的转换器来去除重音符号(尽管我不确定它是否在Windows上可用)。
iconv(Test$Player, 'latin1', 'ASCII//TRANSLIT')
## [1] "Cazorla" "Ozil"

或者使用来自 stringi 包的非常强大的转换器(stringi 版本 >= 0.2-2):

stri_trans_general(Test$Player, 'Latin-ASCII')
## [1] "Cazorla" "Ozil"

非常好的答案 - iconv 的转换函数能够很好地解决这个问题。 - Pash101

0

感谢大家对此的帮助。

字符串已正确编码为UTF-8(我添加了参数到read.table,并使用iconv,如建议所示)。这似乎不是问题所在。

我还使用了stri_sub()函数。但这似乎也没有起作用(它将重音符号视为单独的字符stri_sub("Özil",1,3) = "Ã<U+0096>z")。

然而,感谢您指引我查看stringi文档,它给了我一个解决方法,我很高兴使用:

remove.accents<-function(s){
oldrefs<-c(214,225)#Ö, á
newrefs<-c(79,97)#O,a

New<-utf8ToInt(s)
for(i in 1:length(oldrefs)){
New<-as.numeric(gsub(oldrefs[i],newrefs[i],New))
NEW<-intToUtf8(New)
}
NEW
}
> (remove.accents("Özil"))
[1] "Ozil"
> (remove.accents("Suárez"))
[1] "Suarez"

我现在可以用整数引用填充oldrefs/newref数组,为我需要的某些球员(Touré Jääskeläinen,Agüero等)准备其他角色,希望这不会花费太长时间!


感谢指出这个有趣的字符串处理任务,我很快就会开始着手包括自动音译机制到stringi中,请参见此问题 - gagolews
如果 stri_sub 没有正确工作,我相信你的数据没有被正确读取。调用 Encoding(Test$Player) 的结果是什么? - gagolews
在导入之前,我已经在read.table函数中包含了encoding='UTF-8'参数。现在,Encoding(Test$Player)给出的输出是:"unknown" "UTF-8"(在这种情况下,unknown代表Cazorla;UTF-8代表Özil)。此外,传递UTF-8参数意味着Özil现在显示为<d6>zil - Pash101
嗯...你能把这个文件公开在某个地方并提供一个链接给SO吗? - gagolews
请查看我的更新答案,希望已经完全修复了。 - gagolews

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