複数のパターンを持つ文字ベクトルを使用するgrep


132

grep文字列のベクトルが別のベクトルに存在するかどうかをテストし、存在する値(一致するパターン)を出力するために使用しようとしています。

私はこのようなデータフレームを持っています:

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

「文字」列にある文字列パターンのベクトルがありますc("A1", "A9", "A6")。例:

パターンベクトルの文字列が「文字」列に存在するかどうかを確認したいと思います。もしそうなら、私はユニークな値の出力を望みます。

問題は、grep複数のパターンを使用する方法がわからないことです。私は試した:

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

しかし、それは真実ではない0一致を私に与えます、何か提案はありますか?


3
fixed=TRUEパターンが真の正規表現であるため、使用できません。
Marek

6
完全一致を比較する唯一の正しい方法は、matchorまたは%in%or を使用することです。正規表現はそのようなタスクにとって非常に危険であり、予期しない結果をもたらす可能性があります。==
David Arenburg 2016

回答:


269

を含めないfixed==TRUEことに関する@Marekのコメントに加えて、正規表現にスペースを含める必要もありません。それはあるはずです"A1|A9|A6"

また、パターンはたくさんあるとおっしゃっていますね。それらがベクトルにあると仮定します

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

その後paste、and を使用して正規表現を直接作成できますcollapse = "|"

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

文字列のリストに句読点として正規表現演算子が含まれているときにこれを行う方法はありますか?
user124123 2015年

@ user1987097他の正規表現演算子の有無にかかわらず、同じように動作するはずです。これが機能しない具体的な例はありましたか?
Brian Diggs、2015

@ user1987097は、ドットまたはブラケットの前に2つのバックスラッシュを使用します。最初のバックスラッシュは、演算子を無効にするために必要な2番目のバックスラッシュを解釈するためのエスケープ文字です。
mbh86 2016年

3
完全一致に正規表現を使用するのは危険で、予期しない結果が生じる可能性があります。なぜtoMatch %in% myfile$Letterですか?
David Arenburg、2016

@ user4050特に理由はありません。問題のバージョンにはそれがあり、おそらくそれが必要かどうかを考えずに実行しただけでしょう。
Brian Diggs 2017年

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
一度にgrepl1つのパターンで動作すると思います(長さ1のベクターが必要です)。3つのパターン(長さ3のベクター)があるため、友好的なgreplセパレーターを使用して1つのパターンと組み合わせることができ|ます。 :)
Adamm 2018

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%
スティーブ

8

Brian Diggの投稿に基づいて、リストのフィルタリングに役立つ2つの関数を以下に示します。

#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
注意すべきことの1つmatchは、パターンを使用しておらず、完全に一致することを期待していることです。
スティーブ

5

この答えがすでに出ているかどうかわからない...

問題の特定のパターンについては、1回の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

小さなスクリプトを書いて、Grepで複数の検索を行うことをお勧めします。私は複数のパターンを検索する方法を見つけたことはありません。

同様に、埋め込み文字列を含むシェルファイル:

 #!/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表記btwです。

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

などなど。

一致するパターンがたくさんある場合は、forループに入れることができます。


ChrisBeanに感謝します。パターンは実際にはたくさんあり、おそらくファイルを使用する方が良いでしょう。私はBASHを使い始めたばかりですが、おそらくこのようなものがうまくいくはずです…#!/ bin / bash for i in 'pattern.txt' do echo $ ij = 'grep -c "$ {i}" myfile.txt' echo $ j if [$ j -eq o] then echo $ i >> matches.txt fi done
user971102

動作しません...エラーメッセージは「[grep:コマンドが見つかりません」です... / binフォルダーにgrepがあり、/ binが$ PATHにあります...何が起こっているのかわからない...助けていただけますか?
user971102 2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.