Karakterlerin bir dizede olup olmadığını test edin


279

Bir dize başka bir dizenin bir alt kümesi olup olmadığını belirlemek için çalışıyorum. Örneğin:

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

"Değer" dize "karakter" bir parçası olarak görünüyorsa, TRUE dönmek istiyorum. Aşağıdaki senaryoda, false döndürmek istiyorum:

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

12
Kabul edilen cevap yanlış, eklemeniz gerekiyor fixed=TRUE, aksi takdirde bir dize yerine normal ifade olarak davranıyorsunuz. Ekim 2016'dan cevabımı görün.
Joshua Cheek

@JoshuaCheek Deseninizde özel karakterler yoksa normal ifade aynı sonucu sabit olarak döndürür.
user3932000

1
Tabii, ama bunu sadece bir kelimenin tam anlamıyla geçiyorsanız bilirsiniz. Aksi takdirde, desende hangi karakterlerin olduğunu bilmezsiniz, bu nedenle fixed=TRUEverilerinizi kullanırsınız veya verilerinizi sessizce ve ustaca bozacak bir hatayla karşılaşırsınız.
Joshua Cheek

Yanıtlar:


388

greplİşlevi kullanın

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

?greplDaha fazlasını öğrenmek için kullanın .


8
Bu basit durum için sabit = TRUE eklemek performansı artırabilir (bu hesaplamaların çoğunu yapacağınızı varsayarak).
Greg Snow

1
@Josh O'Brien, söz konusu yazı karşılaştırıldığında bulgu (sayma) tek uzun bir dize tüm maçları, kısa dizeleri bir demet 1 maç bulma deneyin: vec <- replicate(100000, paste( sample(letters, 10, replace=TRUE), collapse='') ).
Greg Snow

2
Güvenilir - @GregSnow system.time(a <- grepl("abc", vec))ve system.time(a <- grepl("abc", vec, fixed=TRUE))ve fixed=TRUEeğer bir şey biraz daha yavaş, hala. Bu kısa dizelerle fark göze çarpmıyor, ancak fixed=TRUEyine de daha hızlı görünmüyor. Yine de fixed=TRUE, gerçek isabet alan uzun iplerde olduğuna dikkat çektiğiniz için teşekkür ederiz .
Josh O'Brien

2
grepl (desen, x) en azından 2017'de
JMR

2
Bu kabul edilen cevap olmamalı, çünkü değer normal ifade paterni olarak yorumlanacaktır. fixed = TRUE, aradığınız dizenin normal ifade deseni gibi görünmeyeceğini bilmiyorsanız her zaman kullanılmalıdır. Joshua Creek'in aşağıdaki cevabının bunun çok net bir açıklaması var ve kabul edilen cevap olmalı.
bhaller

159

Cevap

Ah, bu basit sorunun cevabını bulmak 45 dakikamı aldı. Cevap: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

yorumlama

grepbir kısaltmadır kendisi de linux yürütülebilir almıştır " G loblu R egular E XPression P rint", bu girişin satırları okuyup onlar verdi argümanlar eşleşirse sonra onları basacaktır. "Global", eşleşmenin giriş satırının herhangi bir yerinde gerçekleşebileceği anlamına geliyordu, aşağıda "Normal İfade" yi açıklayacağım, ancak fikir, dizeyle eşleşmenin daha akıllı bir yoludur (R, bu "karakteri" olarak adlandırır class("abc")) ve "Yazdır "çünkü bu bir komut satırı programıdır, çıktı yayan çıktı çıktı dizesine yazdırır

Şimdi, grepprogram temel olarak giriş hatlarından çıkış hatlarına bir filtredir. Ve R'nin grepişlevi benzer şekilde bir dizi girdi alacak gibi görünüyor . Benim için tamamen bilinmeyen nedenlerden dolayı (R ile sadece bir saat önce oynamaya başladım), bir eşleşme listesi yerine eşleşen dizinlerin bir vektörünü döndürür.

Ancak, orijinal sorunuza geri dönersek, gerçekten istediğimiz şey iğneyi samanlıkta bulup bulmadığımızı bilmek, doğru / yanlış bir değer. Görünüşe göre bu işlevi grepl"grep" de olduğu gibi " L ogical" dönüş değeriyle adlandırmaya karar verdiler (örn class(TRUE). Doğru ve yanlış mantıksal değerleri çağırırlar ).

Şimdi, adın nereden geldiğini ve ne yapması gerektiğini biliyoruz. Düzenli İfadelere geri dönelim. Argümanlar, dize olmasına rağmen, düzenli ifadeler oluşturmak için kullanılırlar (bundan böyle regex). Normal ifade, bir dizeyle eşleşmenin bir yoludur (bu tanım sizi rahatsız ediyorsa, bırakın). Örneğin, normal ifade akarakterle eşleşir, "a"normal ifade 0 veya daha fazla a*karakterle eşleşir "a"ve normal ifade 1 veya daha fazla a+karakterle eşleşir "a". Bu nedenle yukarıdaki örnekte, aradığımız iğne 1+2, normal ifade olarak tedavi edildiğinde "bir veya daha fazla 1 ve ardından 2" anlamına gelir ... ama bizimki bir artı takip ediyor!

Normal ifade olarak 1 + 2

