web-dev-qa-db-ja.com

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

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

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

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

chars <- "test"
value <- "et"
223
mike

grepl関数を使う

grepl(value, chars)
# TRUE
316
smu

回答

ため息、この単純な質問に対する答えを見つけるのに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 "、それは入力行を読み、それらがあなたが与えた引数と一致すればそれを表示します。 "Global"は入力行のどこででもマッチが発生する可能性があることを意味します。以下で "Regular Expression"について説明しますが、それは文字列にマッチするより賢い方法です(Rはこの "character"と呼びます、例えばclass("abc"))、そしてこれはコマンドラインプログラムだからです。出力を発行すると、出力文字列に出力されます。

さて、grepプログラムは基本的に、入力行から出力行へのフィルタです。そしてRのgrep関数も同様に入力の配列を取ります。私には全く知られていない理由(私は約1時間前にRで遊んだだけです)のために、それはマッチのリストではなくマッチするインデックスのベクトルを返します。

しかし、あなたの最初の質問に戻りますが、私たちが本当に欲しいのは、干し草の山の中に針が見つかったかどうかを知ることです。真偽値です。彼らは明らかに "grep"のようにこの関数をgreplと名付けることにしましたが、 " _ l _ ogical"の戻り値を使います(彼らはtrueとfalseの論理値、例えばclass(TRUE)と呼びます)。

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

1+2 as a regex

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

いくつかの最後の考え

コードが優れているほど、それを理解するために知っておく必要がある履歴は少なくなります。すべての引数は少なくとも2つの興味深い値を持つことができます(そうでなければ引数である必要はありません)。docsはここで9つの引数をリストします。つまり、少なくとも2 ^ 9 = 512の呼び出し方法があります。書いて、テストして、覚えてください...そのような関数を切り離してください(それらを分割し、互いの依存関係を取り除き、文字列のものは正規表現のものとベクトルのものとは異なります)。オプションの中には相互排他的なものもあります。つまり、問題のある呼び出しは構造的に無意味なもの(存在しないオプションを渡すなど)ではなく、論理的に無意味なものにしないでください。それを説明するために警告を出す。比喩的に言えば、10階の横にある正面玄関を壁に取り替えることは、その使用に対して警告するサインを掛けるよりはましですが、どちらもどちらよりもましです。インターフェースでは、呼び出し元ではなく引数がどのように見えるべきかを定義します(呼び出し元は関数に依存しているため、誰もがそれを呼び出したいと思うすべてを推測するので、関数も呼び出し元に依存します)。循環的な依存関係があると、システムがすぐに目詰まりして、期待したようなメリットが得られません。型を曖昧にすることには十分注意してください。TRUE0"abc"のようなものがすべてベクトルであるという設計上の欠陥です。

121
Joshua Cheek

あなたはgreplが欲しいです:

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

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
21
bartektartanus

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

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

あなたが得るでしょう

[1]  TRUE FALSE FALSE  TRUE

最初のWordは "as"というサブストリングを持ち、最後のWordは "at"というサブストリングを含むため

15
C. Zeng

また、 "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
14
Surya

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

デフォルトでは、grepと関連する文字列は、一致するためにリテラル部分文字列ではなく、 正規表現 を取ります。あなたがそれを期待していない、そしてあなたが無効な正規表現にマッチさせようとするなら、それはうまくいきません:

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

真のサブストリングテストを行うには、fixed = TRUEを使用します。

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

あなたが素晴らしい正規表現が欲しいのであれば、それはOPが尋ねているように見えるものではありません。

8
Chris

grepを使うことができます

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