我的文件路径中包含以下uuid:
“〜/ My_Files / F0 / F1 / F2 / 0b27ea5fad61c99d / 0b27ea5fad61c99d / 2015-04-1-04-25-12-925”
我想使用正则表达式提取它。
我知道我可以unlist(strsplit(string, "/"))
并接受第7个元素,但对我来说似乎太慢了,解决问题的效率也不高。
这是我到目前为止尝试过的:
\w{16}
我一直在尝试玩这个游戏,请告知。
我要提取uuid:0b27ea5fad61c99d
答案 0 :(得分:3)
您是否进行过一些有关计时的基准测试?我认为您自己的解决方案已经非常不错,尤其是在引入fixed = T
的情况下进行了一些改进。请参阅以下时序。当您已经知道在哪里分割字符串的确切符号时,为什么要开始复杂的正则表达式搜索...
有关注释的更新:矢量化版本显示,f2表示的性能不是最好,但仍然可以接受。但是,正如评论中指出的那样,向量化的正则表达式方法通常会随着向量长度的增加而表现更好-当然,如果您对目录名称的结构了解较少,它们会更加灵活。
更新2:如果仍然有人感兴趣,我已经通过使用一种更好的方式访问列表的子元素来更新了功能f2。现在,至少对于500个项目的基准而言,这使它成为特定示例的最快方法。
library(microbenchmark)
library(stringi)
string = "~/My_Files/F0/F1/F2/0b27ea5fad61c99d/0b27ea5fad61c99d/2015-04-1-04-25-12-925"
string = rep(string, 500)
f1 = function(x) sapply(strsplit(x, "/"), `[[`, 7)
f2 = function(x) sapply(strsplit(x, "/", fixed = T), `[[`, 7)
f2b = function(x) sapply(stri_split_fixed(string, "/"), `[[`, 7)
f3 = function(x) stri_extract_first_regex(x, "(?=[a-f0-9]+[a-f])(?=[a-f0-9]+[0-9])([a-f0-9]{16})")
f4 = function(x) sapply(x, function(y) tail(unlist(strsplit(dirname(x), "/")),1), USE.NAMES = FALSE)
f5 = function(x) basename(dirname(x))
f6 = function(x) gsub("([^/]*)/([^/]*)/([^/]*)/([^/]*)/([^/]*)/([^/][0-9a-z]+)/(.*)","\\6",x)
f7 = function(x) sub("^.*/(.*)$", "\\1", dirname(x))
f8 = function(x) sub(".*/(.*)/[^/]+$","\\1",x)
bm = microbenchmark(
(a = f1(string))
,(b = f2(string))
, (b2 = f2b(string))
,(c = f3(string))
, (d = f4(string))
, (e = f5(string))
, (f = f6(string))
, (g = f7(string))
, (h = f8(string))
, times = 25)
bm
# Unit: microseconds
# expr min lq mean median uq max neval
# (a = f1(string)) 1894.017 1947.307 2083.6390 2072.444 2142.709 2896.684 25
# (b = f2(string)) 532.520 575.153 605.7698 592.917 630.813 823.451 25
# (b2 = f2b(string)) 545.152 569.232 617.1387 606.733 637.129 778.450 25
# (c = f3(string)) 855.426 894.112 953.5931 946.614 999.511 1286.890 25
# (d = f4(string)) 2497889.661 2538700.607 2604673.5850 2602081.839 2654385.172 2820226.019 25
# (e = f5(string)) 4686.881 4935.573 5087.7735 5155.450 5201.240 5544.674 25
# (f = f6(string)) 5991.532 6357.861 6750.8284 6584.054 6886.039 9232.438 25
# (g = f7(string)) 4313.840 4462.661 4770.6780 4696.749 4900.046 6442.733 25
# (h = f8(string)) 2328.637 2422.193 2620.5163 2606.542 2660.229 3697.239 25
all(all.equal(a, b)
,all.equal(a, c)
,all.equal(a, d)
,all.equal(a, e)
,all.equal(a, f)
,all.equal(a, g)
,all.equal(a, b2)
,all.equal(a, h)
)
# TRUE
答案 1 :(得分:3)
编辑: 根据Onyambu的评论,现在也添加了以下解决方案。
sub(".*/(.*)/[^/]+$","\\1",val)
请问您可以尝试将gsub
函数移至基础R
的位置,并告诉我这是否对您有帮助。
gsub("([^/]*)/([^/]*)/([^/]*)/([^/]*)/([^/]*)/([^/][0-9a-z]+)/(.*)","\\6",val)
说明: 这是上面代码段的简要说明。
([^/]*)
:选择从开始到/
的所有内容,并将其保留在内存的首位。
/
:然后提及/
。
再次重复上述两个步骤,直到5次,以选择([^/][0-9a-z]+)
所提到的第六个字段,然后/(.*)
意味着将所有剩余的匹配项都放在第七个存储位置。
"\\6"
:现在将变量val
的整个值替换为仅第6个存储位置,OP实际需要这些存储位置才能获得所需的结果。
答案 2 :(得分:3)
这是一个有点笨拙但紧凑且无正则表达式的解决方案:
basename(dirname(x))
#[1] "0b27ea5fad61c99d"
哪里
x <- "~/My_Files/F0/F1/F2/0b27ea5fad61c99d/0b27ea5fad61c99d/2015-04-1-04-25-12-925"
答案 3 :(得分:2)
您可以匹配一个正斜杠,然后使用正数使用2个正向前行(?=
来断言紧随其后的是至少[a-f]
和至少[0-9]
。然后捕获到([a-f0-9]{16})
组
答案 4 :(得分:1)
您可以使用正则表达式:
(?:[^\/]+\/){5}(\w+)
(?:
非捕获组的开始。
[^\/]+\/
除正斜杠/
和正斜杠/
之外的所有内容。)
关闭非捕获组。{5}
精确匹配前一个模式的五次出现。(\w+)
捕获组。贪婪地捕获字母数字字符。感兴趣的子字符串包含在捕获组中。 您可以实时测试正则表达式here。