Извлечение нескольких регулярных выражений из текста R

У меня есть следующий дф

df = data.frame(id = c(1,2,3), text = c('Label issues as ISS101  and ISS 201 on label 23 with x203 17','issue as ISS5051 with label 01 as l018','there is nothing here') 

Я хочу извлечь и создать следующий фрейм данных из df

id  iss     label  ext1 ext2
 1  ISS101  23     x203  17
 1  ISS201  23     x203  17
 2  ISS5051 01     l018  NA
 3    NA    NA      NA   NA

Длина is может варьироваться, как показано в примере. Он может иметь или не иметь пробела между «ISS» и последующими цифрами, опять же, это видно, например. Длина метки, ext1 и ext2 фиксированы. Я пробовал различные возможности с регулярным выражением, используя stringr и dplyr. Но ни один из них не близок к решению и, следовательно, заслуживает упоминания здесь. С нетерпением ждем помощи, дайте мне знать, если вам нужна дополнительная информация.


person Param    schedule 09.02.2018    source источник


Ответы (3)


Вы можете использовать dplyr и stringr вот так...

library(dplyr)
library(stringr)

df2 <- df %>% mutate(iss=str_extract_all(str_replace_all(text,"ISS\\s+(\\d+)","ISS\\1"),
                        "ISS\\d+"), #remove spaces and then extract ISSnnn
                 label=str_match(text,"label\\s+(\\d+)")[,2], #extract label + nn
                 ext1=str_match(text,"label\\s+\\d+.*?([a-z]\\d+)")[,2], #extract Xnnn after label
                 ext2=str_match(text,"\\s(\\d+)$")[,2]) %>% #extract digits at end of string
              unnest(iss) %>% #unnest iss (creates one row for each iss)
              select(iss,label,ext1,ext2) #select wanted variables

df2

      iss label ext1 ext2
1  ISS101    23 x203   17
2  ISS201    23 x203   17
3 ISS5051    01 l018 <NA>
person Andrew Gustar    schedule 09.02.2018
comment
работает!! Ничего не убирая, не могли бы вы порекомендовать шпаргалку по регулярным выражениям? Использовали тот, что от Rstudio - person Param; 10.02.2018
comment
@Param Я обычно использую его, когда застреваю... rexegg.com/regex-quickstart .html - person Andrew Gustar; 10.02.2018
comment
regex101.com — отличный IMO, вы также можете напрямую + интерактивно тестировать свои выражения - person erocoar; 10.02.2018

Это может быть началом:

do.call(plyr::rbind.fill, 
  lapply(df$text, function(x) {
    as.data.frame(cbind(
      iss = unlist(stringr::str_extract_all(x, "(ISS\\s?\\d{3,4})")),
      label = unlist(stringr::str_extract_all(x, "(?<=label)\\s?(\\d{1,2})")),
      ext1 = unlist(stringr::str_extract_all(x, "((x|l)\\d{3})")),
      ext2 = unlist(stringr::str_extract_all(x, "(?<=x|l\\d{3})\\s?\\d{1,3}"))
    ))}
    ))

      iss label ext1 ext2
1  ISS101    23 x203  203
2 ISS 201    23 x203  203
3 ISS5051    01 l018 <NA>
person erocoar    schedule 09.02.2018

Я сделал все, что мог, основываясь на вашем описании. Не видя дополнительных данных, я не могу гарантировать, что это будет обобщаемо, но он дает желаемый результат для предоставленного вами df, поэтому это должно быть хорошим началом.

# create data frame
df = data.frame(id = c(1,2,3), text = c('Label issues as ISS101  and ISS 201 on label 23 with x203 17','issue as ISS5051 with label 01 as l018','there is nothing here'))

# parse text into fields
df <- df %>% mutate(
    iss = str_extract(text, "ISS\\d+\\D"),
    iss_space = str_extract(text, "ISS\\s\\d+\\D"),
    label = str_extract(text, "label.+\\D"), 
    label = str_extract(label, "\\d+\\D"),
    ext1 = str_extract(text, "\\s\\D\\d{3}"),
    ext2 = str_extract(text, "\\s\\D\\d{3}\\s\\d{2}"),
    ext2 = str_extract(ext2, "\\s\\d{2}")) 

# clean up into correct format
df <- df %>%
   gather(iss, iss_space, key = "type", value = "iss") %>%
    select(-text, -type) %>% 
    distinct() %>%
    filter(!(duplicated(id) == T & is.na(iss) == T)) %>%
    arrange(id) %>%
    select(id, iss, label, ext1, ext2) %>%
    mutate(iss = str_replace_all(iss, " ", ""))

df

  id     iss label  ext1 ext2
1  1  ISS101   23   x203   17
2  1  ISS201   23   x203   17
3  2 ISS5051   01   l018 <NA>
4  3    <NA>  <NA>  <NA> <NA>
person Nick Holt    schedule 09.02.2018