iconv()在给定包含特定特殊字符的字符串时返回NA

3
我试图将输入文件中的一些字符串从UTF8转换为ASCII。 对于我提供的大多数字符串,iconv()可以完美地进行转换。 但是对于其中的一些字符串,它返回NA。手动修复文件中的问题似乎是最简单的选项,但不幸的是,目前我根本没有这个选项。
我已经创建了一个可重现的示例来展示我的问题,但我们需要找到一种方法让iconv()以某种方式转换s1中的字符串,而不会得到NA
以下是可重现性的示例:
s1 <- "Besançon" #as read from an input file I cannot modify
s2 <- "Paris"
s3 <- "Linköping"
s4 <- "Besançon" #Manual input for testing

s1 <- iconv(s1, to='ASCII//TRANSLIT')
s2 <- iconv(s2, to='ASCII//TRANSLIT')
s3 <- iconv(s3, to='ASCII//TRANSLIT')
s4 <- iconv(s4, to='ASCII//TRANSLIT')

I get the following output:

> s1
[1] NA
> s2
[1] "Paris"
> s3
[1] "Link\"oping"
> s4
[1] "Besancon"

玩弄代码后,我发现录入的“贝桑松”出现了问题,但是当我手动输入时,问题得到解决。考虑到无法修改输入文件,您认为确切的问题是什么?您有什么解决方法吗?
提前致谢。
编辑:
经过仔细检查,第一行字符中有一些奇怪的问题。似乎被 SO 的格式化所拿走了。 但为了再现它,我能给出的最好的是这两张图片描述它。第一张图片把我的光标放在 # 前面。 第二张图片是按下删除键后,应该会删除空格...结果删除了 "。因此,那里肯定有些奇怪的东西。 enter image description here enter image description here

您需要将s1转换为音译文字。将命令更改为s1 <- iconv(s1, to='ASCII//TRANSLIT')可以按照要求工作。 - thorepet
@thorepet 那是我复制粘贴的错误。我已经加上了。正在编辑中。但还是不能正常工作。 - LBes
当您指定一个 sub 时会发生什么?系统中的 iconvlist() 是否与您本地的相同? - Chris
@Chris,你想让我指定哪个子程序?不确定我理解你的问题。 - LBes
只是跟随 ?iconv 无法转换的‘x’元素(可能是因为它们无效或无法在目标编码中表示)将返回为‘NA’,除非指定了‘sub’。 这似乎不太直观,考虑到您的s3 /,但也许指定一个子目录,例如 sub = '/' 可以让您的不受控制的文件正常工作。这只是一个想法。 - Chris
显示剩余3条评论
2个回答

2
原来使用sub=''解决了问题,尽管我不太确定为什么。
iconv(s1, to='ASCII//TRANSLIT', sub='')

从文档中得知,sub函数的作用是:

将输入字符串中无法转换的字节替换为指定的字符。该字符可以是单个字符,也可以是多个字符。如果指定为"byte",则用该字节的十六进制代码表示。如果从UTF-8转换为Unicode,则使用形式为"<U+xxxx>"的Unicode点。

因此,我最终发现在字符串中有一个无法转换(也看不到)的字符,使用sub函数可以消除它。但我仍然不确定这个字符是什么。但问题已经解决了。


这个逻辑似乎很合理,即iconv将尝试基于所有可用选项进行转换,如果无法转换,则发出嵌入式不可转换的错误信号。然后sub函数作为“如果其他方法都失败了”,使用它。根据您的数据管道和研究需求,您可能会进一步决定一个符号,例如“+”或“/”,如果您正在跟踪其传播路径。很高兴解决了问题。 - Chris
@Chris 是的,我似乎无法追踪这个来自哪里,我用 sub='+' 的技巧来查看它的位置。现在我知道它在哪里了,但仍然看不到实际字符是什么... 至少问题已经解决了! - LBes
这导致了@Webb的方法,如果真的有关注的话。 - Chris
这似乎几乎肯定是控制字符。以下是一种在输入数据中查找它们的方法:https://superuser.com/a/377805/1280908 - webb

1

您的文件中可能存在latin1(或其他编码)字符,而不是utf8。例如:

> latin=iconv('Besançon','utf8','latin1')
> iconv(latin,to='ascii//translit')
[1] NA
> iconv(latin,'utf8','ascii//translit')
[1] NA
> iconv(latin,'latin1','ascii//translit')
[1] "Besancon"
> iconv(l,'Windows-1250','ascii//translit')
[1] "Besancon"

您可以例如创建一个新的向量或数据列,其中包含数据中每个字符集编码的结果,如果其中一个为NA,则回退到下一个编码,例如:
utf8 = iconv(x,'utf8','ascii//translit')
latin1 = iconv(x,'latin1','ascii//translit')
win1250 = iconv(x,'Windows-1250','ascii//translit')
result = ifelse(
  is.na(utf8),
  ifelse(
    is.na(latin1),
    win1250,
    latin1
  ),
  utf8
)

如果这些编码无法使用,可以创建一个只包含问题单词的文件,然后使用Unix/Linux的file命令来检测编码,或尝试一些可能的编码。
过去我曾列出了所有iconv支持的编码,用lapply尝试了所有编码,然后在每个字符串上使用有效结果,但某些“from”编码将返回非NA但不正确的结果,因此最好在数据中的每个唯一字符上尝试此操作,以决定使用iconv的哪个子集及其顺序。

你好,感谢您的建议。无论是R还是文件命令都表明这是utf-8编码,但是您提出的所有方法都没有奏效。我倾向于认为输入中存在某些问题(请参见我的图像编辑),但我似乎无法找出问题所在。 - LBes

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