R: Regex Madness (Стринги)

У меня есть вектор строк, которые выглядят так:

G30(H).G3(M).G0(L).Replicate(1)

Перебирая c("H", "M", "L")Я хотел бы извлечь G30 (за "H"), G3 (за "M") а также G0 (за "L").

Мои различные попытки запутали меня - regex101.com например, отладчик указывает, что (\w*)\(M\) работает просто отлично, но передать это в R не удается...

5 ответов

Решение

С использованием stringi пакет и outer() функция:

library(stringi)

strings <- c(
  "G30(H).G3(M).G0(L).Replicate(1)",
  "G5(M).G11(L).G6(H).Replicate(9)",
  "G10(M).G6(H).G8(M).Replicate(200)"  # No "L", repeated "M"
)
targets  <- c("H", "M", "L")
patterns <- paste0("\\w+(?=\\(", targets, "\\))")
matches  <- outer(strings, patterns, FUN = stri_extract_first_regex)
colnames(matches) <- targets
matches
#      H     M    L    
# [1,] "G30" "G3" "G0" 
# [2,] "G6"  "G5" "G11"
# [3,] "G6"  "G10" NA

Это игнорирует любые случаи целевой буквы после первого, дает вам NA когда цель не найдена, и возвращает все в простой матрице. Регулярные выражения хранятся в patterns сопоставлять подстроки как XX(Y), где Y является целевой буквой и XX любое количество символов слова.

Если порядок всегда один и тот же, альтернативой может быть разделение строк. Например:

string <- "G30(H).G3(M).G0(L).Replicate(1)"
tmp <- str_split(string, "\\.")[[1]]
lapply(tmp[1:3], function(x) str_split(x, "\\(")[[1]][1])
[[1]]
[1] "G30"

[[2]]
[1] "G3"

[[3]]
[1] "G0"

Я собираюсь предположить, что функции (G...) являются переменными, а входные данные являются переменными. Это предполагает, что ваши функции начинаются с буквы G, а ваш ввод всегда является буквой.

parse = function(arb){
  tmp = stringi::stri_extract_all_regex(arb,"G.*?\\([A-Z]\\)")[[1]]
  unlist(lapply(lapply(tmp,strsplit,"\\)|\\("),function(x){
    output = x[[1]][1]
    names(output) = x[[1]][2]
    return(output)
  }))
}

Сначала анализируются все функции G с их входами. Затем каждый из них разделяется на свою функциональную часть и входную часть. Это вставка в символьный вектор функций, названных для их ввода.

parse("G30(H).G3(M).G0(L).Replicate(1)")
>     H     M     L 
  "G30"  "G3"  "G0"

Или же

parse("G35(L).G31(P).G02(K).Replicate(1)")
>     L     P     K 
  "G35" "G31" "G02" 

Если коды (например, "G30"), предшествующие тегам (например, "(H).") Или порядок тегов в строке, могут быть изменены (разные буквы или длина), вы можете попробовать более гибкий решение на основе regexpr ().

aa <-paste("G30(H).G3(M).G0(L).Replicate(",1:10,")", sep="")
my.tags <- c("H","M", "L")

extr.data <- lapply(my.tags, (function(tag){
  pat <-  paste("\\(", tag, "\\)\\.", sep="")
  pos <- regexpr(paste("(^|\\.)([[:alnum:]])*", pat ,sep=""), aa)
  out <- substr(aa, pos, (pos+attributes(pos)$match.length - 4 - length(tag)))  
  gsub("(^\\.)", "", out) 
}))
names(extr.data) <- my.tags
extr.data

Я уверен, что есть лучшие решения, но это работает...

jnk <- 'G30(H).G3(M).G0(L).Replicate(1)'
patter <- '([^\\(]+)\\(H\\)\\.([^\\(]+)\\(M\\)\\.([^\\(]+)\\(L\\)\\.Replicate\\(\\d+\\)'
H <- sub(patter, '\\1', jnk)
M <- sub(patter, '\\2', jnk)
L <- sub(patter, '\\3', jnk)

РЕДАКТИРОВАТЬ:

На самом деле, я нашел один раз очень хорошую функцию parse.one что позволяет искать больше в питоне, как способ регулярного выражения...

Посмотри на это:

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
}
jnk <- 'G30(H).G3(M).G0(L).Replicate(1)'
pattern <- '(?<H>[^\\(]+)\\(H\\)\\.(?<M>[^\\(]+)\\(M\\)\\.(?<L>[^\\(]+)\\(L\\)\\.Replicate\\(\\d+\\)'
parse.one(jnk, regexpr(pattern, jnk, perl=TRUE))

Результат выглядит так:

> parse.one(jnk, regexpr(pattern, jnk, perl=TRUE))
     H     M    L   
[1,] "G30" "G3" "G0"
Другие вопросы по тегам