grep, використовуючи векторний символ із кількома візерунками


132

Я намагаюся використовувати, grepщоб перевірити, чи присутній вектор струн в іншому векторі чи ні, і вивести значення, які є в наявності (відповідні шаблони).

У мене є такий кадр даних:

FirstName Letter   
Alex      A1
Alex      A6
Alex      A7
Bob       A1
Chris     A9
Chris     A6

У мене є вектор шаблонів рядків можна знайти в шпальтах «Letter», наприклад: c("A1", "A9", "A6").

Я хотів би перевірити, чи присутній якийсь із рядків у векторі візерунка у стовпці "Буква". Якщо вони є, я хотів би отримати унікальні значення.

Проблема полягає в тому, що я не знаю, як використовувати grepдекілька моделей. Я намагався:

matches <- unique (
    grep("A1| A9 | A6", myfile$Letter, value=TRUE, fixed=TRUE)
)

Але це дає мені 0 збігів, що не відповідає дійсності, будь-які пропозиції?


3
Ви не можете використовувати, fixed=TRUEтому що ви малюєте справжній регулярний вираз.
Марек

6
Використання matchабо %in%навіть ==є тільки правильним способом для порівняння точних збігів. Регекс дуже небезпечний для такого завдання і може призвести до несподіваних результатів.
Девід Аренбург

Відповіді:


269

Окрім коментаря @ Marek про невключення fixed==TRUE, вам також не повинно бути пробілів у регулярному виразі. Це повинно бути "A1|A9|A6".

Ви також згадуєте, що моделей багато. Якщо припустити, що вони перебувають у векторі

toMatch <- c("A1", "A9", "A6")

Тоді ви можете створити свій регулярний вираз безпосередньо за допомогою pasteі collapse = "|".

matches <- unique (grep(paste(toMatch,collapse="|"), 
                        myfile$Letter, value=TRUE))

Будь-який спосіб це зробити, коли ваш список рядків містить оператори регулярних виразів як розділові знаки?
користувач124123

@ user1987097 Це має працювати так само, з іншими операторами регулярних виразів або без них. У вас був конкретний приклад, для якого це не працювало?
Брайан Діггс

@ user1987097 використовуйте 2 зворотні риски перед крапкою або дужкою. Перша зворотна косою рисою є символом втечі для інтерпретації другого, необхідного для відключення оператора.
mbh86

3
Використання регулярного вираження для точних відповідностей мені здається небезпечним і може мати несподівані результати. Чому б не просто toMatch %in% myfile$Letter?
Девід Аренбург

@ user4050 Немає конкретних причин. Версія у питанні мала її, і я, мабуть, просто переніс її, не замислюючись про те, чи потрібно це.
Брайан Діггс

34

Хороші відповіді, проте не забувайте про filter()dplyr:

patterns <- c("A1", "A9", "A6")
>your_df
  FirstName Letter
1      Alex     A1
2      Alex     A6
3      Alex     A7
4       Bob     A1
5     Chris     A9
6     Chris     A6

result <- filter(your_df, grepl(paste(patterns, collapse="|"), Letter))

>result
  FirstName Letter
1      Alex     A1
2      Alex     A6
3       Bob     A1
4     Chris     A9
5     Chris     A6

3
Я думаю, що greplпрацює з одним малюнком одночасно (нам потрібен вектор з довжиною 1), у нас є 3 візерунки (вектор довжини 3), тому ми можемо поєднати їх з одним, використовуючи дружній для розділення grepl - |спробуйте свою удачу з іншими :)
Адамм

3
ой, я зрозумію це зараз. Тож його стиснення дозволяє вивести щось на зразок A1 | A2, тож якби хотіли всі умови, то згортання було б зі знаком &, прикольне спасибі
Ahdee

