既然Ruby的簡單版和C#的版本都寫了,寫個F#版來對比一下也不錯。
下面的程序邏輯基本上與前一篇的C#版類似,只是在如何抽取出文件名中的各部分的實現用了不同的劃分方式:C#版的TryGetRenameName()方法更傾向於直接支持不同的pattern和format;F#版則是直接把pattern和format硬編碼到parseFilename和getReformattedFilename函數裡了。到底該怎麼劃分好我也不太肯定,不過在這麼小的程序裡劃分方式好不好體現不出來,或許也不值得多想吧?
ReformatComiketFilenames.fsx
F#代碼
#light open System open System.IO open System.Text.RegularExpressions let parseFilename name = let result = Regex.Match(name, @"^\(([^)]+)\)\s*\(([^)]+)\)\s*\[([^\]]+)\]\s*(.+)$") let success = result.Success let comiketNum = result.Groups.Item(1).Value let contentType = result.Groups.Item(2).Value let circleName = result.Groups.Item(3).Value let itemName = result.Groups.Item(4).Value success, comiketNum, contentType, circleName, itemName let getReformattedFilename name = let success, comiketNum, contentType, circleName, itemName = parseFilename name if success then sprintf "(%s)(%s)[%s] %s" comiketNum contentType circleName itemName else name let reformatAndRenameDir (dirInfo : DirectoryInfo) = let name = dirInfo.Name let destName = getReformattedFilename name if name <> destName then printfn "%s" destName dirInfo.MoveTo(Path.Combine(dirInfo.Parent.FullName, destName)) true else false let reformatAndRenameFile (fileInfo : FileInfo) = let name = fileInfo.Name let destName = getReformattedFilename name if name <> destName then printfn "%s" destName fileInfo.MoveTo(Path.Combine(fileInfo.DirectoryName, destName)) true else false let getRootDir = fun () -> #if COMPILED let args = Environment.GetCommandLineArgs () #else let args = fsi.CommandLineArgs #endif let rootPath = match args with | [| _ |] -> new DirectoryInfo(Environment.CurrentDirectory); | _ -> new DirectoryInfo(args.[1]) rootPath let main = fun () -> let root = getRootDir () Array.iter (fun dir -> (reformatAndRenameDir dir; ())) (root.GetDirectories()) Array.iter (fun file -> (reformatAndRenameFile file; ())) (root.GetFiles()) main ()