使用R中的正则表达式从字符串中提取信息

时间:2015-04-16 06:39:11

标签: regex r

我搜索了堆栈溢出了一点,我发现的是,与Perl或Python相比,R中的正则表达式有点棘手且不方便。

我的问题如下。我的文件名很长,里面有信息。看起来如下:

20150416_QEP1_EXT_GR_1234_hs_IP_NON_060.raw
20150416_QEP1_EXT_GR_1234-1235_hs_IP_NON_060.raw
20150416_QEP1_EXT_GR_1236_hs_IP_NON_060_some_other_info.raw
20150416_QEP1_EXT_GR_1237_hs_IP_NON_060

我想从文件名中提取部分并将它们方便地转换为值,例如第一部分是日期,第二部分是机器缩写,下一部分是缩写,组缩写,样本编号等。 ..

我现在所做的是构建一个正则表达式,使(几乎)确定,我grep正确的字符串部分:

regex <- '([:digit:]{8})_([:alnum:]{1,4})_([:upper:]+)_ etc'

然后我使用sub将每个剪切保存到变量中:

date <- sub(regex, '\\1', filename)
machine <- sub(regex, '\\2', filename)
etc

如果文件名具有正确的约定,则此方法有效。这总体上很难阅读,我正在寻找一种更方便的工作方式。我想过用_分割文件名并通过索引访问字符串可能是一个很好的解决方案。但有时,由于文件名通常是手工创建的,因此名称中缺少术语或其他信息,我正在寻找更好的解决方案。

有人能建议更好的方法吗?

修改

我想要创建的是一个对象,它具有提取和访问的文件名的所有信息......例如my_object$machine左右......

1 个答案:

答案 0 :(得分:1)

?regex的帮助页面实际上提供的示例与Python的re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")完全相同(根据您的评论):

## named capture
notables <- c("  Ben Franklin and Jefferson Davis",
              "\tMillard Fillmore")
#name groups 'first' and 'last'
name.rex <- "(?<first>[[:upper:]][[:lower:]]+) (?<last>[[:upper:]][[:lower:]]+)"
(parsed <- regexpr(name.rex, notables, perl = TRUE))
gregexpr(name.rex, notables, perl = TRUE)[[2]]
parse.one <- function(res, result) {
  m <- do.call(rbind, lapply(seq_along(res), function(i) {
    if(result[i] == -1) return("")
    st <- attr(result, "capture.start")[i, ]
    substring(res[i], st, st + attr(result, "capture.length")[i, ] - 1)
  }))
  colnames(m) <- attr(result, "capture.names")
  m
}
parse.one(notables, parsed)

从字符串中提取的正常方式(即R方式)如下:

text <- "Malcolm Reynolds"
x <- gregexpr("\\w+", text) #Don't forget to escape the backslash
regmatches(text, x)
[[1]]
[1] "Malcolm"  "Reynolds"

您可以使用参数perl=TRUE

来使用Perl样式的组命名
regexpr("(?P<first_name>\\w+) (?P<last_name>\\w+)", text, perl=TRUE)

但是regmatches不支持它,因此需要创建自己的函数来处理它,这在帮助页面中给出:

parse.one <- function(res, result) {
       m <- do.call(rbind, lapply(seq_along(res), function(i) {
         if(result[i] == -1) return("")
         st <- attr(result, "capture.start")[i, ]
         substring(res[i], st, st + attr(result, "capture.length")[i, ] - 1)
       }))
       colnames(m) <- attr(result, "capture.names")
       m
     }

应用于您的示例:

 text <- "Malcolm Reynolds"
 x <- regexpr("(?P<first_name>\\w+) (?P<last_name>\\w+)", text, perl=TRUE)
 parse.one(text, x)
     first_name last_name 
[1,] "Malcolm"  "Reynolds"

回到最初的问题:

filenames <- c("20150416_QEP1_EXT_GR_1234_hs_IP_NON_060.raw", "20150416_QEP1_EXT_GR_1234-1235_hs_IP_NON_060.raw", "20150416_QEP1_EXT_GR_1236_hs_IP_NON_060_some_other_info.raw", "20150416_QEP1_EXT_GR_1237_hs_IP_NON_060")
regex <- '(?P<date>[[:digit:]]{8})_(?P<machine>[[:alnum:]]{1,4})_(?P<whatev>[[:upper:]]+)'
x <- regexpr(regex,filenames,perl=TRUE)
parse.one(filenames,x)
     date       machine whatev
[1,] "20150416" "QEP1"  "EXT" 
[2,] "20150416" "QEP1"  "EXT" 
[3,] "20150416" "QEP1"  "EXT" 
[4,] "20150416" "QEP1"  "EXT"