Как улучшить этот код? Извлечение информации с помощью Regex - PullRequest
2 голосов
/ 20 июня 2019

У меня есть этот фрейм данных с некоторыми данными, которые я пытаюсь извлечь, на самом деле у меня нет проблем, но я чувствую, что должен быть лучший / более элегантный способ сделать это.

Итак, у меня есть эта строка

CVEGEO=0901500011337<BR>CVE_ENT=09<BR>CVE_MUN=015<BR>CVE_LOC=0001<BR>CVE_AGEB=1337<BR>

136 раз, и я заинтересован в MUN=(.*) and AGEB=(.*)

Для получения информации я использую:

test1 <- sub(".*_MUN=(.*)<BR>CVE_LOC=0001<BR>CVE_AGEB=(.*)<.*", "\\1_\\2", L1_AGEB$description)
str_split_fixed(test1, "_", 2)

И это работает просто отлично, но, как я уже сказал, и это только для академических целей / для улучшения Есть ли более простой / элегантный способ?

Спасибо

Ответы [ 4 ]

1 голос
/ 20 июня 2019

Мы можем полностью проанализировать весь ввод, преобразовав его в формат DCF. Это дает преимущество в том, что любое из полей может быть легко извлечено впоследствии.

Предполагая ввод x, показанный в примечании в конце, мы можем заменить <BR> на новую строку и заменить = на двоеточие, а затем прочитать то, что осталось, используя read.dcf. Пакеты не используются.

x2 <- gsub("=", ":", gsub("<BR>", "\n", x))
read.dcf(textConnection(x2))

дает эту матрицу символов:

     CVEGEO          CVE_ENT CVE_MUN CVE_LOC CVE_AGEB
[1,] "0901500011337" "09"    "015"   "0001"  "1337"  
[2,] "0901500011337" "09"    "015"   "0001"  "1337"  
[3,] "0901500011337" "09"    "015"   "0001"  "1337"  

Вариант этого с использованием пакета magrittr будет:

library(magrittr)
x %>%
  gsub("<BR>", "\n", .) %>%
  gsub("=", ":", .) %>%
  textConnection %>%
  read.dcf

Примечание

x <- "CVEGEO=0901500011337<BR>CVE_ENT=09<BR>CVE_MUN=015<BR>CVE_LOC=0001<BR>CVE_AGEB=1337<BR>"
x <- rep(x, 3)
0 голосов
/ 20 июня 2019

Определенно посмотрите на пакет rex, у него есть кривая обучения, но это может быть довольно изящно:

library(rex)

rex::re_matches("CVEGEO=0901500011337<BR>CVE_ENT=09<BR>CVE_MUN=015<BR>CVE_LOC=0001<BR>CVE_AGEB=1337<BR>",
                pattern = rex::rex(
                  "MUN=",
                  capture(any_numbers, name = "MUN"),
                  anything,
                  "AGEB=",
                  capture(any_numbers, name = "AGEB")
                ))
  MUN AGEB
1 015 1337
0 голосов
/ 20 июня 2019

Этот ответ неэффективен. Здесь, может быть, мы просто использовали бы [0-9] вместо \d, который мог бы незначительно лучше работать в отношении временных и пространственных сложностей, что я просто догадываюсь, и, как вы упомянули, ваше оригинальное выражение просто хорошо, lookaround обычно не рекомендуется, как и любые другие причудливые методы, когда мы работаем с регулярными выражениями.

MUN=([0-9]+).+AGEB=([0-9]+)

Демо

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

Пожалуйста, смотрите другие мнения в комментариях, и я только ссылаюсь, на самом деле здесь нет своего мнения / рекомендации, хотя это может звучать иначе.

Ссылки

0 голосов
/ 20 июня 2019

Вы можете использовать подход regmatches / regexpr с регулярным выражением PCRE, которое извлечет 1+ цифр после известных "префиксов":

x <- "CVEGEO=0901500011337<BR>CVE_ENT=09<BR>CVE_MUN=015<BR>CVE_LOC=0001<BR>CVE_AGEB=1337<BR>"
regmatches(x, regexpr("_MUN=\\K\\d+", x, perl=TRUE))
## => [1] "015"
regmatches(x, regexpr("_AGEB=\\K\\d+", x, perl=TRUE))
## => [1] "1337"

См. Демонстрационную версию R online.

Сведения о регулярном выражении

  • _MUN= - _MUN текст
  • \K - оператор сброса совпадений, который сбрасываеттекст соответствует
  • \d+ - 1+ цифр.

Использование perl=TRUE крайне важно для работы регулярного выражения.

Эквивалентное использованиеstringr:

library(stringr)
str_extract(x, "(?<=_MUN=)\\d+")
str_extract(x, "(?<=_AGEB=)\\d+")

Положительный обзор (?<=...) только проверяет совпадение с шаблоном непосредственно слева от текущего местоположения, но не использует текст, т.е. не помещает его в значение совпадения.

И причудливое решение с stringr::str_match захватом результатов в один заход в столбцы 2 и 3:

library(stringr)
str_match(x, "_MUN=(\\d+).*_AGEB=(\\d+)")
#      [,1]                                        [,2]  [,3]  
# [1,] "_MUN=015<BR>CVE_LOC=0001<BR>CVE_AGEB=1337" "015" "1337"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...