通过 ODBC 从 MS SQL 读取后编码出现 R 问题
R problems with encoding after reading from MS SQL via ODBC
我们在不同的虚拟机上有一个数据库和 R 脚本 运行。
首先我们连接到 db
con <- dbConnect(
odbc(),
Driver = "SQL Server",
Server = "server", Database = "db", UID = "uid", PWD = "pwd",
encoding = "UTF-8"
)
并收集数据
data <- dbGetQuery(con, "SELECT * FROM TableName")
问题如下:当不同的机器运行相同的脚本时,对于其中一些我们面临字符变量编码问题。
例如,这是我们在机器 A 上的内容
> data$char_var[1]
[1] "фамилия"
> Encoding(data$char_var[1])
[1] "UTF-8"
> Sys.getlocale()
[1] "LC_COLLATE=Russian_Russia.1251;LC_CTYPE=Russian_Russia.1251;LC_MONETARY=Russian_Russia.1251;LC_NUMERIC=C;LC_TIME=Russian_Russia.1251"
> Encoding(data$char_var[1]) <- "1251"
> data$char_var[1]
[1] "гревцев"
这就是我们在机器 B 上的内容
> data$char_var[1]
[1] "<e3><f0><e5><e2><f6><e5><e2>"
> Encoding(data$char_var[1])
[1] "UTF-8"
> Sys.getlocale()
[1] "LC_COLLATE=Russian_Russia.1251;LC_CTYPE=Russian_Russia.1251;LC_MONETARY=Russian_Russia.1251;LC_NUMERIC=C;LC_TIME=Russian_Russia.1251"
> Encoding(data$char_var[1]) <- "1251"
> data$char_var[1]
[1] "фамилия"
第一个脚本 returns 乱码,但它正确地打印了初始值。机器 B 上的相同代码 运行 最初打印 utf-8,然后打印 returns 编码值。造成这种差异的原因可能是什么?
因此,我们需要一个具有相同“фамилия”输出值的脚本,以在仪表板上显示它。
根据您调用 Encoding(data$char_var[1])
的结果,两台机器都声明 returned 结果使用 UTF-8 编码。
在第一台机器上,这似乎是正确的,因为您看到的是有效输出。然后你通过将编码错误地声明为 "1251"
来搞砸它,你会看到乱码。
在第二台机器上,您收到的结果声明为 UTF-8,但实际上不是(这就是为什么一开始看起来像乱码)。当您将声明的编码更改为 "1251"
时,它看起来没问题,所以它一直都是这样。
所以你有两个选择:
确保两台机器关于 return 来自 dbGetQuery
的内容是一致的。您可以处理任何一种编码,但您需要知道它是什么并确保它被正确声明。
或者,尝试检测正在 returned 的内容,并适当地声明它。执行此操作的一种方法可能是将已知字符串放入数据库并将结果与该字符串进行比较。如果你知道你应该得到 "фамилия"
而你得到了其他东西,请切换声明的编码。您也可以尝试 readr::guess_encoding()
函数。
另一个问题是某些下游函数可能只能处理 UTF-8 和 1251 编码中的一种。 (Windows R 在非本地编码方面真的很糟糕,而 UTF-8 在 Windows 上从来不是本地编码。)在那种情况下,您可能想要实际转换为通用编码。您可以使用 iconv()
函数来执行此操作,例如
iconv(char_var, from = "cp1251", to = "UTF-8")
将尝试转换为 UTF-8。
我们在不同的虚拟机上有一个数据库和 R 脚本 运行。 首先我们连接到 db
con <- dbConnect(
odbc(),
Driver = "SQL Server",
Server = "server", Database = "db", UID = "uid", PWD = "pwd",
encoding = "UTF-8"
)
并收集数据
data <- dbGetQuery(con, "SELECT * FROM TableName")
问题如下:当不同的机器运行相同的脚本时,对于其中一些我们面临字符变量编码问题。
例如,这是我们在机器 A 上的内容
> data$char_var[1]
[1] "фамилия"
> Encoding(data$char_var[1])
[1] "UTF-8"
> Sys.getlocale()
[1] "LC_COLLATE=Russian_Russia.1251;LC_CTYPE=Russian_Russia.1251;LC_MONETARY=Russian_Russia.1251;LC_NUMERIC=C;LC_TIME=Russian_Russia.1251"
> Encoding(data$char_var[1]) <- "1251"
> data$char_var[1]
[1] "гревцев"
这就是我们在机器 B 上的内容
> data$char_var[1]
[1] "<e3><f0><e5><e2><f6><e5><e2>"
> Encoding(data$char_var[1])
[1] "UTF-8"
> Sys.getlocale()
[1] "LC_COLLATE=Russian_Russia.1251;LC_CTYPE=Russian_Russia.1251;LC_MONETARY=Russian_Russia.1251;LC_NUMERIC=C;LC_TIME=Russian_Russia.1251"
> Encoding(data$char_var[1]) <- "1251"
> data$char_var[1]
[1] "фамилия"
第一个脚本 returns 乱码,但它正确地打印了初始值。机器 B 上的相同代码 运行 最初打印 utf-8,然后打印 returns 编码值。造成这种差异的原因可能是什么?
因此,我们需要一个具有相同“фамилия”输出值的脚本,以在仪表板上显示它。
根据您调用 Encoding(data$char_var[1])
的结果,两台机器都声明 returned 结果使用 UTF-8 编码。
在第一台机器上,这似乎是正确的,因为您看到的是有效输出。然后你通过将编码错误地声明为 "1251"
来搞砸它,你会看到乱码。
在第二台机器上,您收到的结果声明为 UTF-8,但实际上不是(这就是为什么一开始看起来像乱码)。当您将声明的编码更改为 "1251"
时,它看起来没问题,所以它一直都是这样。
所以你有两个选择:
确保两台机器关于 return 来自
dbGetQuery
的内容是一致的。您可以处理任何一种编码,但您需要知道它是什么并确保它被正确声明。或者,尝试检测正在 returned 的内容,并适当地声明它。执行此操作的一种方法可能是将已知字符串放入数据库并将结果与该字符串进行比较。如果你知道你应该得到
"фамилия"
而你得到了其他东西,请切换声明的编码。您也可以尝试readr::guess_encoding()
函数。
另一个问题是某些下游函数可能只能处理 UTF-8 和 1251 编码中的一种。 (Windows R 在非本地编码方面真的很糟糕,而 UTF-8 在 Windows 上从来不是本地编码。)在那种情况下,您可能想要实际转换为通用编码。您可以使用 iconv()
函数来执行此操作,例如
iconv(char_var, from = "cp1251", to = "UTF-8")
将尝试转换为 UTF-8。