我有这个向量:
x <- c("De 1 a 2 semanas", "De 3 a 4 semanas", "Más de 6 semanas", "Menos de 1 semana")
我正在尝试通过唯一身份提取每个值:
str_extract(x, "1 sem|1 a 2|3 a 4|5 a 6|de 6 sem")
它有效:
[1] "1 a 2" "3 a 4" "de 6 sem" "1 sem"
但是,当我从数据帧调用向量时:
> x$PVS9
[1] "De 1 a 2 semanas" "De 3 a 4 semanas" "Más de 6 semanas" "Menos de 1 semana"
> x$PVS9 <- str_extract(x$PVS9, "1 sem|1 a 2|3 a 4|5 a 6|de 6 sem")
> x$PVS9
[1] "1 a 2" NA NA "1 sem"
为什么要给这两个NA
?
PS:您会发现question(及其答案)很有用。
这是最小的可复制示例:
> dput(x)
structure(list(PVS9 = c("De 1 a 2 semanas", "De 3 a 4 semanas",
"Más de 6 semanas", "Menos de 1 semana"), n = c(1L, 1L, 1L, 3L
), Porcentaje = c(0.17, 0.17, 0.17, 0.5)), row.names = c(NA,
-4L), class = c("tbl_df", "tbl", "data.frame"))
当前输出:
> str_extract(x$PVS9, "1 sem|1 a 2|3 a 4|5 a 6|de 6 sem")
[1] "1 a 2" NA NA "1 sem"
所需的输出:
[1] "1 a 2" "3 a 4" "de 6 sem" "1 sem"
其他信息:
会话信息:
> sessionInfo()
R version 3.5.2 (2018-12-20)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)
Matrix products: default
locale:
[1] LC_COLLATE=Spanish_Chile.1252 LC_CTYPE=Spanish_Chile.1252 LC_MONETARY=Spanish_Chile.1252 LC_NUMERIC=C LC_TIME=Spanish_Chile.1252
班级:
> class(x$PVS9)
[1] "character"
编码:
> Encoding(x$PVS9)
[1] "unknown" "unknown" "unknown" "unknown"
> guess_encoding(x$PVS9)
# A tibble: 3 x 2
encoding confidence
<chr> <dbl>
1 ISO-8859-1 0.98
2 ISO-8859-2 0.88
3 ISO-8859-9 0.33
也:
> x$PVS9 == y
[1] TRUE FALSE FALSE TRUE
我正在想解决这个问题,改变矢量的编码。这可能吗?如果没有,还有其他方法吗?
编辑:要求更多其他信息。
R认为是什么
> sapply(x$PVS9, charToRaw)
$`De 1 a 2 semanas`
[1] 44 65 20 31 20 61 20 32 20 73 65 6d 61 6e 61 73
$`De 3 a 4 semanas`
[1] 44 65 20 33 a0 61 20 34 a0 73 65 6d 61 6e 61 73
$`Más de 6 semanas`
[1] 4d e1 73 20 64 65 20 36 a0 73 65 6d 61 6e 61 73
$`Menos de 1 semana`
[1] 4d 65 6e 6f 73 20 64 65 20 31 20 73 65 6d 61 6e 61
答案 0 :(得分:1)
至少部分的原因是由于存在奇怪的字符,这些字符看起来与人类的普通字符相同,但与计算机不同:
charToRaw
将字符串转换为代表计算机字符的原始十六进制值。让我们看一下与您不匹配的第二个字符串,并将其与我在计算机上看到的第二个字符串(匹配匹配的地方)进行比较:
# This does NOT match
$`De 3 a 4 semanas`
[1] 44 65 20 33 a0 61 20 34 a0 73 65 6d 61 6e 61 73
# This does match
$`De 3 a 4 semanas`
[1] 44 65 20 33 20 61 20 34 20 73 65 6d 61 6e 61 73
有一个区别:第5个和第9个数字在我的系统上是20
,在您的系统上是a0
。这意味着什么?您可以使用intToUtf8
来查看这些字符的呈现方式,尽管首先我们必须convert from hexidecimal to decimal:
# 20 in hexidecimal
# is 32 in decimal
intToUtf8(32)
[1] " "
# a0 in hexidecimal
# is 160 in decimal
intToUtf8(160)
[1] " "
因此,对于我们来说,它们看起来都像是空间,但是对于计算机而言,它们是完全不同的字符。如果您在UTF-8 lookup table上查找这些数字,将会看到32是正常空间,而160是不间断空间:
32 SPACE
160 NO-BREAK SPACE
HTML文档中经常发现不间断空格(又名 
),以创建更宽的空格(因为多个连续的普通空格都缩短为一个)。
那么,我们该如何解决呢?首先,让我们复制您的数据:
bad_str2 <- paste0('De 3', intToUtf8(160), 'a', intToUtf8(160), '4 semanas')
# Looks the same
bad_str2
[1] "De 3 a 4 semanas"
# But has the non-breaking spaces
charToRaw(bad_str2)
[1] 44 65 20 33 c2 a0 61 c2 a0 34 20 73 65 6d 61 6e 61 73
# Regex does not work:
str_extract(bad_str2, "1 sem|1 a 2|3 a 4|5 a 6|de 6 sem")
[1] NA
现在,我们可以使用gsub
将常规空格替换为不间断空格:
# The \u prefix means interpret the following Hexidecimal code as a character
# So \ua0 means, the character specified by hex code 'a0', which is the nbsp
fixed_str <- gsub("\ua0", " ", bad_str2, fixed = TRUE)
# Still looks the same
fixed_str
[1] "De 3 a 4 semanas"
# But regex works now!
str_extract(fixed_str, "1 sem|1 a 2|3 a 4|5 a 6|de 6 sem")
[1] "3 a 4"