str_extract()提供了不同的结果,从数据帧调用矢量-R

时间:2019-04-22 20:57:57

标签: r regex string

我有这个向量:

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

1 个答案:

答案 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文档中经常发现不间断空格(又名&nbsp),以创建更宽的空格(因为多个连续的普通空格都缩短为一个)。


那么,我们该如何解决呢?首先,让我们复制您的数据:

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"