Извлекать данные из списка и помещать их в аккуратный tibble, R

#r #list #loops

#r #Список #циклы

Вопрос:

У меня есть список (список в примере кода) Я хочу выполнить цикл, извлечь данные и попасть в аккуратный набор данных (целевой tibble в примере кода). Список состоит из 5 элементов, каждый из которых, как предполагается, представляет страницу в форме заявки. Каждый элемент представляет собой одну строку.

  1. Из первого элемента я хочу извлечь информацию, относящуюся к числу слов и организации.

  2. Между словами Start(элемент 3) и stop(элемент 5) Я стремлюсь извлечь информацию, относящуюся к имени и информации. Это информация между двоеточием (:) после name и info и строки, которую я хочу извлечь. Возможно, возможно решение с регулярными выражениями? В примере кода есть 3 имени и 3 информации. Я стремлюсь создать универсальную функцию, которая может обрабатывать любое количество имен и информации в определенных границах (start, stop).

Как я могу решить эту проблему в R? Благодарен за любую помощь. Я предпринял несколько попыток с помощью str_extract_all(), но все они потерпели неудачу.

 library(tidyverse)

target <- tibble(number = c("10", "10", "10"),
          organization = c("TEST", "TEST", "TEST"),
       name = c("X", "Y", "Z"),
       info = c(12, 1, 43))

string1 <- "Application rn Date: 2020-09-23rn number: 10rn organization: TEST rnMail: x@x.comrn
             Page 1(5)rn"
string2 <- "Application rn Date: 2020-09-23rn ZZZZZZZZrn
             Page 2(5)rn"
string3 <- "Application rn Date: 2020-09-23rn Startrn name: Xrninfo: 12rnmiss: NOrnname: Yrninfo: 1rnname: Zr
             Page 3(5)rn"
string4 <- "Application rn Date: 2020-09-23rn info: 43rn miss: YESrnPage 4(5)rn"
string5 <- "stoprnname: ZYrninfo:45rnMISS:-rnPage 5(5)"

list <- as.list(c(string1, string2, string3, string4, string5))

  

Комментарии:

1. Вы уверены, что ваша «цель» соответствует входным данным, должно быть 5 строк?

2. ДА. Я стремлюсь иметь одну строку для каждого имени (X, Y, Z). И я хочу извлекать данные только из имен, находящихся в границах start stop. Это попытка воспроизвести условия для моего реального случая, который заключается в извлечении данных из больших форм заявок (pdf).

3. Понятно, вы пробовали использовать tabulizer , используемый для извлечения таблиц из PDF-файлов.

4. Нет. Я использую pdf_text() из pdftools. Функция возвращает одну длинную строку с разрывами строк для каждой страницы в pdf. Возможно, tabulizer лучше? Для этого требуется установленная Java, и это является проблемой для меня, когда я использую свой рабочий компьютер.

Ответ №1:

Я думаю, это то, чего вы хотите достичь:

 str <- paste0(string1, string2, string3, string4, string5)
str_extract_all(str, regex("(?<=start). ?(?=stop)", dotall = TRUE,ignore_case = TRUE))[[1]] -> strs

str_match_all(strs, regex("name: *([^\r\n] ?)\r\n.*?info: *([^\r\n] ?)\r\n", dotall=T))[[1]][,-1] -> mat

tibble(name=mat[,1], info=mat[,2], number=as.numeric(str_extract(str, "(?<=number: )\d ")),organization=str_extract(str, "(?<=organization: ). (?=  \r)") )
  
 # A tibble: 3 x 4
  name  info  number organization
  <chr> <chr>  <dbl> <chr>       
1 X     12        10 TEST        
2 Y     1         10 TEST        
3 Z     43        10 TEST  
  

Пояснения:

Я использую lookaheads (?=pat) (соответственно. посмотрите (?<=pat на )), чтобы проверить, соответствуют ли следующие (соответственно, предыдущие) символы pat .

  • str_extract_all(..., "(?<=start). ?(?=stop)") получите текст, который находится между start и stop.
  • name: *([^\r\n] ?)\r\n.*?info: *([^\r\n] ?)\r\n :
    1. name: * совпадение name: , за которым следует любое количество пробелов.
    2. ([^\r\n] ?) захватите один или несколько символов, которые отличаются от возврата каретки r и новой строки r , ? квантификатор должен соответствовать минимально возможному количеству символов, т.е. в терминах регулярных выражений квантификатор не является жадным.
    3. \r\n.*? сопоставьте литерал rn и .*? любое количество символов как можно меньше.
    4. ([^\r\n] ?)\r\n захват …. затем сопоставьте литерал rn .

Комментарии:

1. Я искренне благодарен. Я не понимаю всех регулярных выражений. я, конечно, изучу это более глубоко, но если это не слишком сложно для вас, не могли бы вы рассказать мне, что происходит? Почему вы сделали это в виде строки, а не списка? Имеет ли строка какие-либо преимущества в этом случае?

2. @Henrik Я добавил пояснения и упростил код. Я сделал это строкой, чтобы я мог получать данные между start и stop, а также потому, что третье имя содержало информацию на другой странице. Так проще манипулировать строкой. также, если у вас есть несколько запусков и остановок в одном файле, я могу приспособиться к этому.

3. Я думаю, что я следую регулярному выражению. Весело! Я, конечно, столкнулся с новой проблемой, потому что мне нужно собрать мои реальные данные в одну строку, подобную той, которую вы использовали. Pdf_text возвращает список с одной строкой на страницу. Один элемент — это целая страница.

4. если он возвращает список, вы можете превратить его в вектор, используя unlist(ur.lst)

5. paste0(ur.lst, collapse="") чтобы сделать его одной строкой