टेस्ट अगर अक्षर एक स्ट्रिंग में हैं


279

मैं यह निर्धारित करने की कोशिश कर रहा हूं कि क्या एक स्ट्रिंग दूसरे स्ट्रिंग का सबसेट है। उदाहरण के लिए:

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

मैं TRUE वापस करना चाहता हूं यदि "मूल्य" स्ट्रिंग "वर्ण" के भाग के रूप में प्रकट होता है। निम्नलिखित परिदृश्य में, मैं गलत वापसी करना चाहूंगा:

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

12
स्वीकृत उत्तर गलत है, आपको जोड़ने की आवश्यकता है fixed=TRUE, अन्यथा आप इसे स्ट्रिंग के बजाय रीजैक्स के रूप में मान रहे हैं। मेरा जवाब अक्टूबर 2016 से देखें।
जोशुआ गाल

@JoshuaCheek जब तक आप अपने पैटर्न में विशेष वर्ण नहीं रखते हैं, तब तक regex उसी परिणाम को वापस करेगा।
user3932000

1
ज़रूर, लेकिन आप केवल यह जान सकते हैं कि यदि आप इसे शाब्दिक रूप से पारित कर रहे हैं। अन्यथा, आपको पता नहीं होगा कि पैटर्न में कौन से वर्ण हैं, इसलिए आप या तो उपयोग करते हैं fixed=TRUEया आपके पास एक बग है जो चुपचाप और आसानी से आपके डेटा को गड़बड़ कर देगा।
जोशुआ गाल

जवाबों:


388

greplफ़ंक्शन का उपयोग करें

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

?greplअधिक जानने के लिए उपयोग करें ।


8
इस साधारण मामले के लिए फिक्स्ड = TRUE जोड़ने से प्रदर्शन में सुधार हो सकता है (यह मानते हुए कि आप इनमें से बहुत सारी गणनाएँ कर रहे हैं)।
ग्रेग स्नो

1
@ जोश ओब्रायन, उस पोस्ट को एक ही लंबे स्ट्रिंग में सभी मैचों को खोजने (गिनने) की तुलना में, छोटे स्ट्रिंग्स के एक गुच्छा में 1 मैच खोजने की कोशिश करते हैं vec <- replicate(100000, paste( sample(letters, 10, replace=TRUE), collapse='') ):।
ग्रेग स्नो

2
@GregSnow - कोशिश की system.time(a <- grepl("abc", vec))और system.time(a <- grepl("abc", vec, fixed=TRUE)), और fixed=TRUEअभी भी, अगर कुछ भी थोड़ा धीमा है। इन छोटे तारों के साथ अंतर प्रशंसनीय नहीं है, लेकिन फिर fixed=TRUEभी यह तेज नहीं लगता है। हालांकि, इशारा करने के लिए धन्यवाद, कि यह लंबे समय तक तार पर fixed=TRUEहै जो वास्तविक हिट लेता है।
जोश ओ'ब्रायन

2
grepl (पैटर्न, एक्स) में कम से कम 2017
JMR

2
यह स्वीकृत उत्तर नहीं होना चाहिए, क्योंकि मूल्य को रेगेक्स पैटर्न के रूप में व्याख्या किया जाएगा। फिक्स्ड = TRUE का उपयोग हमेशा तब तक किया जाना चाहिए जब तक कि आपको पता न हो कि आप जिस स्ट्रिंग को खोज रहे हैं, वह रेगेक्स पैटर्न की तरह नहीं होगी। नीचे जोशुआ क्रीक के उत्तर में इसका बहुत स्पष्ट विवरण है, और स्वीकृत उत्तर होना चाहिए।
bhaller

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" का एक परिचित है , यह इनपुट की पंक्तियों को पढ़ेगा और फिर उन्हें मुद्रित करेगा यदि वे आपके द्वारा दिए गए तर्कों से मेल खाते हैं। "ग्लोबल" का मतलब है कि इनपुट लाइन पर कहीं भी मैच हो सकता है, मैं नीचे "रेगुलर एक्सप्रेशन" बताऊंगा, लेकिन यह विचार स्ट्रिंग से मेल खाने का एक अधिक उपयुक्त तरीका है (आर इस "चरित्र", जैसे कॉल करता है class("abc")), और "प्रिंट" "क्योंकि यह एक कमांड लाइन प्रोग्राम है, आउटपुट उत्सर्जित करने का मतलब है कि यह अपने आउटपुट स्ट्रिंग को प्रिंट करता है।

