又到了Comiket大潮,抓下來的文件的名字總是格式不統一,按照文件名排序來查看很不方便。於是又到了出動Ruby的時間~
(每次到批量重命名文件的時候我的第一反應就是打開irb……)
這次的腳本在好幾個類別的目錄下都能用,所以順便記下來。
腳本作用:將類似"(Cxx)(item_type)[circle_name] item_name"的文件名中開頭部分的空格調整到:前綴標簽間不包括空格,標簽整體與後面的文件名之間留一個空格。普通文件和目錄都是重命名的目標。不符合這種帶有兩組圓括號和一組方括號為前綴標簽的文件則不在重命名目標范圍內。我一般是用另外的腳本來把順序都倒到這個順序上然後再一起抽掉空格。
限制:如果文件名中出現了在當前系統locale下無法顯示出來的字符,那麼那個文件的重命名會失敗;重命名失敗不會影響後續循環,失敗的文件名會顯示到stderr。反正有特殊字符的文件/目錄不會很多,暫時就手工修改算了 OTL
Ruby 1.8自身的編碼是有點問題,而Ruby 1.9的字符串雖然能用UNICODE,但在執行這種操作的時候似乎還是處理不了。怪哉,可能我沒寫對還是怎樣。回頭再試試看。
Ruby代碼
#!/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
其實用這腳本心裡有點癢……又想起之前在寫的重命名工具了。找個時間把它寫完就好了 T T
當然咯,用C#來寫這個程序就不會出現編碼問題。采用跟上面相似的邏輯,重寫為:
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, // format items in this param correspond to match.Groups[1..$] 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 != src; // using a local variable here saves an indirect read } else { result = input; return false; } } static void Main( string[ ] args ) { DirectoryInfo root; if ( 0 < args.Length ) { root = new DirectoryInfo( args[ 0 ] ); } else { root = 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 ) ); } } } }
試了下,似乎都能行。運行環境是.NET Framework 3.5 SP1。