stringr: извлечь слова, содержащие определенное слово

Рассмотрим этот простой пример

dataframe <- data_frame(text = c('WAFF;WOFF;WIFF200;WIFF12',
                                 'WUFF;WEFF;WIFF2;BIGWIFF'))

> dataframe
# A tibble: 2 x 1
                      text
                     <chr>
1 WAFF;WOFF;WIFF200;WIFF12
2  WUFF;WEFF;WIFF2;BIGWIFF

Здесь я хочу извлечь слова, содержащие WIFF, то есть я хочу получить такой кадр данных

> output
# A tibble: 2 x 1
            text
           <chr>
1 WIFF200;WIFF12
2  WIFF2;BIGWIFF

я пытался использовать

dataframe %>% 
  mutate( mystring = str_extract(text, regex('\bwiff\b', ignore_case=TRUE)))

но это только перенастраивает NA. Любые идеи?

Спасибо!


person ℕʘʘḆḽḘ    schedule 18.07.2017    source источник


Ответы (2)


Кажется, вы хотите удалить все слова, содержащие WIFF и конечный ;, если они есть. Использовать

> dataframedataframe <- data.frame(text = c('WAFF;WOFF;WIFF200;WIFF12', 'WUFF;WEFF;WIFF2;BIGWIFF'))
> dataframe$text <- str_replace_all(dataframe$text, "(?i)\\b(?!\\w*WIFF)\\w+;?", "")
> dataframe
            text
1 WIFF200;WIFF12
2  WIFF2;BIGWIFF

Шаблон (?i)\\b(?!\\w*WIFF)\\w+;? соответствует:

  • (?i) — встроенный модификатор без учета регистра.
  • \\b - граница слова
  • (?!\\w*WIFF) - отрицательный просмотр вперед не соответствует ни одному совпадению, если слово содержит WIFF где-либо внутри него.
  • \\w+ - 1 или более символов слова
  • ;? - необязательный ; (? соответствует 1 или 0 вхождениям шаблона, который он изменяет)

Если по какой-то причине вы хотите использовать str_extract, обратите внимание, что ваше регулярное выражение не может работать, потому что \bWIFF\b соответствует целому слову WIFF и ничего больше. У вас нет таких слов в вашем ДФ. Вы можете использовать "(?i)\\b\\w*WIFF\\w*\\b" для сопоставления любых слов с WIFF внутри (без учета регистра) и использовать str_extract_all для получения несколько вхождений и не забудьте объединить совпадения в одну «строку»:

> df <- data.frame(text = c('WAFF;WOFF;WIFF200;WIFF12', 'WUFF;WEFF;WIFF2;BIGWIFF'))
> res <- str_extract_all(df$text, "(?i)\\b\\w*WIFF\\w*\\b")
> res
[[1]]
[1] "WIFF200" "WIFF12" 

[[2]]
[1] "WIFF2"   "BIGWIFF"

> df$text <- sapply(res, function(s) paste(s, collapse=';'))
> df
            text
1 WIFF200;WIFF12
2  WIFF2;BIGWIFF

Вы можете «сжать» код, поместив str_extract_all в функцию sapply, я разделил их для лучшей видимости.

person Wiktor Stribiżew    schedule 18.07.2017
comment
спасибо Виктор очень приятно. Вы, кажется, подразумеваете, что легче заменить несовпадающие шаблоны, чем извлекать совпадающие? Зачем? - person ℕʘʘḆḽḘ; 18.07.2017
comment
@Noobie: я этого не говорил. Вам решать, что проще. - person Wiktor Stribiżew; 18.07.2017
comment
Я имею в виду, что ваше решение отличное, но знаете ли вы, что мой str_extract вообще не работает? - person ℕʘʘḆḽḘ; 18.07.2017
comment
@Noobie: Моя логика проста: если ваши векторы символов содержат строки со словами, которые не обязательно имеют WIFF внутри, подход сопоставления означает разделение/извлечение или сопоставление всех допустимых вхождений, а затем их обратное соединение. Мне это кажется громоздким (хотя это не то, о чем я думал, когда писал ответ). Ваш подход не сработает, поскольку \bWIFF\b соответствует целому слову WIFF и ничему другому. У вас нет таких слов в вашем ДФ. - person Wiktor Stribiżew; 18.07.2017
comment
Ок понял спасибо. вы видите здесь простой способ использовать str_extract? Просто пытаюсь изучить некоторые навыки регулярных выражений здесь :) - person ℕʘʘḆḽḘ; 18.07.2017
comment
Я забыл сделать шаблон нечувствительным к регистру, добавил этот бит сейчас. - person Wiktor Stribiżew; 18.07.2017

Классический подход без регулярных выражений через базу R:

sapply(strsplit(me$text, ';', fixed = TRUE), function(i) 
                              paste(grep('WIFF', i, value = TRUE, fixed = TRUE), collapse = ';'))

#[1] "WIFF200;WIFF12" "WIFF2;BIGWIFF" 
person Sotos    schedule 18.07.2017