每逢 Comic Market(Comiket)大展期間,下載回來的同人誌、周邊檔案命名格式五花八門,若直接依檔名排序瀏覽極為不便。這時候就得祭出批次重命名腳本。筆者習慣用 Ruby 的 irb 互動環境快速撰寫一次性腳本,這次整理出的腳本可在多個分類目錄下通用,特此記錄備查。
目標檔名格式為 (Cxx)(item_type)[circle_name] item_name,腳本會將前綴標籤之間的多餘空格移除,並確保標籤整體與後方檔名之間僅保留一個空格。普通檔案與目錄皆為重命名對象;不符合「兩組圓括號 + 一組方括號」前綴格式的項目將被略過。筆者通常先用另一支腳本將各欄位順序調整為上述標準格式,再統一執行去空格動作。
#!/usr/bin/env ruby
def reformat_comiket_folder(dir='.')
Dir.entries(dir).each do |p|
begin
if p =~ /^\(([^)]+)\)\s*\(([^)]+)\)\s*\[([^\]]+)\]\s*(.+)$/
File.rename p, "(#{$1})(#{$2})[#{$3}] #{$4}"
end
rescue SystemCallError
$stderr.puts 'IO failed: ' + $!
end
end
end
if __FILE__ == $0
reformat_comiket_folder ARGV[0] || '.'
end
為徹底解決編碼問題,改以 C# 實作相同邏輯:
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
sealed class ReformatComiketFiles {
static bool TryGetRenameName(
Regex pattern, string input, string format,
out string result
) {
var match = pattern.Match(input);
if (match.Success) {
var str = string.Format(format,
match.Groups.Cast<Group>().Skip(1).Select(g => g.Value).ToArray());
result = str;
return str != input;
} else {
result = input;
return false;
}
}
static void Main(string[] args) {
DirectoryInfo root = (0 < args.Length)
? new DirectoryInfo(args[0])
: new DirectoryInfo(Environment.CurrentDirectory);
var pattern = new Regex(@"^\(([^)]+)\)\s*\(([^)]+)\)\s*\[([^\]]+)\]\s*(.+)$");
foreach (var dir in root.GetDirectories()) {
string dest = null;
if (TryGetRenameName(pattern, dir.Name, "({0})({1})[{2}] {3}", out dest)) {
Console.WriteLine(dest);
dir.MoveTo(Path.Combine(dir.Parent.FullName, dest));
}
}
foreach (var file in root.GetFiles()) {
string dest = null;
if (TryGetRenameName(pattern, file.Name, "({0})({1})[{2}] {3}", out dest)) {
Console.WriteLine(dest);
file.MoveTo(Path.Combine(file.DirectoryName, dest));
}
}
}
}
實測兩版腳本均能正常運作。C# 版本得益於 .NET 處理 Unicode 的完善支援,不再受編碼困擾,適合長期維護使用。