将Comiket物的文件名格式统一化的脚本

又到了Comiket大潮,抓下来的文件的名字总是格式不统一,按照文件名排序来查看很不方便。于是又到了出动Ruby的时间~
(每次到批量重命名文件的时候我的第一反应就是打开irb……)
这次的脚本在好几个类别的目录下都能用,所以顺便记下来。

脚本作用:将类似 "(Cxx)(item_type)[circle_name] item_name"的文件名中开头部分的空格调整到:前缀标签间不包括空格,标签整体与后面的文件名之间留一个空格。普通文件和目录都是重命名的目标。不符合这种带有两组圆括号和一组方括号为前缀标签的文件则不在重命名目标范围内。我一般是用另外的脚本来把顺序都倒到这个顺序上然后再一起抽掉空格。
限制:如果文件名中出现了在当前系统locale下无法显示出来的字符,那么那个文件的重命名会失败;重命名失败不会影响后续循环,失败的文件名会显示到stderr。反正有特殊字符的文件/目录不会很多,暂时就手工修改算了 OTL
Ruby 1.8自身的编码是有点问题,而Ruby 1.9的字符串虽然能用UNICODE,但在执行这种操作的时候似乎还是处理不了。怪哉,可能我没写对还是怎样。回头再试试看。

#!/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#来写这个程序就不会出现编码问题。采用跟上面相似的逻辑,重写为:

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。
于是把编译出来的exe发到附件里。有需要的拿~

你可能感兴趣的:(正则表达式,脚本,Ruby,groovy,LINQ)