R:提取文件名的一部分

6
我希望能用R来提取文件名的一部分。从以下链接中,我有一个大致的想法:extract part of a file name in R 但是我无法将其应用于我的文件名列表。
文件名示例:
"Species Count (2011-12-15-07-09-39).xls"
"Species Count 0511.xls"
"Species Count 151112.xls" 
"Species Count1011.xls" 
"Species Count2012-01.xls" 
"Species Count201207.xls" 
"Species Count2013-01-15.xls"  

一些文件名间在物种数量和日期之间有空格,一些没有空格,它们的长度也不同,有些还包含括号。我只想提取文件名中的数字部分,并同时保留连字符。例如上面的数据,我会得到以下输出:

期望输出:

2011-12-15-07-09-39 , 0511 , 151112 , 1011 , 2012-01 , 201207 , 2013-01-15
4个回答

7
以下是一种方法:
regmatches(tt, regexpr("[0-9].*[0-9]", tt))

我假设你的文件名中没有其他数字。因此,我们只需搜索数字的开头并使用贪婪运算符.*来捕获最后一个数字之前的所有内容。这是通过使用regexpr来获取匹配位置来完成的。然后,我们使用regmatches从这些匹配位置中提取(子)字符串。


其中tt是:

tt <- c("Species Count (2011-12-15-07-09-39).xls", "Species Count 0511.xls", 
        "Species Count 151112.xls", "Species Count1011.xls", 
        "Species Count2012-01.xls", "Species Count201207.xls", 
        "Species Count2013-01-15.xls")

基准测试:

注意:基准测试结果可能因操作系统不同而有所不同(如下方评论中@Hansi所述)。

这里有一些很好的答案。现在是进行基准测试的时候了 :)

tt <- rep(tt, 1e5) # tt is from above

require(microbenchmark)
require(stringr)
aa <- function() regmatches(tt, regexpr("[0-9].*[0-9]", tt))
bb <- function() gsub("[A-z \\.\\(\\)]", "", tt)
cc <- function() str_extract(tt,'([0-9]|[0-9][-])+')

microbenchmark(arun <- aa(), agstudy <- cc(), Jean <- bb(), times=25)
Unit: seconds
            expr      min       lq   median       uq       max neval
    arun <- aa() 1.951362 2.064055 2.198644 2.397724  3.236296    25
 agstudy <- cc() 2.489993 2.685285 2.991796 3.198133  3.762166    25
    Jean <- bb() 7.824638 8.026595 9.145490 9.788539 10.926665    25

identical(arun, agstudy) # TRUE
identical(arun, Jean) # TRUE

我认为你的评论应该针对原帖问题或作为一个独立的回答。 - Arun
1
请注意,添加 perl=TRUE 将使所有这些解决方案运行得更快(gsub 具有最大的速度提升,尽管比其他方法慢)- 这里没有进行基准测试。 - Arun
@Hansi,我已经在R 3.0.1 Mac Mountain Lion 10.8.3上以及现在在Debian Linux集群R 2.15.2上尝试过了。而且顺序没有改变(arun = 2,agstudy = 2.5和jean = 5.5秒)。 - Arun
在微基准测试调用中假设了aa,bb,cc,但没有注意到bb和cc被翻转了。不小心删除了我的评论而不是编辑它。个人会使用带有“[^ 0-9 \ -]”的gsub,但它只比上面略快一些。对于我来说,str_extract仍然比regmatches更快。 - Hansi
@Hansi,“stringr”包主要是基于基本函数的封装。str_extract使用了str_locate,而str_locate在内部使用了regexpr。因此,考虑到函数开销来到达regexpr,我不认为它会更快。从概念上讲,gsub应该更慢,因为它多次(全局)搜索模式,而不是像regexpr一样只搜索一次(注意它不是gregexpr)。 - Arun
显示剩余4条评论

5
使用函数gsub()来删除所有的字母,空格,句号和括号。然后你就只剩下数字和连字符了。例如:
x <- c("Species Count (2011-12-15-07-09-39).xls", "Species Count 0511.xls", 
    "Species Count 151112.xls", "Species Count1011.xls", "Species Count2012-01.xls", 
    "Species Count201207.xls", "Species Count2013-01-15.xls")

gsub("[A-z \\.\\(\\)]", "", x)

[1] "2011-12-15-07-09-39" "0511"                "151112"             
[4] "1011"                "2012-01"             "201207"             
[7] "2013-01-15"         

+1. 这个答案没有问题。只是我尽可能避免全局搜索。在更大的数据上,这会变得更慢。尝试执行 tt <- rep(tt, 1e5) 并将其与 regexpr 进行比较测试。 - Arun

2

如果您关心速度,可以使用带回溯引用的sub来提取所需部分。还要注意,根据?grepperl=TRUE通常更快。

jj <- function() sub("[^0-9]*([0-9].*[0-9])[^0-9]*", "\\1", tt, perl=TRUE)
aa <- function() regmatches(tt, regexpr("[0-9].*[0-9]", tt, perl=TRUE))

# Run on R-2.15.2 on 32-bit Windows
microbenchmark(arun <- aa(), josh <- jj(), times=25)
# Unit: milliseconds
#           expr       min        lq    median        uq       max
# 1 arun <- aa() 2156.5024 2189.5168 2191.9972 2195.4176 2410.3255
# 2 josh <- jj()  390.0142  390.8956  391.6431  394.5439  493.2545
identical(arun, josh)  # TRUE

# Run on R-3.0.1 on 64-bit Ubuntu
microbenchmark(arun <- aa(), josh <- jj(), times=25)
# Unit: seconds
#          expr      min       lq   median       uq      max neval
#  arun <- aa() 1.794522 1.839044 1.858556 1.894946 2.207016    25
#  josh <- jj() 1.003365 1.008424 1.009742 1.059129 1.074057    25
identical(arun, josh)  # still TRUE

1
使用stringr包提取仅包含数字或数字后跟-的所有字符串:
library(stringr)
str_extract(ll,'([0-9]|[0-9][-])+')

[1] "2011-12-15-07-09-39" "0511"               
    "151112"              "1011"                "2012-01"            
[6] "201207"              "2013-01-15"         

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接