既然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 ()