文字が文字列に含まれているかどうかをテストする


279

文字列が別の文字列のサブセットであるかどうかを確認しようとしています。例えば:

chars <- "test"
value <- "es"

「値」が文字列「chars」の一部として表示される場合は、TRUEを返します。次のシナリオでは、falseを返します。

chars <- "test"
value <- "et"

12
受け入れられた答えは間違っていfixed=TRUEます。追加する必要があります。そうでない場合は、文字列ではなく正規表現として扱います。2016
ジョシュアチーク

@JoshuaCheekパターンに特殊文字がない限り、正規表現は修正されたものと同じ結果を返します。
user3932000

1
確かに、しかしそれをリテラルに渡す場合にのみそれを知ることができます。そうしないと、パターン内の文字がわからないので、使用するfixed=TRUEか、静かにそして微妙にデータを破壊するバグが発生します。
ジョシュアチーク

回答:


388

grepl関数を使用する

grepl(value, chars, fixed = TRUE)
# TRUE

?grepl詳細を調べるために使用します。


8
この単純なケースの場合、fixed = TRUEを追加するとパフォーマンスが向上する可能性があります(これらの計算を大量に実行するとします)。
グレッグスノー

1
@Josh O'brien、その投稿は、単一の長い文字列ですべての一致を見つける(数える)ことを比較しましたvec <- replicate(100000, paste( sample(letters, 10, replace=TRUE), collapse='') )。短い文字列の束で1つの一致を見つけてみてください。
グレッグスノー

2
試しました- @GregSnow system.time(a <- grepl("abc", vec))system.time(a <- grepl("abc", vec, fixed=TRUE))し、fixed=TRUEどちらかといえばやや遅く、まだです。これらの短い文字列では違いはあまりわかりfixed=TRUEませんが、それでも高速であるようには見えません。ただし、fixed=TRUE実際にヒットするのは長い文字列にあることを指摘してくれてありがとう。
Josh O'Brien

2
grepl(pattern、x)少なくとも2017年
JMR

2
値は正規表現パターンとして解釈されるため、これは受け入れられる答えではありません。fixed = TRUEは、検索する文字列が正規表現パターンのように見えないことがわかっている場合を除いて、常に使用する必要があります。以下のジョシュアクリークの答えは、これについて非常に明確な説明があり、受け入れられる答えになるはずです。
バラー

159

回答

ため息、この簡単な質問の答えを見つけるのに45分かかりました。答えは:grepl(needle, haystack, fixed=TRUE)

# Correct
> grepl("1+2", "1+2", fixed=TRUE)
[1] TRUE
> grepl("1+2", "123+456", fixed=TRUE)
[1] FALSE

# Incorrect
> grepl("1+2", "1+2")
[1] FALSE
> grepl("1+2", "123+456")
[1] TRUE

解釈

grepそれ自体が「G lobal R egular E xpression P rint 」の頭字語であるlinux実行可能ファイルにちなんで名付けられ、入力行を読み取って、指定した引数と一致する場合はそれらを出力します。「グローバル」は、一致が入力行のどこでも発生する可能性があることを意味しました。以下の「正規表現」について説明しますが、アイデアは、文字列を一致させるためのよりスマートな方法です(Rはこの「文字」を呼び出します。class("abc"))と「印刷」 "これはコマンドラインプログラムであるため、出力を発行すると、出力文字列に出力されます。

現在、grepプログラムは基本的に、入力行から出力行までのフィルターです。そして、Rのgrep関数も同様に入力の配列を取るようです。私にはまったくわからない理由のため(私は約1時間前にRで遊んだばかりです)、一致のリストではなく、一致するインデックスのベクトルを返します。

しかし、元の質問に戻って、私たちが本当に欲しいのは、干し草の山に針が見つかったかどうか、真/偽の値を知ることです。彼らは明らかに、この関数に名前を付けることにしましたgrepl「はgrep」のとしてではなく「と、L(彼らは例えば、真と偽の論理値を呼び出し、戻り値ogical」class(TRUE))。

