将零长度字符向量作为空字符串处理

Handling zero length character vectors as empty strings

例如,请参阅下面的 Twitter 句柄提取。目标是有一个类似于 tweets 的字符串,但只有用逗号分隔的句柄。 str_replace_all 在未找到匹配项时生成空向量,这会进一步引发一些意外错误。

library(purrr)
library(stringr)

tweets <- c(
  "",
  "This tweet has no handles",
  "This is a tweet for @you",
  "This is another tweet for @you and @me",
  "This, @bla, is another tweet for @me and @you"
)


mention_rx <- "@\w+"

这是我的第一次尝试:

map_chr(tweets, ~str_c(str_extract_all(.x, mention_rx)[[1]], collapse = ", "))
#> Error: Result 1 must be a single string, not a character vector of length 0

然后我玩弄了一些东西:

mentions <- map(tweets, ~str_c(str_extract_all(.x, mention_rx)[[1]], collapse = ", "))

mentions
#> [[1]]
#> character(0)
#> 
#> [[2]]
#> character(0)
#> 
#> [[3]]
#> [1] "@you"
#> 
#> [[4]]
#> [1] "@you, @me"
#> 
#> [[5]]
#> [1] "@bla, @me, @you"

as.character(mentions)
#> [1] "character(0)"    "character(0)"    "@you"            "@you, @me"      
#> [5] "@bla, @me, @you"

直到我突然意识到 paste 也可以在这里使用:

map_chr(tweets, ~paste(str_extract_all(.x, mention_rx)[[1]], collapse = ", "))
#> ""                ""                "@you"            "@you, @me"       "@bla, @me, @you"

我的问题是:

我在 , paste, and the 上找到了一些很好的参考资料;但是 none 其中解决了空字符串的情况。

您不需要map超过tweetsstr_extract_all可以处理向量

library(stringr)
str_extract_all(tweets, mention_rx)

#[[1]]
#character(0)

#[[2]]
#character(0)

#[[3]]
#[1] "@you"

#[[4]]
#[1] "@you" "@me" 

#[[5]]
#[1] "@bla" "@me"  "@you"

现在,如果您需要一个逗号分隔的字符串,那么您可以使用 map

purrr::map_chr(str_extract_all(tweets, mention_rx), toString)
#[1] ""    ""      "@you"     "@you, @me"      "@bla, @me, @you"

要回答"why"的问题,我们可以查看pastestr_c函数的文档。

来自?paste

Vector arguments are recycled as needed, with zero-length arguments being recycled to "".

来自 ?str_c

Zero length arguments are removed.

因此,默认情况下 str_c 删除零长度参数,这使得输出为 0 长度字符串,对于 map_chr 失败但它适用于 map 作为 map returns 一个列表

map(tweets, ~str_c(str_extract_all(.x, mention_rx)[[1]], collapse = ", "))

#[[1]]
#character(0)

#[[2]]
#character(0)

#[[3]]
 #[1] "@you"

#[[4]]
#[1] "@you, @me"

#[[5]]
#[1] "@bla, @me, @you"