如何改进此代码?使用正则表达式提取信息

时间:2019-06-19 21:47:33

标签: r regex

我有这个数据帧,并且正在尝试提取一些数据,我实际上没有问题,但是我觉得应该有一个更好/更优雅的方法来实现它。

所以,我有这个字符串

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 个答案:

答案 0 :(得分:1)

通过将输入转换为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)

答案 1 :(得分:0)

您可以对PCRE regex使用regmatches / regexpr方法,该方法将在已知的“前缀”之后提取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 demo

正则表达式详细信息

  • _MUN=-_MUN文字
  • \K-匹配重置运算符,该运算符会丢弃到目前为止已匹配的文本
  • \d+-1个以上的数字。

使用perl=TRUE对于正则表达式的工作至关重要。

等效于stringr

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

后面的(?<=...)正向外观仅检查当前位置左侧的模式匹配项,但不使用文本,即不将其放入匹配值。

第2列和第3列是一个花哨的解决方案,其中stringr::str_match一目了然地捕获了结果。

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"

答案 2 :(得分:0)

绝对看看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

答案 3 :(得分:0)

This answer效率低下。在这里,也许,我们只使用[0-9]而不是\d,这在时间和空间复杂性方面的表现可能微不足道,我只是猜测,就像您提到的那样,当我们使用正则表达式时,原始表达式就很好,通常不建议环顾四周,也不建议使用其他任何奇特的方法。

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

Demo

我很确定应该有其他方法来改进我们希望在此处完成的工作,但是关键是,您的原始表达已经在走正确的道路,但也许不是正确的道路,为此我们可能需要权衡所期望的优雅的原因。

请在评论中查看其他视图,我只是在参考,这里实际上没有任何意见/建议,即使听起来可能不是这样。

参考文献