Извлечь URL-адреса с регулярным выражением в новый столбец фрейма данных

Я хочу использовать регулярное выражение для извлечения всех 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                        

person lmcshane    schedule 21.10.2014    source источник
comment
Для R все регулярное выражение должно находиться в символьной переменной. Откуда вы взяли, что \\< и \\> будут анализироваться?   -  person joran    schedule 22.10.2014
comment
Вы играете с огнем, если используете grep для регулярного выражения в html-документе   -  person Rich Scriven    schedule 22.10.2014
comment
Возможно, нам тоже поможет показ данных и того, что вы пытаетесь извлечь.   -  person hwnd    schedule 22.10.2014
comment
Все URL-адреса или определенный URL-адрес?   -  person hwnd    schedule 22.10.2014
comment
Извините за путаницу! Я хочу извлечь все URL-адреса.   -  person lmcshane    schedule 22.10.2014
comment
спасибо, что остановились на моем вопросе! Я думаю, что все части головоломки уже там. Я постараюсь сделать это более ясным. Спасибо за помощь!   -  person lmcshane    schedule 22.10.2014


Ответы (4)


Решение Hadleyverse (пакет stringr) с приличным шаблоном URL:

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>

Вы можете использовать str_extract_all, если в Content есть кратные числа, но впоследствии это потребует дополнительной обработки с вашей стороны.

person hrbrmstr    schedule 22.10.2014

Вот один из подходов с использованием библиотеки 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 сообщает вам индексы или дает значения, но значения представляют собой всю строку, а не подстроку, которую вы хотите.

Таким образом, чтобы передать это регулярное выражение в базу или пакет 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, но я не знаком с пакетом.

person Tyler Rinker    schedule 21.10.2014

Разделите на пробел, затем найдите «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>
person zx8754    schedule 15.01.2018

Вы можете использовать пакет unglue:

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>
  • {=.*?} соответствует чему угодно и не назначается извлеченному столбцу, поэтому левая часть = пуста.
  • {url=http[^ ]*} соответствует чему-то, что начинается с http и за которым следуют не пробелы, так как левое значение равно url, оно извлекается в url

Ps: я вручную изменил foo на f00 в своем ответе из-за ограничений SO

person Moody_Mudskipper    schedule 08.10.2019