正则表达式从文件路径R中提取字符串?

时间:2018-07-22 08:57:16

标签: r regex

我的文件路径中包含以下uuid:

  

“〜/ My_Files / F0 / F1 / F2 / 0b27ea5fad61c99d / 0b27ea5fad61c99d / 2015-04-1-04-25-12-925”

我想使用正则表达式提取它。 我知道我可以unlist(strsplit(string, "/"))并接受第7个元素,但对我来说似乎太慢了,解决问题的效率也不高。

这是我到目前为止尝试过的:

\w{16}

我一直在尝试玩这个游戏,请告知。

我要提取uuid:0b27ea5fad61c99d

5 个答案:

答案 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})

/(?=[a-f0-9]+[a-f])(?=[a-f0-9]+[0-9])([a-f0-9]{16})

答案 4 :(得分:1)

您可以使用正则表达式:

(?:[^\/]+\/){5}(\w+)

  • (?:非捕获组的开始。
    • [^\/]+\/除正斜杠/和正斜杠/之外的所有内容。
  • )关闭非捕获组。
  • {5}精确匹配前一个模式的五次出现。
  • (\w+)捕获组。贪婪地捕获字母数字字符。

感兴趣的子字符串包含在捕获组中。 您可以实时测试正则表达式here