0

正規表現を使用して、大量のファイルの名前を一度にまとめて変更するユーティリティを作成しようとしています。一度に名前を変更するファイルは、特定の命名規則に従っており、すでにファイル名に含まれているデータを使用して、新しい命名規則に変更したいと思います。しかし、現在、すべてのファイルが同じ規則に従っているわけではありません。

そのため、実行時にファイル名のパターンと、ファイル名から抽出して名前の変更に使用するトークンをテキストボックスに入力できる汎用プログラムを作成できるようにしたいと考えています。

例-。という名前のファイルが1つあるとします[Coalgirls]_Suite_Precure_02_(1280x720_Blu-Ray_FLAC)_[33D74D55].mkv。このファイルの名前を次のように変更できるようにしたいSuite Precure - Ep 02 [Coalgirls][33D74D55].mkv

これは、何かに似た名前を変更する前にプログラムに入ることができれば[%group%]_Suite_Precure_%ep%_(...)_[%crc%].mkv、ローカル変数groupにデータepを入力crcし、バッチの名前変更に使用できることを意味します。

私が考えている特定のプログラムの1つは、ファイル名をid3タグに変換するために使用されるmp3tagです。%artist%-%album%-%tracknumber%-%title%のようなものを入れることができ、それらの4つのトークンを受け取り、それぞれのid3タグに入れます。

ユーザーに正規表現の構文を知らせずに、これに似たシステムを作成するにはどうすればよいですか?

4

2 に答える 2

2

usrで説明されているように、を使用して検索文字列内のすべての名前付きプレースホルダーを抽出できます%(?<name>[^%]+)%。これにより、「group」、「ep」、および「crc」が取得されます。

次に、プレースホルダー間のすべてのフラグメントをスキャンし、正規表現の各プレースホルダーにキャプチャを配置する必要があります。上から一致を繰り返します(プレースホルダー以外のフラグメントをナビゲートするために、各一致の開始オフセットと長さを取得できます)。

(あなたの例には間違いがあります、私は最後の部分が正しいと思います、そして私は神秘的なものを落としています(...))

次のような正規表現を作成します。

^%(?<group>.*?)_Suite_Precure_(?<ep>.*?)_(?<crc>.*?).mkv$

リテラルフラグメントをRegex.Escapeに渡してから、正規表現で使用して、厄介な文字を適切に処理します。

ここで、ファイル名ごとに、正規表現をそれに一致させようとします。一致する場合は、このファイルのプレースホルダーの値を取得します。次に、それらのプレースホルダー値を取得して出力パターンにマージし、プレースホルダーを適切に置き換えます。これにより、新しい名前が付けられ、名前を変更できます。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace renamer
{
    class RenameImpl
    {
        public static IEnumerable<Tuple<string,string>> RenameWithPatterns(
            string path, string curpattern, string newpattern,
            bool caseSensitive)
        {
            var placeholderNames = new List<string>();

            // Extract all the cur_placeholders from the user's input pattern
            var input_regex = new Regex(@"(\%[^%]+\%)");
            var cur_matches = input_regex.Matches(curpattern);
            var new_matches = input_regex.Matches(newpattern);
            var regex_pattern = new StringBuilder();

            if (!caseSensitive)
                regex_pattern.Append("(?i)");
            regex_pattern.Append('^');

            // Do a pass over the matches and grab info about each capture
            var cur_placeholders = new List<Tuple<string, int, int>>();
            var new_placeholders = new List<Tuple<string, int, int>>();
            for (var i = 0; i < cur_matches.Count; ++i)
            {
                var m = cur_matches[i];
                cur_placeholders.Add(new Tuple<string, int, int>(
                    m.Value, m.Index, m.Length));
            }
            for (var i = 0; i < new_matches.Count; ++i)
            {
                var m = new_matches[i];
                new_placeholders.Add(new Tuple<string, int, int>(
                    m.Value, m.Index, m.Length));
            }

            // Build the regular expression
            for (var i = 0; i < cur_placeholders.Count; ++i)
            {
                var ph = cur_placeholders[i];

                // Get the literal before the first capture if it is the first
                if (i == 0 && ph.Item2 > 0)
                    regex_pattern.Append(Regex.Escape(
                        curpattern.Substring(0, ph.Item2)));

                // Generate the capture for the placeholder
                regex_pattern.AppendFormat("(?<{0}>.*?)",
                    ph.Item1.Replace("%", ""));

                // The literal after the placeholder
                if (i + 1 == cur_placeholders.Count)
                    regex_pattern.Append(Regex.Escape(
                        curpattern.Substring(ph.Item2 + ph.Item3)));
                else
                    regex_pattern.Append(Regex.Escape(
                        curpattern.Substring(ph.Item2 + ph.Item3,
                        cur_placeholders[i + 1].Item2 - (ph.Item2 + ph.Item3))));
            }

            regex_pattern.Append('$');

            var re = new Regex(regex_pattern.ToString());

            foreach (var pathname in Directory.EnumerateFileSystemEntries(path))
            {
                var file = Path.GetFileName(pathname);
                var m = re.Match(file);

                if (!m.Success)
                    continue;

                // New name is initially same as target pattern 
                var newname = newpattern;

                // Iterate through the placeholder names
                for (var i = new_placeholders.Count; i > 0; --i)
                {
                    // Target placeholder name
                    var tn = new_placeholders[i-1].Item1.Replace("%", "");

                    // Get captured value for this capture
                    var ct = m.Groups[tn].Value;

                    // Perform the replacement
                    newname = newname.Remove(new_placeholders[i - 1].Item2,
                        new_placeholders[i - 1].Item3);
                    newname = newname.Insert(new_placeholders[i - 1].Item2, ct);
                }

                newname = Path.Combine(path, newname);
                yield return new Tuple<string, string>(pathname, newname);
            }
        }
    }
}
于 2012-12-16T01:09:34.813 に答える
1

正規表現パターンを作成し%(?<name>[^%]+)%ます。これにより、パーセント記号で囲まれた文字列内のすべてのトークンがキャプチャされます。

次に、を使用Regex.Replaceしてそれらを置き換えます。

var replaced = Regex.Replace(input, pattern, (Match m) => EvaluateToken(m.Groups["name"].Value));

Regex.Replace動的な値を提供できるコールバックを受け取ることができます。

于 2012-12-15T19:43:04.823 に答える