कई पैटर्न के साथ एक चरित्र वेक्टर का उपयोग कर grep


132

मैं grepयह जांचने के लिए उपयोग करने की कोशिश कर रहा हूं कि क्या एक वेक्टर का तार एक दूसरे वेक्टर में मौजूद है या नहीं, और जो मान मौजूद हैं (मिलान पैटर्न) आउटपुट करने के लिए।

मेरा डेटा फ्रेम इस तरह है:

FirstName Letter   
Alex      A1
Alex      A6
Alex      A7
Bob       A1
Chris     A9
Chris     A6

मेरे पास "लेटर" कॉलम में पाए जाने वाले स्ट्रिंग्स पैटर्न का एक वेक्टर है, उदाहरण के लिए c("A1", "A9", "A6"):।

मैं यह जांचना चाहूंगा कि क्या पैटर्न वेक्टर में कोई भी तार "लेटर" कॉलम में मौजूद है। यदि वे हैं, तो मैं अनूठे मूल्यों का उत्पादन करना चाहूंगा।

समस्या यह है, मैं नहीं जानता कि कैसे grepकई पैटर्न के साथ उपयोग करने के लिए । मैंने कोशिश की:

matches <- unique (
    grep("A1| A9 | A6", myfile$Letter, value=TRUE, fixed=TRUE)
)

लेकिन यह मुझे 0 मैच देता है जो सच नहीं है, कोई सुझाव?


3
आप उपयोग नहीं कर सकते fixed=TRUEक्योंकि आप पैटर्न सही नियमित अभिव्यक्ति है।
मारेक

6
का उपयोग करते हुए matchया %in%या यहाँ तक कि ==है केवल सटीक मिलान तुलना करने के लिए सही तरीका। regex ऐसे कार्य के लिए बहुत खतरनाक है और अप्रत्याशित परिणाम पैदा कर सकता है।
बजे डेविड अर्नबर्ग

जवाबों:


269

शामिल नहीं होने के बारे में @ मारेक की टिप्पणी के अलावा fixed==TRUE, आपको अपनी नियमित अभिव्यक्ति में रिक्त स्थान नहीं होने की भी आवश्यकता है। यह होना चाहिए "A1|A9|A6"

आप यह भी उल्लेख करते हैं कि बहुत सारे पैटर्न हैं। यह मानते हुए कि वे एक वेक्टर में हैं

toMatch <- c("A1", "A9", "A6")

तो फिर तुम सीधे का उपयोग कर अपने नियमित अभिव्यक्ति बना सकते हैं pasteऔर collapse = "|"

matches <- unique (grep(paste(toMatch,collapse="|"), 
                        myfile$Letter, value=TRUE))

ऐसा करने का कोई तरीका जब आपके तार की सूची में विराम चिह्न ऑपरेटर शामिल हों?
user124123

@ user1987097 यह उसी तरह से काम करना चाहिए, जैसे किसी अन्य रेगेक्स ऑपरेटर के साथ या उसके बिना। क्या आपके पास एक विशिष्ट उदाहरण है जिसके लिए यह काम नहीं किया?
ब्रायन डिग

@ user1987097 एक डॉट या ब्रैकेट से पहले 2 बैकस्लैस का उपयोग करें। पहला बैकस्लैश ऑपरेटर को निष्क्रिय करने के लिए आवश्यक दूसरे की व्याख्या करने के लिए एक भागने का चरित्र है।
mbh86

3
सटीक मैचों के लिए रेगेक्स का उपयोग करना मेरे लिए खतरनाक लगता है और इसके अप्रत्याशित परिणाम हो सकते हैं। सिर्फ क्यों नहीं toMatch %in% myfile$Letter?
डेविड अर्नबर्ग

@ user4050 कोई विशेष कारण नहीं। प्रश्न में संस्करण के पास यह था और मैंने शायद इसके बारे में सोचने के बिना यह किया कि क्या यह आवश्यक था।
ब्रायन डिग्स

34

अच्छा जवाब है, तथापि के बारे में भूल नहीं है filter()dplyr से:

patterns <- c("A1", "A9", "A6")
>your_df
  FirstName Letter
1      Alex     A1
2      Alex     A6
3      Alex     A7
4       Bob     A1
5     Chris     A9
6     Chris     A6

result <- filter(your_df, grepl(paste(patterns, collapse="|"), Letter))

>result
  FirstName Letter
1      Alex     A1
2      Alex     A6
3       Bob     A1
4     Chris     A9
5     Chris     A6

3
मुझे लगता है कि greplउस समय एक पैटर्न के साथ काम करता है (हमें लंबाई 1 के साथ वेक्टर की आवश्यकता होती है), हमारे पास 3 पैटर्न (लंबाई 3 के वेक्टर) हैं, इसलिए हम उन्हें grepl विभाजक के लिए कुछ अनुकूल का उपयोग करके जोड़ सकते हैं - |, दूसरे के साथ अपनी किस्मत आज़माएं :)
एडमंड

3
ओह, अब मुझे समझ में आ गया। तो यह A1 की तरह कुछ उत्पादन करने के लिए एक संक्षिप्त तरीका है A2 इसलिए यदि कोई सभी शर्तों को चाहता था तो पतन एक & संकेत, शांत धन्यवाद के साथ होगा।
अहिंदी