अब, grepप्रोग्राम मूल रूप से एक फिल्टर है, इनपुट की लाइनों से, आउटपुट की लाइनों तक। और ऐसा लगता है कि आर grepफ़ंक्शन समान रूप से इनपुट की एक सरणी ले जाएगा। उन कारणों के लिए जो मेरे लिए पूरी तरह से अज्ञात हैं (मैंने केवल एक घंटे पहले आर के साथ खेलना शुरू किया था), यह मैचों की सूची के बजाय, अनुक्रमित होने वाले वेक्टर का एक रिटर्न देता है।

लेकिन, अपने मूल प्रश्न पर वापस, हम वास्तव में क्या जानना चाहते हैं कि क्या हम सुई को धड़धड़ाते हुए, सही / गलत मान पाते हैं। उन्होंने स्पष्ट greplरूप से इस फ़ंक्शन को "grep" के रूप में नाम देने का फैसला किया , लेकिन " L ogical" रिटर्न वैल्यू के साथ (वे सच्चे और झूठे तार्किक मूल्यों को कहते हैं, जैसे class(TRUE))।

तो, अब हम जानते हैं कि नाम कहाँ से आया है और यह क्या करने वाला है। नियमित एक्सप्रेशन पर वापस जाएं। तर्क, भले ही वे तार हैं, उनका उपयोग नियमित अभिव्यक्ति बनाने के लिए किया जाता है (इसलिए: regex)। एक रेगेक्स एक स्ट्रिंग से मेल खाने का एक तरीका है (यदि यह परिभाषा आपको परेशान करती है, तो इसे जाने दें)। उदाहरण के लिए, रेगेक्स aचरित्र से मेल खाता है "a", रेगेक्स a*चरित्र से "a"0 या अधिक बार मेल खाता है , और रेगेक्स 1 या अधिक बार a+चरित्र से मेल खाता है "a"। इसलिए ऊपर दिए गए उदाहरण में, हम जिस सुई की खोज कर रहे हैं 1+2, जब रेगेक्स के रूप में माना जाता है, तो इसका अर्थ है "एक या एक से अधिक 1 के बाद 2" ... लेकिन हमारा पीछा एक प्लस द्वारा किया जाता है!

रेगेक्स के रूप में 1 + 2

इसलिए, यदि आप greplसेटिंग के बिना उपयोग करते हैं, तो fixedआपकी सुई गलती से छलनी हो जाएगी, और यह अकस्मात काफी काम करेगा, हम इसे ओपी के उदाहरण के लिए भी काम कर सकते हैं। लेकिन वह एक अव्यक्त बग है! हमें यह बताने की आवश्यकता है कि इनपुट एक स्ट्रिंग है, रेगेक्स नहीं, जो स्पष्ट रूप fixedसे इसके लिए है। क्यों तय किया? कोई सुराग नहीं, इस उत्तर को बुकमार्क करें b / c आप इसे याद रखने से पहले शायद 5 बार इसे देखने जा रहे हैं।

कुछ अंतिम विचार

