过滤一些字符串,但其中一些不是!与grepl

时间:2017-05-29 22:35:31

标签: r filter dplyr grepl

我正在尝试过滤数据中的一些字符串。例如,我想过滤掉'AxxBy'字符串,但是我想保留这个字符串'AxxByy'! x和y代表位数!

这是我尝试过的,

data <- data.frame(pair=paste(paste('A',c(seq(1:4),10,11),sep=''),paste('B',c(2,3,4,22,33,44),sep=''),sep='')) 
    pair
1   A1B2
2   A2B3
3   A3B4
4  A4B22
5 A10B33
6 A11B44

我想删除以A1开头而不是A10和A11的那些对。也和B2一样但保留B22!等

x <- c(paste('A',1,sep=''), paste('B',2,sep='')) # filtering conditions

library(dplyr)
df <- data%>%
  filter(!grepl(paste(x,collapse='|'),pair))

 pair
1 A2B3
2 A3B4

在这篇文章中Filtering observations in dplyr in combination with grepl 可以通过正则表达式函数添加以"^x|xx$"开头的行,但如果在管道外定义了过滤条件,我还没有看到任何帖子。

预期输出

  pair
    1   A2B33
    2   A3B4
    3   A4B22
    4   A10B33
    6   A11B44

规则的拇指是那样的;如果在'A'之后有两个数字,则将B使得AxxB和!grepl在x输入中定义xx数字的所有内容。如果只有'B'并且给出了一个'By'数字!grepl'通过$'而不是'Byy'输入。当然,这包括'AxBy $'和'AxxBy $'。我仍然无法概括@alistaire解决方案!

1 个答案:

答案 0 :(得分:2)

OP要求过滤掉'AxxBy'字符串,但希望保留字符串'AxxByy'(其中'x'和'y'表示数字。

通常,指定要保留的内容比删除内容更容易。保持符合模式'AxxByy'的字符串是正则表达式

"^A\\d{2}B\\d{2}$"
可以使用

,其中^表示字符串的开头,\\d{2}表示正好两位数的序列,$表示字符串的结尾。 AB代表自己。

使用此正则表达式,dplyrgrepl()可用于过滤输入数据框DF

library(dplyr)
#which rows are kept?
kept <- DF %>%
+   filter(grepl("^A\\d{2}B\\d{2}$", pair))
kept
#    pair
#1 A10B33
#2 A11B44

# which rows are removed?
removed <- DF %>%
+   filter(!grepl("^A\\d{2}B\\d{2}$", pair))
removed
#      pair
#1     A1B2
#2     A2B3
#3     A3B4
#4    A4B22
#5       AB
#6        A
#7        B
#8       A1
#9      A12
#10      B1
#11     B12
#12 AA12B34
#13 A12BB34

请注意,我添加了一些边缘案例进行演示。

BTW:如果只需要过滤矢量dplyr,则不需要pair。所以,在基础R中,替代表达式

pair[grepl("^A\\d{2}B\\d{2}$", pair)]
grep("^A\\d{2}B\\d{2}$", pair, value = TRUE)

都返回字符串以保持:

[1] "A10B33" "A11B44"

,而

pair[!grepl("^A\\d{2}B\\d{2}$", pair)]

返回已删除的字符串:

 [1] "A1B2"    "A2B3"    "A3B4"    "A4B22"   "AB"      "A"       "B"       "A1"     
 [9] "A12"     "B1"      "B12"     "AA12B34" "A12BB34"

数据

由OP给出但附加了一些边缘情况:

# create vector of test patterns using paste0() instead of paste(..., sep = "")
pair <- paste0("A", c(1:4, 10, 11), "B", c(2, 3, 4, 22, 33, 44))
# alternatvely use sprintf()
pair <- sprintf("A%iB%i", c(1:4, 10, 11), c(2, 3, 4, 22, 33, 44))
# add some edge cases
pair <- append(pair, c("AB", "A", "B", "A1", "A12", "B1", "B12", "AA12B34", "A12BB34"))
# create data frame
DF <- data.frame(pair)
DF
#      pair
#1     A1B2
#2     A2B3
#3     A3B4
#4    A4B22
#5   A10B33
#6   A11B44
#7       AB
#8        A
#9        B
#10      A1
#11     A12
#12      B1
#13     B12
#14 AA12B34
#15 A12BB34