1
नमस्ते, )|(अलग-अलग पैटर्न का उपयोग करने से यह अधिक मजबूत हो सकता है paste0("(", paste(patterns, collapse=")|("),")"):। दुर्भाग्य से यह भी थोड़ा कम ग्यारह हो जाता है। यह पैटर्न में परिणाम है (A1)|(A9)|(A6)
फैबर्न

14

यह काम करना चाहिए:

grep(pattern = 'A1|A9|A6', x = myfile$Letter)

या और भी सरल:

library(data.table)
myfile$Letter %like% 'A1|A9|A6'

11
%like%आधार R में नहीं है, इसलिए आपको यह उल्लेख करना चाहिए कि इसका उपयोग करने के लिए किस पैकेज की आवश्यकता है।
ग्रेगर थॉमस

1
इस उत्तर को देखने वाले अन्य लोगों के लिए, पैकेज %like%का हिस्सा है data.table। इसके अलावा समान में data.tableहैं like(...), %ilike%, और %flike%
steveb

8

ब्रायन डिग के पद के आधार पर, सूची को छानने के दो सहायक कार्य यहां दिए गए हैं:

#Returns all items in a list that are not contained in toMatch
#toMatch can be a single item or a list of items
exclude <- function (theList, toMatch){
  return(setdiff(theList,include(theList,toMatch)))
}

#Returns all items in a list that ARE contained in toMatch
#toMatch can be a single item or a list of items
include <- function (theList, toMatch){
  matches <- unique (grep(paste(toMatch,collapse="|"), 
                          theList, value=TRUE))
  return(matches)
}

5

क्या आपने match()या charmatch()कार्य करने की कोशिश की है?

उदाहरण का उपयोग करें:

match(c("A1", "A9", "A6"), myfile$Letter)

1
ध्यान देने वाली एक बात matchयह है कि यह पैटर्न का उपयोग नहीं कर रहा है, यह एक सटीक मैच की उम्मीद कर रहा है।
चरण

5

यकीन नहीं होता कि क्या यह जवाब पहले ही सामने आ चुका है ...

प्रश्न में विशेष पैटर्न के लिए, आप इसे केवल एक grep()कॉल के साथ कर सकते हैं,

grep("A[169]", myfile$Letter)

4

ब्रायन डिग्स उत्तर में जोड़ने के लिए।

grepl का उपयोग करने का दूसरा तरीका आपके सभी मूल्यों वाले डेटा फ़्रेम को लौटाएगा।

toMatch <- myfile$Letter

matches <- myfile[grepl(paste(toMatch, collapse="|"), myfile$Letter), ]

matches

Letter Firstname
1     A1      Alex 
2     A6      Alex 
4     A1       Bob 
5     A9     Chris 
6     A6     Chris

शायद थोड़ा क्लीनर ... शायद?


2

रिक्त स्थान हटा दें। ऐसा:

matches <- unique(grep("A1|A9|A6", myfile$Letter, value=TRUE, fixed=TRUE))

1

का उपयोग करते हुए sapply

 patterns <- c("A1", "A9", "A6")
         df <- data.frame(name=c("A","Ale","Al","lex","x"),Letters=c("A1","A2","A9","A1","A9"))



   name Letters
1    A      A1
2  Ale      A2
3   Al      A9
4  lex      A1
5    x      A9


 df[unlist(sapply(patterns, grep, df$Letters, USE.NAMES = F)), ]
  name Letters
1    A      A1
4  lex      A1
3   Al      A9
5    x      A9

-1

मेरा सुझाव है कि थोड़ा स्क्रिप्ट लिखें और ग्रीप के साथ कई खोजें करें। मुझे कई पैटर्न खोजने का तरीका कभी नहीं मिला, और मुझे विश्वास है, मैंने देखा है!

जैसे, आपकी शेल फ़ाइल, एक एम्बेडेड स्ट्रिंग के साथ:

 #!/bin/bash 
 grep *A6* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
 grep *A7* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";
 grep *A8* "Alex A1 Alex A6 Alex A7 Bob A1 Chris A9 Chris A6";

फिर myshell.sh लिखकर चलाएं।

यदि आप कमांड लाइन पर स्ट्रिंग में पास होने में सक्षम होना चाहते हैं, तो इसे इस तरह से करें, शेल तर्क के साथ - यह बैश नोटेशन btw है:

 #!/bin/bash 
 $stingtomatch = "${1}";
 grep *A6* "${stingtomatch}";
 grep *A7* "${stingtomatch}";
 grep *A8* "${stingtomatch}";

इत्यादि।

यदि मैच करने के लिए बहुत सारे पैटर्न हैं, तो आप इसे लूप में डाल सकते हैं।


धन्यवाद क्रिसबैन। पैटर्न वास्तव में बहुत सारे हैं, और शायद तब फ़ाइल का उपयोग करना बेहतर होगा। मैं BASH में नया हूं, लेकिन शायद कुछ इस तरह काम करना चाहिए ... #! / Bin / bash for i in 'pattern.txt' do echo $ ij = 'grep -c "$ {i}" myfile.txt' इको $ j अगर [$ जे -eq ओ] तो गूंज $ i >> matches.txt फाई किया
user971102

काम नहीं करता ... त्रुटि संदेश '[grep: कमांड नहीं मिला' ... मेरे पास / बिन फ़ोल्डर में grep है, और / बिन मेरे $ पथ पर है ... निश्चित नहीं कि क्या हो रहा है ... क्या आप कृपया मदद कर सकते हैं?
user971102
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.