1
Привіт, використовуючи )|(для окремих моделей може зробити це більш надійним: paste0("(", paste(patterns, collapse=")|("),")"). На жаль, він стає також трохи менш елегантним. Це призводить до викрійки (A1)|(A9)|(A6).
fabern

14

Це має працювати:

grep(pattern = 'A1|A9|A6', x = myfile$Letter)

Або ще простіше:

library(data.table)
myfile$Letter %like% 'A1|A9|A6'

11
%like%не знаходиться в базі R, тому вам слід згадати, який пакет (и) потрібні для його використання.
Грегор Томас

1
Для інших, хто дивиться на цю відповідь, %like%є частиною data.tableпакету. Крім того, схоже на data.tableце like(...), %ilike%і %flike%.
steveb

8

На основі публікації Брайана Дігга, ось дві корисні функції для фільтрації списків:

#Returns all items in a list that are not contained in toMatch
#toMatch can be a single item or a list of items
exclude <- function (theList, toMatch){
  return(setdiff(theList,include(theList,toMatch)))
}

#Returns all items in a list that ARE contained in toMatch
#toMatch can be a single item or a list of items
include <- function (theList, toMatch){
  matches <- unique (grep(paste(toMatch,collapse="|"), 
                          theList, value=TRUE))
  return(matches)
}

5

Ви спробували match()або charmatch()функції?

Приклад використання:

match(c("A1", "A9", "A6"), myfile$Letter)

1
Варто зазначити одне match, що він не використовує шаблони, він очікує точної відповідності.
steveb

5

Не впевнений, чи вже з’явилася ця відповідь ...

Для конкретного шаблону запитання ви можете це зробити за допомогою одного grep()дзвінка,

grep("A[169]", myfile$Letter)

4

Щоб додати відповідь Брайана Діггса.

інший спосіб використання grepl поверне кадр даних, що містить усі ваші значення.

toMatch <- myfile$Letter

matches <- myfile[grepl(paste(toMatch, collapse="|"), myfile$Letter), ]

matches

Letter Firstname
1     A1      Alex 
2     A6      Alex 
4     A1       Bob 
5     A9     Chris 
6     A6     Chris

Може, трохи чистіше ... можливо?


2

Забирайте простори. То роби:

matches <- unique(grep("A1|A9|A6", myfile$Letter, value=TRUE, fixed=TRUE))

1

Використання sapply

 patterns <- c("A1", "A9", "A6")
         df <- data.frame(name=c("A","Ale","Al","lex","x"),Letters=c("A1","A2","A9","A1","A9"))



   name Letters
1    A      A1
2  Ale      A2
3   Al      A9
4  lex      A1
5    x      A9


 df[unlist(sapply(patterns, grep, df$Letters, USE.NAMES = F)), ]
  name Letters
1    A      A1
4  lex      A1
3   Al      A9
5    x      A9

-1

Я пропоную написати невеликий сценарій та здійснити кілька пошукових запитів із Грепом. Я ніколи не знаходив способу пошуку кількох шаблонів, і повірте, я шукав!

Так, ваш файл оболонки із вбудованим рядком:

 #!/bin/bash 
 grep *A6* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
 grep *A7* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
 grep *A8* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";

Потім запустіть, ввівши myshell.sh.

Якщо ви хочете передати рядок у командному рядку, зробіть це так, з аргументом оболонки - це bash notation btw:

 #!/bin/bash 
 $stingtomatch = "${1}";
 grep *A6* "${stingtomatch}";
 grep *A7* "${stingtomatch}";
 grep *A8* "${stingtomatch}";

І так далі.

Якщо є багато шаблонів, які можуть відповідати, ви можете помістити їх у цикл for.


Дякую, ChrisBean Шаблонів насправді багато, і, можливо, було б краще використовувати файл тоді. Я новачок у BASH, але, можливо, щось подібне повинно працювати ... #! / Bin / bash for i в 'pattern.txt' do echo $ ij = 'grep -c "$ {i}" myfile.txt' echo $ j якщо [$ j -eq o], то відлуння $ i >> match.txt fi зроблено
user971102

не працює ... повідомлення про помилку: "[grep: команда не знайдена" ... у мене папка в / bin папці, і / bin знаходиться в моєму $ PATH ... Не впевнений, що відбувається ... Чи можете ви допомогти?
user971102
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.