文字列が別の文字列のサブセットであるかどうかを判断しようとしています。例えば:
chars <- "test"
value <- "es"
「value」が文字列「chars」の一部として表示される場合は、TRUEを返したいです。次のシナリオでは、falseを返したいと思います。
chars <- "test"
value <- "et"
grepl
関数を使用する
grepl( needle, haystack, fixed = TRUE)
そのようです:
grepl(value, chars, fixed = TRUE)
# TRUE
詳細を確認するために使用?grepl
します。
ため息をつく、この簡単な質問の答えを見つけるのに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
Linux実行可能ファイルにちなんで名付けられました。これは、それ自体が「G lobal R egular E xpression P rint」の頭字語であり、入力行を読み取り、指定した引数と一致する場合はそれらを出力します。「グローバル」とは、入力行のどこでも一致が発生する可能性があることを意味します。以下で「正規表現」について説明しますが、文字列(Rはこれを「文字」と呼びますclass("abc")
)と「印刷」を一致させるためのよりスマートな方法です。 "これはコマンドラインプログラムであるため、出力を出力するということは、出力文字列に出力することを意味します。
現在、grep
プログラムは基本的に、入力行から出力行までのフィルターです。また、Rのgrep
関数も同様に入力の配列を受け取るようです。私にはまったく知られていない理由で(私は約1時間前にRで遊び始めただけです)、一致のリストではなく、一致するインデックスのベクトルを返します。
しかし、元の質問に戻ると、私たちが本当に望んでいるのは、干し草の山で針が真/偽の値であるかどうかを知ることです。彼らは明らかに、この関数grepl
に「grep」のように名前を付けることを決定しましたが、「論理」の戻り値を使用します(たとえば、真と偽の論理値を呼び出しますclass(TRUE)
)。
これで、名前の由来とその意味がわかりました。正規表現に戻りましょう。引数は文字列ですが、正規表現(以降:regex)を作成するために使用されます。正規表現は文字列を照合する方法です(この定義がイライラする場合は、手放してください)。たとえば、正規表現a
は文字と一致し"a"
、正規表現a*
は文字と"a"
0回以上一致し、正規表現a+
は文字と"a"
1回以上一致します。したがって、上記の例では、正規表現として扱われる場合、検索している針は1+2
「1つ以上の1の後に2が続く」ことを意味します...しかし、私たちの針の後にはプラスが続きます!
したがって、grepl
設定せずに使用した場合fixed
、針が誤って干し草の山になり、それが誤って頻繁に機能する可能性があります。これは、OPの例でも機能することがわかります。しかし、それは潜在的なバグです!入力が正規表現ではなく文字列であることを伝える必要があります。これは明らかにfixed
目的です。なぜ修正されたのですか?手がかりはありません。この回答をブックマークしてください。おそらく、覚える前にさらに5回調べる必要があります。
コードが優れているほど、コードを理解するために知っておく必要のある履歴は少なくなります。すべての引数は少なくとも2つの興味深い値を持つことができます(そうでなければ引数である必要はありません)。ドキュメントにはここに9つの引数がリストされています。つまり、少なくとも2 ^ 9 = 512の方法で呼び出すことができます。これは、多くの作業が必要です。書き込み、テスト、および記憶...そのような関数を分離します(それらを分割し、相互の依存関係を削除し、文字列のものは正規表現のものとは異なり、ベクトルのものとは異なります)。一部のオプションも相互に排他的であり、ユーザーにコードの誤った使用方法を提供しないでください。つまり、問題のある呼び出しは、論理的に無意味ではなく(存在しないオプションを渡すなど)、構造的に無意味である必要があります(必要な場合)それを説明するために警告を発します)。比喩的に言えば:10階横の玄関ドアを壁に替えるのは、使用を警告する看板を掛けるよりはましですが、どちらもどちらよりもいいです。インターフェイスでは、関数は呼び出し元ではなく、引数がどのように見えるかを定義します(呼び出し元は関数に依存しているため、誰もが呼び出したいと思う可能性のあるすべてのものを推測すると、関数も呼び出し元に依存します。このタイプ周期的な依存関係があると、システムがすぐに詰まり、期待するメリットが得られなくなります)。タイプを曖昧にすることに非常に注意してください、それは次のようなものの設計上の欠陥です 誰もがそれを呼び出したいと思うかもしれないすべてを推測すると、関数は呼び出し元にも依存します。このタイプの周期的な依存関係は、システムをすぐに詰まらせ、期待する利点を提供しません)。タイプを曖昧にすることに非常に注意してください、それは次のようなものの設計上の欠陥です 誰もがそれを呼び出したいと思うかもしれないすべてを推測すると、関数は呼び出し元にも依存します。このタイプの周期的な依存関係は、システムをすぐに詰まらせ、期待する利点を提供しません)。タイプを曖昧にすることに非常に注意してください、それは次のようなものの設計上の欠陥ですTRUE
および0
と"abc"
はすべてベクトルです。
あなたが欲しいgrepl
:
> chars <- "test"
> value <- "es"
> grepl(value, chars)
[1] TRUE
> chars <- "test"
> value <- "et"
> grepl(value, chars)
[1] FALSE
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
また、 「stringr」ライブラリを使用して実行できます。
> 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
文字列(または文字列のセット)に複数のサブ文字列が含まれているかどうかも確認したい場合は、「|」を使用することもできます。2つの部分文字列の間。
>substring="as|at"
>string_vector=c("ass","ear","eye","heat")
>grepl(substring,string_vector)
あなたは得るでしょう
[1] TRUE FALSE FALSE TRUE
最初の単語には「as」という部分文字列があり、最後の単語には「at」という部分文字列が含まれているためです。
grep
またはを使用grepl
しますが、正規表現を使用するかどうかに注意してください。
デフォルトでは、grep
およびrelatedは、リテラルの部分文字列ではなく、一致する正規表現を取ります。それを予期しておらず、無効な正規表現で一致させようとすると、機能しません。
> grep("[", "abc[")
Error in grep("[", "abc[") :
invalid regular expression '[', reason 'Missing ']''
真の部分文字列テストを実行するには、を使用しますfixed = TRUE
。
> grep("[", "abc[", fixed = TRUE)
[1] 1
正規表現が必要な場合は素晴らしいですが、それはOPが求めているようには見えません。
使用できますgrep
grep("es", "Test")
[1] 1
grep("et", "Test")
integer(0)
ここでの同様の問題:文字列とキーワードのリストが与えられた場合、文字列に含まれているキーワードがある場合はそれを検出します。
stringr
このスレッドからの推奨事項は、とを提案しstr_detect
ますgrepl
。microbenchmark
パッケージのベンチマークは次のとおりです。
使用する
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
ご覧のとおり、実用的な文字列とキーワードのベクトルを使用str_detect
したキーワード検索の5,000回以上の反復は、よりもかなり優れたパフォーマンスを発揮します。grepl
grepl
str_detect
r
結果は、文字列に含まれているキーワードがある場合はそれを識別するブールベクトルです。
したがって、を使用grepl
して、文字列にキーワードが含まれているかどうかを判断することをお勧めします。