【问题标题】:Extracting folder, filename and extension from path从路径中提取文件夹、文件名和扩展名
【发布时间】:2018-07-06 22:22:16
【问题描述】:

我有一个包含文件路径和名称的数据框,格式如下:

files_list <- c(
  "C:/User/Name/Folder/Subfolder1/Sub-subfolder/file.txt", 
  "C:/User/Name/Folder/Subfolder1/Sub-subfolder/file - Copy.txt",
  "C:/User/Name/Folder/Subfolder1/Sub-subfolder/file (1).txt",
  "C:/User/Name/Folder/Subfolder1/Sub-subfolder/file - Copy (2).txt",
  "C:/User/Name/Folder/Subfolder1/fileB.txt",
  "C:/User/Name/Folder/file.C.txt",
  "C:/User/Name/Folder/file-D.txt", 
  "C:/User/Name/Folder/file",
  "C:/User/Name/Folder/file Z.txt", 
  "C:/User/Name/Folder/file - backup.txt"
)

每个文件都有一个父文件夹和一个名称。这些名称可能包含一个或多个句点“.”。和/或破折号“-”。此外,有些具有“复制”符号、编号指定和/或文件扩展名。我想将数据转换为如下所示:

[1]  "Sub-subfolder   file   txt"
[2]  "Sub-subfolder   file   Copy   txt"
[3]  "Sub-subfolder   file   1   txt"
[4]  "Sub-subfolder   file   Copy   2   txt"
[5]  "Subfolder1   fileB   txt"
[6]  "Folder   file.C   txt"
[7]  "Folder   file-D   txt"
[8]  "Folder   file"
[9]  "Folder   file Z   txt"
[10] "Folder   file - backup   txt"

这是我认为应该可以解决问题的代码:

sub(
  "(^.:/)([^/.]+/)*([^/.]+/)([^/]+)(\\s-\\sCopy)?(\\s\\(([0-9]+)\\))?(\\.([^.]+))?$", 
  "\\3   \\4   \\5   \\7   \\9",
  files_list
)

但我得到的是:

[1] "Sub-subfolder/   file.txt         "           
[2] "Sub-subfolder/   file - Copy.txt         "    
[3] "Sub-subfolder/   file (1).txt         "       
[4] "Sub-subfolder/   file - Copy (2).txt         "
[5] "Subfolder1/   fileB.txt         "             
[6] "Folder/   file.C.txt         "                
[7] "Folder/   file-D.txt         "                

斜线“/”和多余的空格我可以处理,但“复制”符号、数字名称和文件扩展名并没有像我预期的那样分开。

关于如何识别“复制”符号、数字名称和文件扩展名有什么建议吗?还是应该只在一行代码中标识父文件夹,然后在另一行中分隔其余文件夹?

(最终,我要将这些文本字符串转换为一个数据框,其中文件夹、文件名、复制名称和扩展名是单独的列。我很确定我可以用tidyr::separate 做到这一点,但即使这需要了解正则表达式,我想学习如何使用() 和反向引用。)

【问题讨论】:

  • 不要用评论来澄清问题。 编辑问题以澄清它。删除评论。
  • dirnamebasenametools::file_ext
  • 我在 寻找 tools::file_ext,但我一直忘记 tools 默认不在搜索路径中。 (但我认为,这个问题的难点在于 Copy 和数字等的特殊情况。)
  • Josh,你用这个抽象的单字符串 thingamajig 做什么?它没有分栏,因此表格格式不能很好地(或一致地)工作;它不支持文件访问,所以自动化已经过时了; ... ??

标签: r regex backreference


【解决方案1】:

这可能会有所帮助:

library(tools)
as.data.frame(cbind(dirname(files_list), file_path_sans_ext(basename(files_list)), file_ext(files_list)))
#                                            V1              V2  V3
#1 C:/User/Name/Folder/Subfolder1/Sub-subfolder            file txt
#2 C:/User/Name/Folder/Subfolder1/Sub-subfolder     file - Copy txt
#3 C:/User/Name/Folder/Subfolder1/Sub-subfolder        file (1) txt
#4 C:/User/Name/Folder/Subfolder1/Sub-subfolder file - Copy (2) txt
#5               C:/User/Name/Folder/Subfolder1           fileB txt
#6                          C:/User/Name/Folder          file.C txt
#7                          C:/User/Name/Folder          file-D txt
#8                          C:/User/Name/Folder            file    

