-1

我有一个字符串变量要解析成两部分。我想我会使用包中str_match的方法来解决这个问题stringr,它返回一个矩阵,第一列中包含原始字符串,而其他列中的每个提取部分。

我找到了大约十几个正则表达式来提取这两个部分。(这些部分是一个梯子,按工资计划排列,非常混乱。我已经通过使用一堆嵌套ifelse语句定义一个函数来验证我的正则表达式是否有效。)

library(stringr)
library(data.table)
my_strs <- c("A 01","G 00","A    2")
mydt <- data.table(strs = my_strs)

rx1 <- '^([[:alpha:]] )([[:digit:]]{2})$'
rx2 <- '(A)    ([[:digit:]])'

我想按顺序检查正则表达式并使用第一个签出的部分提取部分。如果我只有一个正则表达式,我可以这样做:

myfun <- function(x){
    y <- str_match(x,rx1)
    return(y)
}
mydt[,myfun(strs)] 
#      [,1]   [,2] [,3]
# [1,] "A 01" "A " "01"
# [2,] "G 00" "G " "00"
# [3,] NA     NA   NA  

(我花了很长时间才让它工作,尝试了函数的所有组合Vectorize以及调用中的 ing。)as.list*apply

我按顺序检查正则表达式的最佳尝试是这个相当丑陋的组合:

myfun2 <- function(x){
    y <- str_match(x,rx1)
    ifelse(!is.na(y[1]),"",(y <- str_match(x,rx2))[1])
    return(y)
}
mydt[1:2,myfun2(strs)] 
#      [,1]   [,2] [,3]
# [1,] "A 01" "A " "01"
# [2,] "G 00" "G " "00"
mydt[3,myfun2(strs)] 
#      [,1]     [,2] [,3]
# [1,] "A    2" "A"  "2" 
mydt[1:3,myfun2(strs)]
#      [,1]   [,2] [,3]
# [1,] "A 01" "A " "01"
# [2,] "G 00" "G " "00"
# [3,] NA     NA   NA  

如您所见,它还没有完全起作用。

您对解决此问题的更好方法有任何想法吗?我的数据集中有大约 3.5 m 行,但这个字符串只有大约 2000 个唯一值,所以我并不担心效率。

4

2 回答 2

1

尝试使用gsubfn 包strapply中的这个。我们定义了一个函数来接受匹配并返回前两个非空的。然后将它与 的每个组件的正则表达式一起使用:paste(rx1, rx2, sep = "|")my_str

library(gsubfn)

# test data
# there was an addition to the question in the comments.  It asked to be able to handle
# one regular expression which has only a single capture.  Make sure its at the end.
rx3 <- "^([[:digit:]]{2})$"
my_strs2 <- c(my_strs, "99")    

# code
first2 <- function(...) { x <- c(..., NA); head(x[x != ""], 2) }
strapply(my_strs2, paste(rx1, rx2, rx3, sep = "|"), first2, simplify = TRUE)

最后一行返回:

    [,1] [,2] [,3] [,4]
[1,] "A " "G " "A"  "99"
[2,] "01" "00" "2"  NA  

(如果其中的某些组件my_strs根本不匹配,则将返回一个列表,其中这些组件为 NULL。在这种情况下,您可能更愿意删除simplify = TRUE并始终让它返回一个列表。)

注意: strapplyc在同一个包中strapply因为它的核心是用 tcl(一种字符串处理语言)编写而用 R 编写的,所以要快得多strapply。因此,您可能希望以这种方式分解它以利用更快的例程:

L <- strapplyc(my_strs2, paste(rx1, rx2, rx3, sep = "|"))
sapply(L, first2)
于 2013-05-06T20:59:35.130 回答
0

对于后代,这是我今天找到的另一个解决方案:

mydt[,{
    i_rx <- min(which(unlist(sapply(rx_list,function(x)grepl(x,strs)))))
    as.list(str_match(strs,rx_list[[i_rx]]))
},by=1:nrow(mydt)]

我对正则表达式做了一些小的改动并将它们放在一个列表中。

rx1  <- '^([[:alpha:]] )([[:digit:]]{2})$'
rx2a <- "^(A)    ([[:digit:]])$"
rx3a <- "^()([[:digit:]]{2})$"
rx_list <- list(rx1,rx2a,rx3a)
于 2013-05-14T03:46:40.183 回答