R grep: сопоставить одну строку с несколькими шаблонами
В R grep обычно соответствует вектору нескольких строк в отношении одного регулярного выражения.
В: Есть ли возможность сопоставить одну строку с несколькими регулярными выражениями? (без прокрутки по каждому шаблону регулярного выражения)?
Некоторая предыстория:
У меня есть 7000+ ключевых слов в качестве индикаторов для нескольких категорий. Я не могу изменить словарь ключевых слов. Словарь имеет следующую структуру (ключевые слова в столбце 1, номера указывают категории, к которым относятся эти ключевые слова):
ab 10 37 41
abbrach* 38
abbreche 39
abbrich* 39
abend* 37
abendessen* 60 63
aber 20 23 45
abermals 37
Объединение так много ключевых слов с помощью "|" не является возможным (и я не знаю, какой из ключевых слов сгенерировал хит).
Кроме того, просто реверсирование "шаблонов" и "строк" не работает, поскольку у шаблонов есть усечения, которые не будут работать наоборот.
[связанный вопрос, другой язык программирования]
Ответы
Ответ 1
Как насчет применения функции regexpr над вектором ключевых слов?
keywords <- c("dog", "cat", "bird")
strings <- c("Do you have a dog?", "My cat ate by bird.", "Let get icecream!")
sapply(keywords, regexpr, strings, ignore.case=TRUE)
dog cat bird
[1,] 15 -1 -1
[2,] -1 4 15
[3,] -1 -1 -1
sapply(keywords, regexpr, strings[1], ignore.case=TRUE)
dog cat bird
15 -1 -1
Возвращаемые значения - это позиция первого символа в матче, при этом -1
не означает совпадения.
Если позиция совпадения не имеет значения, вместо этого используйте grepl
:
sapply(keywords, grepl, strings, ignore.case=TRUE)
dog cat bird
[1,] TRUE FALSE FALSE
[2,] FALSE TRUE TRUE
[3,] FALSE FALSE FALSE
Обновление:. Это довольно быстро работает в моей системе, даже с большим количеством ключевых слов:
# Available on most *nix systems
words <- scan("/usr/share/dict/words", what="")
length(words)
[1] 234936
system.time(matches <- sapply(words, grepl, strings, ignore.case=TRUE))
user system elapsed
7.495 0.155 7.596
dim(matches)
[1] 3 234936
Ответ 2
Чтобы перейти к другому ответу, чтобы преобразовать вывод sapply()
в полезный логический вектор, вам нужно дополнительно использовать шаг apply()
.
keywords <- c("dog", "cat", "bird")
strings <- c("Do you have a dog?", "My cat ate by bird.", "Let get icecream!")
(matches <- sapply(keywords, grepl, strings, ignore.case=TRUE))
# dog cat bird
# [1,] TRUE FALSE FALSE
# [2,] FALSE TRUE TRUE
# [3,] FALSE FALSE FALSE
Чтобы узнать, какие строки содержат какие-либо ключевые слова (шаблоны):
apply(matches, 1, any)
# [1] TRUE TRUE FALSE
Чтобы узнать, какие ключевые слова (шаблоны) были сопоставлены в прилагаемых строках:
apply(matches, 2, any)
# dog cat bird
# TRUE TRUE TRUE
Ответ 3
Пакет re2r
может соответствовать нескольким шаблонам (параллельно). Минимальный пример:
# compile patterns
re <- re2r::re2(keywords)
# match strings
re2r::re2_detect(strings, re, parallel = TRUE)