【问题标题】:How to split a character row, based on urls in R如何根据 R 中的 url 拆分字符行
【发布时间】:2021-03-20 10:30:39
【问题描述】:

如何根据 url 拆分字符行?我在数据框中有一列,其中每一行的文本超过 200-300 行,并包含一堆 url、特殊字符和数字等。我正在尝试清理此列。

最初的想法是从整列中删除停用词和标点符号,但这会弄乱文本中现有的网址。

因此,第二种方法是将文本拆分为多个列,其中拆分发生在每个 url。与此相关的一个后续问题是,每行中的 url 位置是否不同,因此仍然难以仅清理文本?

这里是示例文本:

sample_text <- "Random text](https://random_url.com/image.png) --- more random text : - !!!!! (Numbers in the middle, versions 4.3.2.1 more random text ) [] --- //// more and more random text for another 300 lines. Line1 has some useful text , line 2 has a url, https://rstudio.com/maybe_has_some_version_files/2/image.png [ #] and continues for another 299 lines."

我确实尝试了 strsplit(),但它从文本中删除了 url。

url_pattern <- "http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*,]|(?:%[0-9a-fA-F][0-9a-fA-F]))+|\\)$"  
split_string_1 <-  strsplit(sample_text, url_pattern, perl = TRUE)

预期的输出应该是: 将字符串拆分为多列。

所以我的问题分为两部分:

  1. 如何拆分字符串并保留url?
  2. 如何拆分字符串并为每个拆分创建新列?

编辑:

是的,我不想要新列,而是希望清理文本并将 URL 保留在其位置。

问题是:

  • 如何拆分字符串、清理其余文本而不弄乱 URL 并保留 URL 在文本中的位置?

【问题讨论】:

  • 您期望的实际输出是什么?一条线会变成多条线吗?还有什么?
  • @TimBiegeleisen 不完全是,预期的输出是将字符串拆分为多列。但是,另一个问题是,对于剩余的行,一个 url 的拆分可能不会发生在同一位置,那么我该如何清理文本列呢?这有意义吗?

标签: r regex data-cleaning strsplit


【解决方案1】:

假设每行包含 2 个 URL(否则你不能将它们存储在标准数据框中,因为每行需要不同数量的列),你只需要找到字符串“http(s)”的位置",并在该位置拆分字符串。

对于此类任务,基本 R 函数 gregexpr()regexec() 非常适合。例如:

gregexpr("https?", sample_text)
#> [[1]]
#> [1]  14 247
#> attr(,"match.length")
#> [1] 5 5
#> attr(,"index.type")
#> [1] "chars"
#> attr(,"useBytes")
#> [1] TRUE

这是一个列表,如果sample_text 有多个元素,它将包含多个元素。第一个条目包含“http(s)”子字符串的起始位置。那么你只需使用substr() 来提取新列:


match_pos <- gregexpr("https?", sample_text)

# column 1
purrr::map2(sample_text, match_pos, ~ substring(.x, 1, .y[2]-1))
# column 2
purrr::map2(sample_text, match_pos, ~ substring(.x, .y[1], .y[2]-1))
# column 3
purrr::map2(sample_text, match_pos, ~ substring(.x, .y[2]))

请注意,我可以在这里对三列进行硬编码,因为必须始终保持相同的数字。

编辑:如果目标是实际提取 URL,则可以采用相同的方法。这里将结果保存在列表中:

sample_text <- "Random text](https://random_url.com/image.png) --- more random text : - !!!!! (Numbers in the middle, versions 4.3.2.1 more random text ) [] --- //// more and more random text for another 300 lines. Line1 has some useful text , line 2 has a url, https://rstudio.com/maybe_has_some_version_files/2/image.png [ #] and continues for another 299 lines."

match_pos <- gregexpr("https?://[[:alnum:]\\.\\-_\\/]+", sample_text)

url_starts <- lapply(match_pos, function(x) {attributes(x) <- NULL;x})
url_lengths <- lapply(match_pos, function(x) attr(x, "match.length"))
url_ends <- purrr::map2(url_starts, url_lengths, ~ .x+.y)

url_texts <- purrr::pmap(list(sample_text,url_starts, url_ends),
                             function(t,s,e) purrr::map2_chr(s,e, ~substr(t,.x,.y-1)))

url_texts
#> [[1]]
#> [1] "https://random_url.com/image.png"                            
#> [2] "https://rstudio.com/maybe_has_some_version_files/2/image.png"

reprex package (v0.3.0) 于 2020-12-09 创建

【讨论】:

  • 我了解 grepexpr 的用法,但这里的问题在于您的第一条语句“假设每行包含 2 个 URL”,这是未知的。每行都有未知数量的 URL,这就是我无法创建数据框的原因,因为正如您所提到的,列数需要相同,而每行可能并非如此。此外,也可能有 2 个 url 彼此相邻的情况,这将创建 2 个单独的列,但下一行可能在每个 url 之后都有文本。
  • 想象一下这个问题,清理带有一堆 URL 的文本,并且您希望保留 URL 以及它们在文本中的位置。数据框中有 1000 行,每行包含未知数量的 url、标点符号、数字、空格。
  • 如果您的预期输出不是数据框的列,请澄清您的问题。如果目标是保留 url 而不是拆分字符串,请参阅我的编辑。
  • 感谢您建议进行编辑。是的,我希望保留 URL 及其在文本中的位置,但也要清除文本的其余部分。您当前的答案确实帮助我提取了 url,但我失去了它在文本中的位置。我使用 str_extract_all(sample_text, url_pattern) 实现了这一点,我在其中预定义了 url_pattern。
  • 文中的位置叫什么?是字面上的位置(例如它在第 45 个字符处)还是其他什么?
猜你喜欢
  • 2017-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-16
  • 2021-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多