これで、名前がどこから来たのか、何をするのかがわかりました。正規表現に戻りましょう。引数は文字列ですが、正規表現(以降、regex)を構築するために使用されます。正規表現は、文字列を照合する方法です(この定義でイライラした場合は、そのままにします)。たとえば、正規表現aは文字"a"に一致し、正規表現a*は文字に"a"0回以上一致し、正規表現a+は文字に"a"1回以上一致します。したがって、上記の例では、検索している針は1+2、正規表現として扱われる場合、「1つ以上の1の後に2が続く」ことを意味します...しかし、私たちの針の後にはプラスが続きます!

正規表現として1 + 2

したがって、を使用せgreplずにを使用した場合fixed、針が誤って干し草の山になり、偶然かなり頻繁に機能するようになるため、OPの例でも機能することがわかります。しかし、それは潜在的なバグです!入力が正規表現ではなく文字列であることを伝える必要がありますfixed。これは明らかに目的です。なぜ修正されたのですか?手がかりがありません。この回答をブックマークしてください。覚える前に、さらに5回調べる必要があります。

いくつかの最終的な考え

コードが優れているほど、それを理解するために知る必要がある履歴が少なくなります。すべての引数は、少なくとも2つの興味深い値を持つことができます(そうでない場合、引数である必要はありません)。ドキュメントには、ここに9つの引数がリストされています。つまり、少なくとも2 ^ 9 = 512の方法で呼び出すことができます。書き、テストし、覚えておいてください...そのような関数を分離します(それらを分割し、相互の依存関係を削除します。文字列は正規表現とは異なり、ベクトルとは異なります)。一部のオプションは相互に排他的でもあります。つまり、ユーザーにコードの誤った使用方法を与えないでください。つまり、問題のある呼び出しは、論理的に無意味ではない(存在するオプションを渡すなど)構造的に無意味である必要があります。それを説明する警告を発します)。比喩的に言えば:10階の側面にある正面玄関を壁に置き換えることは、その使用を警告する標識をぶら下げるよりも優れていますが、どちらもどちらも優れていません。インターフェースでは、関数は呼び出し元ではなく引数の外観を定義します(呼び出し元は関数に依存しているため、誰もがそれを呼び出す可能性のあるすべてのものを推測すると、関数も呼び出し元に依存するため、この型周期的な依存関係があると、システムがすぐに詰まり、期待するメリットが得られません)。型の等価性に非常に注意してください。これは、設計上の欠陥であり、誰もが呼び出す可能性のあるすべてのものを推測すると、関数も呼び出し元に依存するようになり、このタイプの循環依存関係はシステムをすぐに詰まらせ、期待する利点を提供しません)。型の等価性に非常に注意してください。これは、設計上の欠陥であり、誰もがそれを呼び出したいと思うかもしれないすべてを推測すると、関数も呼び出し元に依存するようになり、このタイプの循環依存はシステムをすぐに詰まらせ、期待する利点を提供しません)。型の等価性に非常に注意してください。これは、設計上の欠陥であり、TRUEそして、0し、"abc"すべてのベクトルです。


6
あなたの説明を乾杯!Rは長期間にわたって進化し、奇妙な設計上の選択に悩まされているようです(たとえば、値の型に関するこの質問への回答を参照してください)。ただし、grepセルではなく行をフィルタリングする場合と同様に、この場合は一致インデックスのベクトルを返すことが適切と思われます。
krevelen 2017

4
「固定」とは、「固定」シーケンスに一致する文字を指します。
Beason、

32

あなたが欲しいgrepl

> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE

27

この関数をstringiパッケージから使用します。

> stri_detect_fixed("test",c("et","es"))
[1] FALSE  TRUE

いくつかのベンチマーク:

library(stringi)
set.seed(123L)
value <- stri_rand_strings(10000, ceiling(runif(10000, 1, 100))) # 10000 random ASCII strings
head(value)

chars <- "es"
library(microbenchmark)
microbenchmark(
   grepl(chars, value),
   grepl(chars, value, fixed=TRUE),
   grepl(chars, value, perl=TRUE),
   stri_detect_fixed(value, chars),
   stri_detect_regex(value, chars)
)
## Unit: milliseconds
##                               expr       min        lq    median        uq       max neval
##                grepl(chars, value) 13.682876 13.943184 14.057991 14.295423 15.443530   100
##  grepl(chars, value, fixed = TRUE)  5.071617  5.110779  5.281498  5.523421 45.243791   100
##   grepl(chars, value, perl = TRUE)  1.835558  1.873280  1.956974  2.259203  3.506741   100
##    stri_detect_fixed(value, chars)  1.191403  1.233287  1.309720  1.510677  2.821284   100
##    stri_detect_regex(value, chars)  6.043537  6.154198  6.273506  6.447714  7.884380   100

22

また、「ストリンガー」ライブラリーを使用して実行できます

> library(stringr)
> chars <- "test"
> value <- "es"
> str_detect(chars, value)
[1] TRUE

### For multiple value case:
> value <- c("es", "l", "est", "a", "test")
> str_detect(chars, value)
[1]  TRUE FALSE  TRUE FALSE  TRUE

20

文字列(または文字列のセット)に複数のサブ文字列が含まれているかどうかも確認したい場合に備えて、 '|'を使用することもできます。2つの部分文字列の間。

>substring="as|at"
>string_vector=c("ass","ear","eye","heat") 
>grepl(substring,string_vector)

あなたが得るでしょう

[1]  TRUE FALSE FALSE  TRUE

最初の単語には部分文字列 "as"があり、最後の単語には部分文字列 "at"が含まれているため


OR演算子はまさに私が必要とするものでした!+1
サム

10

grepまたはgrepl を使用しますが、正規表現を使用するかどうかに注意してください。

デフォルトではgrep、関連するものは、リテラル部分文字列ではなく、正規表現を使用して一致します。それを期待しておらず、無効な正規表現で照合しようとすると、機能しません。

> grep("[", "abc[")
Error in grep("[", "abc[") : 
  invalid regular expression '[', reason 'Missing ']''

真の部分文字列テストを行うには、を使用しますfixed = TRUE

> grep("[", "abc[", fixed = TRUE)
[1] 1

正規表現が必要な場合は素晴らしいですが、OPが求めているようには見えません。


7

使用できます grep

grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)

0

ここで同様の問題:文字列とキーワードのリストを指定して、もしあれば、どのキーワードが文字列に含まれているかを検出します。

このスレッドからの提言を示唆stringrさんstr_detectgreplmicrobenchmarkパッケージのベンチマークは次のとおりです。

使用する

map_keywords = c("once", "twice", "few")
t = "yes but only a few times"

mapper1 <- function (x) {
  r = str_detect(x, map_keywords)
}

mapper2 <- function (x) {
  r = sapply(map_keywords, function (k) grepl(k, x, fixed = T))
}

その後

microbenchmark(mapper1(t), mapper2(t), times = 5000)

我々は気づく

Unit: microseconds
       expr    min     lq     mean  median      uq      max neval
 mapper1(t) 26.401 27.988 31.32951 28.8430 29.5225 2091.476  5000
 mapper2(t) 19.289 20.767 24.94484 23.7725 24.6220 1011.837  5000

あなたは使ってキーワード検索の5,000回の繰り返しの上に、見ることができるようにstr_detectし、greplキーワードの実用的な文字列やベクトル、上greplかなり良くより行ないますstr_detect

結果は、rどのキーワードが文字列に含まれるかを特定するブールベクトルです。

したがって、を使用greplして、キーワードが文字列に含まれているかどうかを判断することをお勧めします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.