разбить строку, зная некоторые из подстрок - PullRequest
4 голосов
/ 11 апреля 2019

Скажем, у меня есть следующая строка и вектор подстрок:

x <- "abc[[+de.f[-[[g"
v <- c("+", "-", "[", "[[")

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

res <- c("abc", "[[", "+", "de.f", "[", "-", "[[", "g")

В случае конфликтующих совпадений более длинные выигрыши (здесь [[ более [), вы можете считать, что не будет конфликтующих совпадений одинаковой длины.

Пометка с помощью regex, но она открыта для любого решения, быстрее - лучше.

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


другой пример:

x <- "a*bc[[+de.f[-[[g[*+-h-+"
v <- c("+", "-", "[", "[[", "[*", "+-")
res <- c("a*bc", "[[", "+", "de.f", "[", "-", "[[", "g", "[*", "+-", "h", "-", "+")

Ответы [ 4 ]

2 голосов
/ 11 апреля 2019

Использование stringr::str_match_all и Hmisc::escapeRegex:

x <- "abc[[+de.f[-[[g"
v <- c("+", "-", "[", "[[")
tmp <- v[order(-nchar(v))] # sort to have longer first, to match in priority
tmp <- Hmisc::escapeRegex(tmp)
tmp <- paste(tmp,collapse="|")  # compile a match string
pattern <- paste0(tmp,"|(.+?)") # add a pattern to match the rest
# extract all matches into a matrix
mat <- stringr::str_match_all(op_chr, pattern)[[1]]
# aggregate where second column is NA
res <- unname(tapply(mat[,1], 
                     cumsum(is.na(mat[,2])) + c(0,cumsum(abs(diff(is.na(mat[,2]))))),
                     paste, collapse=""))
res
#> [1] "abc"  "[["   "+"    "de.f" "["    "-"    "[["   "g"
2 голосов
/ 11 апреля 2019

Это больше похоже на проблему лексизма, чем на проблему соответствия. Кажется, я получаю приличные результаты с пакетом minilexer

library(minilexer) #devtools::install_github("coolbutuseless/minilexer")

patterns <- c(
  dbracket  = "\\[\\[", 
  bracket   = "\\[",
  plus      = "\\+",
  minus     = "\\-",
  name      = "[a-z.]+"
)

x <- "abc[[+de.f[-[[g"
lex(x, patterns)
unname(lex(x, patterns))
# [1] "abc"  "[["   "+"    "de.f" "["    "-"   
# [7] "[["   "g" 
1 голос
/ 11 апреля 2019

Чистое решение на основе регулярных выражений будет выглядеть как

x <- "abc[[+de.f[-[[g"
v <- c("+", "-", "[", "[[")

## Escaping function
regex.escape <- function(string) {
  gsub("([][{}()+*^$|\\\\?])", "\\\\\\1", string)
}
## Sorting by length in the descending order function
sort.by.length.desc <- function (v) v[order( -nchar(v)) ]

pat <- paste(regex.escape(sort.by.length.desc(v)), collapse="|")
pat <- paste0("(?s)", pat, "|(?:(?!", pat, ").)+")
res <- regmatches(x, gregexpr(pat, x, perl=TRUE))
## => [[1]]
##    [1] "abc"  "[["   "+"    "de.f" "["    "-"    "[["   "g"

См. R демо онлайн . Регулярное выражение PCRE здесь

(?s)\[\[|\+|-|\[|(?:(?!\[\[|\+|-|\[).)+

См. Демонстрационный пример регулярных выражений и график Regulex:

enter image description here

Детали

  • (?s) - модификатор DOTALL, который . соответствует любому символу, включая переводы строки
  • \[\[ - [[ подстрока (экранированная regex.escape)
  • | - или
  • \+ - +
  • |- - или - (не нужно экранировать -, поскольку он не находится внутри класса символов)
  • |\[ - или [
  • | - или
  • (?:(?!\[\[|\+|-|\[).)+ - жадный жетон , который соответствует любому символу (.), 1 или более повторений как можно больше (+ в конце), который не запускается aa [[, +, - или [ последовательности символов (узнайте больше о жадном жетоне ).

Вы также можете рассмотреть решение с менее интенсивным регулярным выражением с помощью регулярного выражения TRE:

x <- "abc[[+de.f[-[[g"
v <- c("+", "-", "[", "[[")

## Escaping function
regex.escape <- function(string) {
  gsub("([][{}()+*^$|\\\\?])", "\\\\\\1", string)
}
## Sorting by length in the descending order function
sort.by.length.desc <- function (v) v[order( -nchar(v)) ]
## Interleaving function
riffle3 <- function(a, b) { 
  mlab <- min(length(a), length(b)) 
  seqmlab <- seq(length=mlab) 
  c(rbind(a[seqmlab], b[seqmlab]), a[-seqmlab], b[-seqmlab]) 
} 
pat <- paste(regex.escape(sort.by.length.desc(v)), collapse="|")
res <- riffle3(regmatches(x, gregexpr(pat, x), invert=TRUE)[[1]], regmatches(x, gregexpr(pat, x))[[1]])
res <- res[res != ""]
## => [1] "abc"  "[["   "+"    "de.f" "["    "-"    "[["   "g"   

См. Демоверсию R .

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

1 голос
/ 11 апреля 2019

Один из вариантов получения ваших матчей может быть для нас чередование :

[a-z.]+|\[+|[+-]
  • [a-z.]+ Совпадение 1+ раз a-z или точка
  • | или
  • \[+ совпадение 1+ раз [
  • | `или
  • [+-] Совпадение + или -

Regex demo | R демо

Например, чтобы получить совпадения:

library(stringr)
x <- "abc[[+de.f[-[[g"
str_extract_all(x, "[a-z.]+|\\[+|[+-]")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...