grep โดยใช้เวกเตอร์อักขระที่มีหลายรูปแบบ


132

ฉันกำลังพยายามใช้ grepเพื่อทดสอบว่าเวกเตอร์ของสตริงมีอยู่ในเวกเตอร์อื่นหรือไม่และส่งออกค่าที่มีอยู่ (รูปแบบการจับคู่)

ฉันมีกรอบข้อมูลดังนี้:

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

ฉันมีเวกเตอร์ของรูปแบบสตริงที่จะพบในคอลัมน์ "Letter" เช่น: c("A1", "A9", "A6")คอลัมน์ตัวอย่างเช่น:

ฉันต้องการตรวจสอบว่ามีสตริงใด ๆ ในเวกเตอร์รูปแบบอยู่ในคอลัมน์ "Letter" หรือไม่ ถ้าเป็นเช่นนั้นฉันต้องการผลลัพธ์ของค่าที่ไม่ซ้ำกัน

ปัญหาคือฉันไม่รู้ว่าจะใช้grepกับหลายรูปแบบได้อย่างไร ฉันเหนื่อย:

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

แต่มันให้ 0 แมตช์ที่ไม่จริงมีคำแนะนำไหม


3
คุณไม่สามารถใช้fixed=TRUEสาเหตุที่คุณเป็นรูปแบบเป็นนิพจน์ทั่วไปที่แท้จริง
Marek

6
การใช้matchหรือ%in%หรือแม้กระทั่ง==เป็นวิธีเดียวที่ถูกต้องในการเปรียบเทียบการจับคู่แบบตรงทั้งหมด regex เป็นอันตรายมากสำหรับงานดังกล่าวและอาจนำไปสู่ผลลัพธ์ที่ไม่คาดคิด
David Arenburg

คำตอบ:


269

นอกจากความคิดเห็นของ @ Marek เกี่ยวกับการไม่รวมfixed==TRUEแล้วคุณยังต้องไม่มีช่องว่างในนิพจน์ทั่วไปของคุณด้วย มันควรจะเป็น"A1|A9|A6"มันควรจะเป็น

คุณยังพูดถึงว่ามีลวดลายมากมาย สมมติว่าอยู่ในเวกเตอร์

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

จากนั้นคุณสามารถสร้างการแสดงออกปกติของคุณได้โดยตรงโดยใช้และpastecollapse = "|"

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

จะทำอย่างไรเมื่อรายการสตริงของคุณมีตัวดำเนินการ regex เป็นเครื่องหมายวรรคตอน
user124123

@ user1987097 ควรทำงานในลักษณะเดียวกันโดยมีหรือไม่มีตัวดำเนินการ regex อื่น ๆ คุณมีตัวอย่างเฉพาะที่ใช้ไม่ได้หรือไม่?
Brian Diggs

@ user1987097 ใช้ 2 backslahes ก่อนจุดหรือวงเล็บ แบ็กสแลชตัวแรกเป็นอักขระหลีกเพื่อตีความอักขระที่สองที่จำเป็นในการปิดใช้งานตัวดำเนินการ
mbh86

3
การใช้ regex สำหรับการจับคู่แบบตรงทั้งหมดดูเหมือนจะเป็นอันตรายสำหรับฉันและอาจมีผลลัพธ์ที่ไม่คาดคิด ทำไมไม่เพียงtoMatch %in% myfile$Letter?
David Arenburg

@ user4050 ไม่มีเหตุผลเฉพาะ เวอร์ชันในคำถามมีอยู่และฉันอาจจะดำเนินการต่อไปโดยไม่คิดว่าจำเป็นหรือไม่
Brian Diggs

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 ที่เป็นมิตร - |ลองเสี่ยงโชคกับคนอื่น ๆ :)
Adamm

3
โอ้ฉันเข้าใจแล้ว ดังนั้นจึงเป็นวิธีบีบอัดเพื่อส่งออกบางอย่างเช่น A1 | A2 ดังนั้นหากใครต้องการเงื่อนไขทั้งหมดการล่มสลายจะเป็นด้วยเครื่องหมาย & ขอบคุณมาก
Ahdee

1
สวัสดีโดยใช้รูปแบบการแยกจากกันอาจจะทำให้มีประสิทธิภาพมากขึ้นนี้:)|( paste0("(", paste(patterns, collapse=")|("),")")น่าเสียดายที่มันมีความหรูหราน้อยกว่าเล็กน้อย (A1)|(A9)|(A6)ผลนี้ในรูปแบบ
fabern

14

สิ่งนี้ควรใช้งานได้:

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

หรือง่ายกว่านั้น:

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

11
%like%ไม่ได้อยู่ในฐาน R ดังนั้นคุณควรระบุว่าจำเป็นต้องใช้แพ็คเกจใด
Gregor Thomas

1
สำหรับคนอื่น ๆ ที่ดูคำตอบนี้%like%เป็นส่วนหนึ่งของdata.tableแพ็คเกจ นอกจากนี้ในที่คล้ายกันdata.tableอยู่like(...), และ%ilike% %flike%
steveb

8

จากโพสต์ของ Brian Digg ต่อไปนี้เป็นฟังก์ชันที่มีประโยชน์สองประการสำหรับการกรองรายการ:

#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ก็คือไม่ได้ใช้รูปแบบ แต่คาดว่าจะมีการจับคู่แบบตรงทั้งหมด
steveb

5

ไม่แน่ใจว่าคำตอบนี้ปรากฏแล้วหรือยัง ...

สำหรับรูปแบบเฉพาะในคำถามคุณสามารถทำได้ด้วยการgrep()โทรเพียงครั้งเดียว

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

4

เพื่อเพิ่มคำตอบของ Brian Diggs

อีกวิธีหนึ่งในการใช้ grepl จะส่งคืน data frame ที่มีค่าทั้งหมดของคุณ

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

อาจจะสะอาดกว่าหน่อย ... อาจจะ?



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

ฉันขอแนะนำให้เขียนสคริปต์เล็กน้อยและทำการค้นหาหลายรายการด้วย Grep ฉันไม่เคยพบวิธีค้นหารูปแบบที่หลากหลายและเชื่อเถอะฉันได้ดู!

เช่นนั้นไฟล์เชลล์ของคุณที่มีสตริงฝังอยู่:

 #!/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

หากคุณต้องการส่งผ่านสตริงในบรรทัดคำสั่งให้ทำเช่นนี้โดยมีอาร์กิวเมนต์เชลล์ - นี่คือสัญลักษณ์ bash btw:

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

และอื่น ๆ

หากมีลวดลายให้เข้ากันจำนวนมากคุณสามารถใส่เป็นห่วงได้


ขอบคุณ ChrisBean รูปแบบมีจำนวนมากจริง ๆ และอาจจะดีกว่าถ้าใช้ไฟล์ในตอนนั้น ฉันยังใหม่กับ BASH แต่บางทีสิ่งนี้น่าจะใช้ได้… #! / bin / bash สำหรับ i ใน 'pattern.txt' do echo $ ij = 'grep -c "$ {i}" myfile.txt' echo $ j ถ้า [$ j -eq o] แล้ว echo $ i >> match.txt fi เสร็จ
user971102

ใช้งานไม่ได้ ... ข้อความแสดงข้อผิดพลาดคือ '[grep: command not found' ... ฉันมี grep ในโฟลเดอร์ / bin และ / bin อยู่ใน $ PATH ของฉัน ... ไม่แน่ใจว่าเกิดอะไรขึ้น…คุณช่วยได้ไหม
user971102
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.