#r #list #loops
#r #Список #циклы
Вопрос:
У меня есть список (список в примере кода) Я хочу выполнить цикл, извлечь данные и попасть в аккуратный набор данных (целевой tibble в примере кода). Список состоит из 5 элементов, каждый из которых, как предполагается, представляет страницу в форме заявки. Каждый элемент представляет собой одну строку.
-
Из первого элемента я хочу извлечь информацию, относящуюся к числу слов и организации.
-
Между словами 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
:name: *
совпадениеname:
, за которым следует любое количество пробелов.([^\r\n] ?)
захватите один или несколько символов, которые отличаются от возврата кареткиr
и новой строкиr
,?
квантификатор должен соответствовать минимально возможному количеству символов, т.е. в терминах регулярных выражений\r\n.*?
сопоставьте литералrn
и.*?
любое количество символов как можно меньше.([^\r\n] ?)\r\n
захват …. затем сопоставьте литералrn
.
Комментарии:
1. Я искренне благодарен. Я не понимаю всех регулярных выражений. я, конечно, изучу это более глубоко, но если это не слишком сложно для вас, не могли бы вы рассказать мне, что происходит? Почему вы сделали это в виде строки, а не списка? Имеет ли строка какие-либо преимущества в этом случае?
2. @Henrik Я добавил пояснения и упростил код. Я сделал это строкой, чтобы я мог получать данные между start и stop, а также потому, что третье имя содержало информацию на другой странице. Так проще манипулировать строкой. также, если у вас есть несколько запусков и остановок в одном файле, я могу приспособиться к этому.
3. Я думаю, что я следую регулярному выражению. Весело! Я, конечно, столкнулся с новой проблемой, потому что мне нужно собрать мои реальные данные в одну строку, подобную той, которую вы использовали. Pdf_text возвращает список с одной строкой на страницу. Один элемент — это целая страница.
4. если он возвращает список, вы можете превратить его в вектор, используя
unlist(ur.lst)
5.
paste0(ur.lst, collapse="")
чтобы сделать его одной строкой