Yani, greplayar olmadan kullandıysanız, fixediğneleriniz yanlışlıkla haystacks olurdu ve bu yanlışlıkla oldukça sık işe yarardı, OP örneği için bile işe yaradığını görebiliriz. Ama bu gizli bir hata! Girişin bir dize olduğunu söylemeliyiz, regex değil, görünüşe göre ne fixediçin. Neden düzeltildi? Hiçbir ipucu, bu cevap b / c imi muhtemelen ezberlemeden önce 5 kez daha bakmak zorunda kalacak.

Son birkaç düşünce

Kodunuz ne kadar iyi olursa, onu anlamak için o kadar az geçmişe sahip olmanız gerekir. Her argümanın en az iki ilginç değeri olabilir (aksi takdirde bir argüman olması gerekmez), dokümanlar burada 9 argümanı listeler, yani çağırmak için en az 2 ^ 9 = 512 yol vardır, bu çok iş yazma, test etme ve hatırlama ... bu tür fonksiyonları çözme (bölme, birbirine bağımlılıkları kaldırma, dize işleri regex şeylerinden vektör şeylerinden farklıdır). Bazı seçenekler de karşılıklı olarak münhasırdır, kullanıcılara kodu kullanmaları için yanlış yollar vermeyin, yani sorunlu çağırma mantıksal olarak mantıksız olmayan (yapısal olarak anlamsız (var olmayan bir seçeneği geçmek gibi) olmalıdır açıklamak için bir uyarı verin). Mecazi olarak koyun: 10. katın yan tarafındaki ön kapıyı bir duvarla değiştirmek, kullanımına karşı uyaran bir işaret asmaktan daha iyidir, ancak her ikisinden de daha iyi değildir. Bir arabirimde, işlev, arayanların değil, argümanların nasıl görünmesi gerektiğini tanımlar (çünkü arayan işleve bağlıdır, herkesin onu aramak isteyebileceği her şeyi çıkarırsa, işlev de arayanlara da bağlıdır ve bu tür döngüsel bağımlılık bir sistemi hızla tıkar ve asla beklediğiniz faydaları sağlamaz). Kesinti türlerine karşı çok dikkatli olun, bu tür şeylerin herkesin onu aramak isteyebileceği her şeyi çıkarmak, işlevi arayanlara da bağımlı hale getirir ve bu tür döngüsel bağımlılık, bir sistemi hızla tıkar ve asla beklediğiniz faydaları sağlamaz). Kesinti türlerine karşı çok dikkatli olun, bu tür şeylerin herkesin onu aramak isteyebileceği her şeyi çıkarmak, işlevi arayanlara da bağımlı hale getirir ve bu tür döngüsel bağımlılık, bir sistemi hızla tıkar ve asla beklediğiniz faydaları sağlamaz). Kesinti türlerine karşı çok dikkatli olun, bu tür şeylerinTRUEve 0ve "abc"hepsi vektörlerdir.


6
Açıklamanız için şerefe! R, uzun bir süre boyunca evrimleşmiş gibi görünüyor ve bazı garip tasarım seçenekleriyle sıkışmış (örneğin , değer türleriyle ilgili bu sorunun cevaplarına bakınız ). Bununla birlikte, eşleşme indekslerinin bir vektörünün döndürülmesi, bu durumda, grephücreleri değil satırları filtrelemek gibi uygun görünmektedir .
krevelen

4
"sabit", "sabit" bir diziyle eşleşen karakterleri ifade eder.
Beason

32

İstediğiniz grepl:

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

27

Bu işlevi stringipaketten kullanın :

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

Bazı kriterler:

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

Ayrıca, "stringr" kütüphanesi kullanılarak yapılabilir :

> 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

Bir dizenin (veya bir dizi dizenin) birden çok alt dizeyi içerip içermediğini de kontrol etmek isterseniz, '|' iki alt dize arasında.

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

Alacaksın

[1]  TRUE FALSE FALSE  TRUE

1. kelimenin alt dizesi "as" olduğundan ve son sözcüğün alt dizesi "at"


OR operatörü tam olarak ihtiyacım olan şeydi! +1
Sam

10

Kullanın grepveya grepl düzenli ifadeler kullanmak isteyip istemediğinizin farkında olun .

Varsayılan olarak grepve ilgili , değişmez bir alt dize değil eşleşecek normal bir ifade alır . Bunu beklemiyorsanız ve geçersiz bir normal ifadeyle eşleşmeye çalışıyorsanız, çalışmaz:

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

Gerçek bir alt dize testi yapmak için kullanın fixed = TRUE.

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

Normal ifade istiyorsanız, harika, ama OP'nin sorduğu gibi değil.


7

Kullanabilirsiniz grep

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

0

Burada benzer sorun: Bir dize ve bir anahtar kelime listesi verildiğinde, hangilerinin varsa dizede bulunduğunu tespit edin.

Bu konudaki öneriler stringr' str_detectve ' önermektedir grepl. İşte microbenchmarkpaketteki kriterler :

kullanma

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))
}

ve sonra

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

bulduk

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

Gördüğünüz gibi, 5.000 üzerinde yineleme kullanarak arama anahtar kelimesi str_detectve greplanahtar kelimeler, pratik bir dize ve vektör üzerinde greplbiraz daha iyi gerçekleştirir str_detect.

Sonuç, rhangi anahtar kelimelerin varsa dizede bulunduğunu belirleyen boole vektörüdür .

Bu nedenle, greplherhangi bir anahtar kelimenin bir dizede olup olmadığını belirlemek için kullanmanızı öneririz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.