【讨论】:

  • 你的方法比我的聪明多了。谢谢!
【解决方案2】:

我仍然不知道您是否需要将它们作为字符串:如下所示

gsub("[/().]| - "," ",sub(".*?([^/]+/[^/]+$)","\\1",files_list))

[1] "Sub-subfolder file txt"         
[2] "Sub-subfolder file Copy txt"    
[3] "Sub-subfolder file  1  txt"     
[4] "Sub-subfolder file Copy  2  txt"
[5] "Subfolder1 fileB txt"           
[6] "Folder file C txt"              
[7] "Folder file-D txt"              
[8] "Folder file"  

如果你只需要一种模式,那么:

pattern="[^/]+(?=/[^/]+$)|\\w+(?=[ ).-])|\\w+$"
regmatches(files_list,gregexpr(pattern,files_list,perl = TRUE))

Demo

【讨论】:

  • 您的 gsub 代码完全符合我的要求。不幸的是,我忘记在其中包含一个带有空格“”的示例文件。我正在玩你的代码,看看我能不能让它工作。谢谢。
  • @Josh 你在哪里漏掉了?
  • 您回复后,我将其添加到示例中。您的代码适当地处理了一个空格“”,但是您的代码失败了,因为我忘记在原始示例中包含另一个文件名,但后来添加了:“ - ”,后面没有“复制”。抱歉,我一直在考虑可能会使我正在尝试做的事情复杂化的文件名。
【解决方案3】:

抱歉,如果这不是最好的方法。我意识到我的问题不完整,我想让问题更完整,同时也分享我想出的解决方案。

我希望这段代码能够处理所有可能的名称结构:

  1. “C:/”或任何其他目录/子目录中的文件
  2. 具有以下任何字符/功能的文件名
    • “。”之前 ”。”在文件扩展名的开头
    • “-”或“-”不属于“-复制”
    • " " 或 "(" 不是文件名末尾的 " (number)" 的一部分

我使用此代码生成示例文件名/路径,涵盖所有文件夹/名称/副本/编号/扩展名组合:

files.df <- expand.grid(
    c("C:/"), 
    c("", "F1/", "F1/F2/"), 
    c("folder/"), 
    c("file"), 
    c("", " space", "-dash", " - spacedash", ".period", ".firstperiod.secondperiod"), 
    c("", 1, " 1", 10, " 10"), 
    c("", " - Copy"), 
    c("", " (1)", " (10)"), 
    c("", ".999", ".aaa"), 
    stringsAsFactors = F
)

for (i in 1:nrow(files.df)) {
    if (!exists("x")) {
        x <- vector(mode="character", length=0)
    }
    x[i] <- paste(as.character(as.vector(files.df[i, ])), sep = "", collapse = "")
}

通过使用(regex101,感谢@Onyambu!)的大量试验和错误,我整理了以下实际可行的荒谬正则表达式:

sum(grepl(
    "^.:/(([^/]+)(?=/)/?)*(?<=/)(([^/](?! - Copy| \\([0-9]+\\)|\\.[^/\\.]+$))+.)( - )?((?<= - )Copy(?= \\([0-9]+\\)(?=\\.[^/\\.]+$|$)|\\.[^/\\.]+$|$))?( \\()?((?<= \\()([0-9]+)\\)(?=\\.[^/\\.]+$|$))?\\.?((?<=\\.)([^/\\.]+))?$", 
    x,
    perl = T
))
[1] 1620

length(x)
[1] 1620

不幸的是,这个正则表达式包含 10 个捕获组,我只能反向引用其中的 9 个(而 #10 是文件扩展名)。所以我将使用@RHertel 更优雅的解决方案。但如果有人发现减少捕获组数量的方法,请告诉我!

【讨论】:

    猜你喜欢
    • 2011-12-08
    • 2012-10-06
    • 2012-10-11
    • 1970-01-01
    • 1970-01-01
    • 2011-03-10
    • 1970-01-01
    • 2020-11-20
    相关资源
    最近更新 更多