【问题标题】:Extract URLs with regex into a new data frame column使用正则表达式将 URL 提取到新的数据框列中
【发布时间】:2014-10-21 21:19:27
【问题描述】:

我想使用正则表达式从数据框中的文本中提取所有 URL 到一个新列中。我有一些用于提取关键字的旧代码,因此我希望将代码改编为正则表达式。我想将正则表达式保存为字符串变量并在此处应用:

data$ContentURL <- apply(sapply(regex, grepl, data$Content, fixed=FALSE), 1, function(x) paste(selection[x], collapse=','))

似乎fixed=FALSE 应该告诉grepl 它是一个正则表达式,但 R 不喜欢我尝试将正则表达式保存为:

regex <- "http.*?1-\\d+,\\d+"

我的数据是这样组织在一个数据框中的:

data <- read.table(text='"Content"     "date"   
 1     "a house a home https://www.foo.com"     "12/31/2013"
 2     "cabin ideas https://www.example.com in the woods"     "5/4/2013"
 3     "motel is a hotel"   "1/4/2013"', header=TRUE)

希望看起来像:

                                           Content       date              ContentURL
1               a house a home https://www.foo.com 12/31/2013     https://www.foo.com
2 cabin ideas https://www.example.com in the woods   5/4/2013 https://www.example.com
3                                 motel is a hotel   1/4/2013                        

【问题讨论】:

  • 对于 R,整个正则表达式必须放在一个字符变量中。你从哪里得知\\&lt;\\&gt; 会被解析?
  • 如果您使用grep 对html 文档进行正则表达式,您就是在玩火
  • 也许,向我们展示数据以及您尝试提取的内容也会有所帮助。
  • 所有url还是某个url?
  • 很抱歉给您带来了困惑!我想提取所有的网址。

标签: regex r grepl


【解决方案1】:

具有良好 URL 模式的 Hadleyverse 解决方案(stringr 包):

library(stringr)

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

data$ContentURL <- str_extract(data$Content, url_pattern)

data

##                                            Content       date              ContentURL
## 1               a house a home https://www.foo.com 12/31/2013     https://www.foo.com
## 2 cabin ideas https://www.example.com in the woods   5/4/2013 https://www.example.com
## 3                                 motel is a hotel   1/4/2013                    <NA>

如果Content 中有多个,您可以使用str_extract_all,但这将涉及您之后的一些额外处理。

【讨论】:

    【解决方案2】:

    这是使用qdapRegex 库的一种方法:

    library(qdapRegex)
    data[["url"]] <- unlist(rm_url(data[["Content"]], extract=TRUE))
    data
    
    ##                                            Content       date                     url
    ## 1               a house a home https://www.foo.com 12/31/2013     https://www.foo.com
    ## 2 cabin ideas https://www.example.com in the woods   5/4/2013 https://www.example.com
    ## 3                                 motel is a hotel   1/4/2013                    <NA>
    

    要查看函数使用的正则表达式(qdapRegex 旨在帮助分析和教育正则表达式),您可以使用函数名称以 @ 为前缀的 grab 函数:

    grab("@rm_url")
    
    ## [1] "(http[^ ]*)|(ftp[^ ]*)|(www\\.[^ ]*)"
    

    grepl 告诉你这个字符串包含或不包含的逻辑输出。 grep 告诉您索引或给出值,但值是整个字符串,即您想要的子字符串。

    因此,要将这个正则表达式传递给 base 或 stringi 包(qdapRegex 包装 stingi 以进行提取),您可以这样做:

    regmatches(data[["Content"]], gregexpr(grab("@rm_url"), data[["Content"]], perl = TRUE))
    
    library(stringi)
    stri_extract(data[["Content"]], regex=grab("@rm_url"))
    

    我确定也有 stringr 方法,但对包不熟悉。

    【讨论】:

      【解决方案3】:

      在空间上拆分然后找到“http”:

      data$ContentURL <- unlist(sapply(strsplit(as.character(data$Content), split = " "),
                                       function(i){
                                         x <- i[ grepl("http", i)]
                                         if(length(x) == 0) x <- NA
                                         x
                                       }))
      
      
      data
      #                                            Content       date              ContentURL
      # 1               a house a home https://www.foo.com 12/31/2013     https://www.foo.com
      # 2 cabin ideas https://www.example.com in the woods   5/4/2013 https://www.example.com
      # 3                                 motel is a hotel   1/4/2013                    <NA>
      

      【讨论】:

        【解决方案4】:

        你可以使用包脱胶

        library(unglue)
        unglue_unnest(data,Content, "{=.*?}{url=http[^ ]*}{=.*?}",remove = FALSE)
        #>                                            Content       date                       url
        #> 1               a house a home https://www.f00.com 12/31/2013 1     https://www.f00.com
        #> 2 cabin ideas https://www.example.com in the woods   5/4/2013 2 https://www.example.com
        #> 3                                 motel is a hotel   1/4/2013 3                    <NA>
        
        • {=.*?} 匹配任何内容并且未分配给提取的列,因此 = 的 lhs 为空
        • {url=http[^ ]*} 匹配以http 开头并且后跟非空格的内容,因为 lhs 是 url 它被提取到 url

        Ps:由于 SO 限制,我在答案中手动将 foo 更改为 f00

        【讨论】:

          猜你喜欢
          • 2021-01-22
          • 2020-09-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多