आपका कोड जितना बेहतर होगा, उतना कम इतिहास आपको उसके बारे में समझाना होगा। प्रत्येक तर्क में कम से कम दो दिलचस्प मूल्य हो सकते हैं (अन्यथा उसे तर्क देने की आवश्यकता नहीं होगी), डॉक्स 9 तर्क यहां सूचीबद्ध करता है, जिसका अर्थ है कि इसे लागू करने के लिए कम से कम 2 ^ 9 = 512 तरीके हैं, यह बहुत काम है लिखना, परीक्षण करना, और याद रखना ... ऐसे कार्यों को डिकूप करना (उन्हें अलग करना, एक-दूसरे पर निर्भरता को दूर करना, स्ट्रिंग चीजें regex से भिन्न होती हैं, वेक्टर चीजों से अलग होती हैं)। कुछ विकल्प भी पारस्परिक रूप से अनन्य हैं, उपयोगकर्ताओं को कोड का उपयोग करने के लिए गलत तरीके नहीं देते हैं, यानी समस्याग्रस्त आह्वान संरचनात्मक रूप से निरर्थक होना चाहिए (जैसे कि कोई विकल्प मौजूद नहीं है), तार्किक रूप से निरर्थक नहीं है (जहां आपके पास है) इसे समझाने के लिए चेतावनी दें)। रूपक लगाएं: 10 वीं मंजिल के सामने के दरवाजे को दीवार के साथ बदलना एक संकेत को लटकाने से बेहतर है जो इसके उपयोग के खिलाफ चेतावनी देता है, लेकिन या तो न तो बेहतर है। एक इंटरफ़ेस में, फ़ंक्शन परिभाषित करता है कि तर्कों को कैसा दिखना चाहिए, न कि कॉल करने वाले (क्योंकि कॉलर फ़ंक्शन पर निर्भर करता है, सब कुछ का अनुमान लगाते हुए, जिसे हर कोई कभी भी कॉल कर सकता है, फ़ंक्शन कॉल करने वाले पर निर्भर करता है, और इस प्रकार से भी) चक्रीय निर्भरता जल्दी से एक प्रणाली को रोकना और कभी भी आपके द्वारा अपेक्षित लाभ प्रदान नहीं करेगी)। समान प्रकार से बहुत सावधान रहें, यह एक डिज़ाइन दोष है जैसे कि चीजें सब कुछ का उल्लेख करते हुए कि हर कोई इसे कभी भी कॉल करना चाहता है, जिससे फ़ंक्शन कॉलर्स पर निर्भर करता है, और इस प्रकार का चक्रीय निर्भरता जल्दी से एक सिस्टम को रोक देगा और कभी भी उन लाभों को प्रदान नहीं करेगा जो आप अपेक्षा करते हैं)। समान प्रकार से बहुत सावधान रहें, यह एक डिज़ाइन दोष है जैसे कि चीजें सब कुछ का उल्लेख करते हुए कि हर कोई इसे कभी भी कॉल करना चाहता है, जिससे फ़ंक्शन कॉलर्स पर निर्भर करता है, और इस प्रकार का चक्रीय निर्भरता जल्दी से एक सिस्टम को रोक देगा और कभी भी उन लाभों को प्रदान नहीं करेगा जो आप अपेक्षा करते हैं)। समान प्रकार से बहुत सावधान रहें, यह एक डिज़ाइन दोष है जैसे कि चीजेंTRUEऔर 0और "abc"सब वैक्टर हैं।


6
आपके स्पष्टीकरण के लिए चीयर्स! ऐसा प्रतीत होता है कि आर समय की लंबी अवधि में विकसित हुआ है और कुछ अजीब डिजाइन विकल्पों के साथ अटक गया है (उदाहरण के लिए मान प्रकार पर इस प्रश्न के उत्तर )। हालांकि, मैच सूचकांकों का एक वेक्टर लौटना इस मामले में उचित लगता है, जैसा grepकि पंक्तियों को फ़िल्टर करना है, कोशिकाओं को नहीं।
krevelen

4
"फिक्स्ड" एक "निश्चित" अनुक्रम से मेल खाने वाले पात्रों को संदर्भित करता है।
विल बेंसन

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

यदि आप एक स्ट्रिंग (या तार का एक सेट) में कई उप-स्ट्रिंग होते हैं, तो आप यह भी चेक कर सकते हैं कि आप '|' का उपयोग भी कर सकते हैं। दो पदार्थों के बीच।

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

तुम्हे मिल जाएगा

[1]  TRUE FALSE FALSE  TRUE

चूंकि 1 शब्द में "के रूप में" विकल्प है, और अंतिम शब्द में "पर" विकल्प है।


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

यदि आप regex, महान चाहते हैं, लेकिन वह नहीं है जो ओपी पूछ रहा प्रतीत होता है।


7

आप उपयोग कर सकते हैं grep

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

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

जैसा कि आप देख सकते हैं, कीवर्ड के 5,000 से अधिक पुनरावृत्तियों का उपयोग करके str_detectऔर greplव्यावहारिक स्ट्रिंग और कीवर्ड के वेक्टर पर, की greplतुलना में काफी बेहतर प्रदर्शन करता है str_detect

परिणाम बूलियन वेक्टर है rजो पहचानता है कि, यदि कोई है, तो कीवर्ड स्ट्रिंग में समाहित हैं।

इसलिए, मैं greplयह निर्धारित करने के लिए उपयोग करने की सलाह देता हूं कि क्या कोई कीवर्ड एक स्ट्रिंग में है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.