Last active
December 23, 2015 11:09
-
-
Save tfwio/6626538 to your computer and use it in GitHub Desktop.
a batch file-rename tool that could use some work.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region User/License | |
// Copyright (c) 2005-2013 tfwroble | |
// | |
// Permission is hereby granted, free of charge, to any person | |
// obtaining a copy of this software and associated documentation | |
// files (the "Software"), to deal in the Software without | |
// restriction, including without limitation the rights to use, | |
// copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the | |
// Software is furnished to do so, subject to the following | |
// conditions: | |
// | |
// The above copyright notice and this permission notice shall be | |
// included in all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
// OTHER DEALINGS IN THE SOFTWARE. | |
#endregion | |
// ---------------------------------------------------------------------------- | |
// 'it just works' | |
// ---------------------------------------------------------------------------- | |
// usage: | |
// [todo] web address or article | |
// ---------------------------------------------------------------------------- | |
// why: | |
// you can look up command-line arguments fairly easy with very | |
// few lines of code. | |
// ---------------------------------------------------------------------------- | |
// history: | |
// (1) in a old 'study-project' using sqlite to store 'resources' such as images and | |
// what-ever you might think to store in a resources or resx file. | |
// (2) added to my personal litte cor3 library (of dependency-less) cor3 library | |
// for use in a csharp command-line application/tool 'xrename' for batch rename | |
// of indexed (easily-sortable) files in a directory. | |
// ---------------------------------------------------------------------------- | |
// TODO: BETTER DOCUMENTATION!!! | |
// best way to see how to use this is to see it in action with some examples. | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
namespace System | |
{ | |
// feel free to optimize and/or | |
class Commander | |
{ | |
static public readonly char[] char_trimExt = {'*','.',' '}; | |
static public int ArgIndex = 0; | |
internal List<string> Args, ArgsBackup; | |
/// <summary> | |
/// look up the first found index of the same argument. | |
/// </summary> | |
/// <param name="arguments">N arguments, all representing the same flag.</param> | |
/// <returns>-1 when none found or the first found index.</returns> | |
internal int GetIndex(params string[] arguments) | |
{ | |
foreach (string argument in arguments) | |
{ | |
if (Args.Contains(argument)) | |
return Args.IndexOf(argument); | |
} | |
return -1; | |
} | |
/// <summary> | |
/// equivelant to 'GetValue(index,false);' | |
/// </summary> | |
/// <param name="index"></param> | |
/// <returns></returns> | |
internal string PeekValue(int index) | |
{ | |
return GetValue(index,false); | |
} | |
/// <summary> | |
/// Get a value and delete from list of arguments: 'Args'; | |
/// Something like a Stack.Pop() operation. | |
/// </summary> | |
/// <param name="index">parameter index</param> | |
/// <param name="andRemove">default is true.</param> | |
/// <returns></returns> | |
internal string GetValue(int index, bool andRemove=true) | |
{ | |
string v = Args[index]; | |
if (andRemove) Args.RemoveAt(index); | |
return v; | |
} | |
/// <summary> | |
/// The following (param: getValue) statements apply only if the argument or tag is found. | |
/// </summary> | |
/// <param name="getValue"> | |
/// <para>True to return a value for the argument clearing both.</para> | |
/// <para>False to clear the argument and return string.empty or null.</para> | |
/// </param> | |
/// <param name="attributes"> | |
/// <para>attributes to search for</para> | |
/// <para>The first found attribute is processed and removed.</para> | |
/// </param> | |
/// <returns> | |
/// (1) null if we have not found our argument. | |
/// (2) string.Empty if we have found the argument (getValue=false). | |
/// (3) string value if getValue=true and there is a value to return. | |
/// </returns> | |
internal string GetValue(bool getValue, params string[] attributes) | |
{ | |
int index = -1; | |
string returned = null; | |
foreach (string attribute in attributes) | |
{ | |
if (!Args.Contains(attribute)) continue; | |
index = Args.FindIndex(x => x==attribute); | |
if (index!=-1) Args.RemoveAt(index); | |
else continue; | |
// this could cause issues, but we leave it. | |
if (Args.Count==index) continue; | |
if (Args[index][0]=='-') continue; | |
if (Args[index][0]=='/') continue; | |
// if we've gotten here, we get what we came for. | |
if (getValue) { returned = Args[ index ]; Args.RemoveAt( index ); } | |
else { returned = string.Empty; break; } | |
} | |
return returned; | |
} | |
/// <summary> | |
/// this one is not ready yet. | |
/// <para>We're looking up values for a provided flag.</para> | |
/// | |
/// </summary> | |
/// <param name="attributes"></param> | |
/// <returns></returns> | |
internal List<string> GetValues(params string[] attributes) | |
{ | |
int index = -1; | |
List<string> values = new List<string>(); | |
foreach (string attribute in attributes) | |
{ | |
// get the index of the attribute | |
index = Args.FindIndex(x => x==attribute); | |
// if found, assign index and remove first item at index | |
if (index!=-1) { | |
values.Add(Args[index]); // back up our current | |
Args.RemoveAt(index); | |
} | |
// foreach-continue if no index | |
else continue; | |
while (true) | |
{ | |
// break on next tag or end | |
if (index == Args.Count) break; | |
if (Args[index][0] == '-') break; | |
if (Args[index][0] == '/') break; | |
// continue if we've got arguments to count. | |
string x = Args[index]; | |
Args.RemoveAt(index); | |
values.Add(x.Trim('*','.',' ')); | |
} | |
} | |
return values; | |
} | |
public List<string> GetValuesForArgument(params string[] attributes) | |
{ | |
return GetValuesForArgument(false, attributes); | |
} | |
// var finalize has not yet been implemented. | |
List<string> GetValuesForArgument(bool finalize, params string[] attributes) | |
{ | |
List<string> VALUE = new List<string>(); | |
foreach (var attr in attributes) | |
{ | |
if (Args.Contains(attr)) { | |
// get the index of the attribute | |
int index = Args.FindIndex(x => x==attr); | |
// iterate to the next for-loop point if necessary. | |
if (index==-1) continue; | |
// if found, assign index and remove first item at index | |
// note that we always will find due to our 'args.contains()' usage. | |
else if (index!=-1) { | |
// VALUE.Add(Args[index]); // un-comment if we want the starting var-name | |
Args.RemoveAt(index); | |
VALUE.AddRange(GetValuesForIndex(index)); | |
} | |
// foreach-continue if no index | |
else continue; | |
} | |
} | |
return VALUE; | |
} | |
public List<String> GetValuesForIndex(int index) | |
{ | |
List<string> ITEMS = new List<string>(); | |
while (true) { | |
if (index == Args.Count) break; | |
if (Args[index][0] == '-') break; | |
if (Args[index][0] == '/') break; | |
string x = Args[index]; | |
Args.RemoveAt(index); | |
Debug.WriteLine("adding: {0}",x); | |
ITEMS.Add(x.Trim(char_trimExt)); | |
} | |
return ITEMS; | |
} | |
/// <summary> | |
/// use this method if | |
/// (1) all known flags are stripped from arguments. | |
/// </summary> | |
/// <param name="attributes"></param> | |
/// <returns></returns> | |
List<string> GetLeftovers(params string[] attributes) | |
{ | |
return GetValuesForArgument(true,attributes); | |
} | |
public string GetFlag(params string[] arg) | |
{ | |
int index = GetIndex(arg); | |
return (GetIndex(arg)!=-1) ? GetValue(true,arg) : null; | |
} | |
public bool HasValue(params string[] arg) | |
{ | |
foreach (string a in arg) if (Args.Contains(a)) return true; | |
return false; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#region Using | |
/* User: oio * Date: 9/18/2013 * Time: 12:54 AM */ | |
using System; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using System.Text.RegularExpressions; | |
using System.IO; | |
#endregion | |
#region AssemblyProperties | |
using System.Reflection; | |
using System.Runtime.InteropServices; | |
[assembly: AssemblyTitle("xrename")] | |
[assembly: AssemblyProduct("xrename")] | |
[assembly: ComVisible(false)] | |
[assembly: AssemblyVersion("1.0.*")] | |
#endregion AssemblyProperties | |
// | |
namespace xrename | |
{ | |
// public interface ILesserAction { | |
// void Run(); | |
// } | |
/// <summary> | |
/// <para>A batch tool for renaming multiple files to a format such as "file000.ext"</para> | |
/// </summary> | |
class Rename : Commander /*, ILesserAction*/ | |
{ | |
#region Node | |
class Node | |
{ | |
public FileInfo OldFile; | |
/// <summary> | |
/// the new name identity of the file. | |
/// </summary> | |
public string Name; | |
public string NameExt { get { return string.Concat(Name,OldFile.Extension); } } | |
public string NameFull { get { return OldFile.FullName.Replace(OldFile.Name,NameExt); } } | |
public bool HasMatch = false; | |
} | |
#endregion | |
#region Settings | |
class Setting | |
{ | |
/// <summary> | |
/// default state is un-initialized. | |
/// </summary> | |
public List<string> Items { | |
get { return items; } | |
set { items = value; } | |
} List<string> items; | |
// OPTIONS | |
// ================================================================ | |
/// <summary> | |
/// default = 'false' | |
/// </summary> | |
public bool Recursive { | |
get { return recursive; } | |
set { recursive = value; } | |
} bool recursive = false; | |
/// <summary> | |
/// default = 'false' | |
/// </summary> | |
public bool Reverse { | |
get { return reverse; } | |
set { reverse = value; } | |
} bool reverse = false; | |
/// <summary> | |
/// default = 'false' | |
/// </summary> | |
public bool OnlyUseMatches { | |
get { return onlyUseMatches; } | |
set { onlyUseMatches = value; } | |
} bool onlyUseMatches = false; | |
/// <summary> | |
/// default = 'false' | |
/// </summary> | |
public bool SortPost { | |
get { return sortPost; } | |
set { sortPost = value; } | |
} bool sortPost = false; | |
public bool SortPre { | |
get { return sortPre; } | |
set { sortPre = value; } | |
} bool sortPre = false; | |
/// <summary> | |
/// default = 'null' | |
/// </summary> | |
public string Expression { | |
get { return expression; } | |
set { expression = value; } | |
} string expression = null; | |
/// <summary> | |
/// default = 'rename-temp' | |
/// </summary> | |
public string OutputDir { | |
get { return outputDir; } | |
set { outputDir = value; } | |
} string outputDir = "rename-temp"; | |
/// <summary> | |
/// default = 'null' | |
/// </summary> | |
public string ExpressionReplace { | |
get { return expressionReplace; } | |
set { expressionReplace = value; } | |
} string expressionReplace = null; | |
#region Automate | |
const RegexOptions DefaultRegexOptions = RegexOptions.Singleline|RegexOptions.Compiled; | |
/// <summary> | |
/// | |
/// </summary> | |
public Regex RegularExpression { get { return new Regex(Expression,DefaultRegexOptions); } } | |
bool IsMatch(string input) { return string.IsNullOrEmpty(Expression) ? false : RegularExpression.IsMatch(input); } | |
#endregion | |
} | |
Setting Settings { get; set; } | |
#endregion | |
// -sort -r -i "c:\blah\blah\blah\" -x "a-title-([0-9.-]*)" -xr "SortIndex=$1" | |
// -spr -i "c:\blah\blah\blah\" -x "a-title-([0-9.-]*)" -xr "a-title-{0:000}" -o "newer" | |
virtual public void Run() | |
{ | |
// initialize some stuff | |
DirectoryInfo dir; | |
Setting settings = new Setting(); | |
List<Node> list = new List<Node>(); | |
#region Set Variables from Input | |
string arg = null; | |
int index = -1; | |
// input directories | |
List<string> InputDirectories = null; | |
InputDirectories = GetValuesForArgument("-i"); | |
// input expression | |
settings.Expression = GetValue(true,"-x"); | |
Console.WriteLine("expression : {0}",expression); | |
// replacement expression | |
settings.ExpressionReplace = GetValue(true, "-xr"); | |
settings.OutputDir = GetValue(true, "-o"); | |
// pre sorting? | |
settings.SortPre = HasValue("-spr"); GetValue(false,"-spr"); | |
Console.WriteLine("sort-pre : {0}",sortPre); | |
// post sorting? | |
settings.SortPost = HasValue("-spo"); GetValue(false,"-spo"); | |
Console.WriteLine("sort-post : {0}",sortPost); | |
// order 'asc' | 'desc' | |
settings.Reverse = HasValue("-r"); GetValue(false,"-r"); | |
Console.WriteLine("reverse : {0}",reverse); | |
#endregion | |
// Throw Exception (write to StdError) | |
if (InputDirectories==null) return; | |
if (InputDirectories.Count==0) return; | |
foreach (var d in InputDirectories) | |
{ | |
dir = new DirectoryInfo(d); | |
if (!dir.Exists) { | |
Console.Error.WriteLine("Directory \"{0}\" does not exist.",dir.FullName); | |
continue; | |
} | |
Console.WriteLine("directory-name : {0}",dir.Name); | |
Console.WriteLine("directory-path : {0}",dir.Parent.FullName); | |
Console.WriteLine("------------------------------------------------------------"); | |
if (InputDirectories.Count > 0) | |
{ | |
foreach (FileInfo f in dir.GetFiles()) | |
{ | |
Node node = new Node(){ OldFile=f, Name=Path.GetFileNameWithoutExtension(f.Name) }; | |
if (string.IsNullOrEmpty(settings.Expression) && !settings.OnlyUseMatches) { | |
list.Add(node); | |
} | |
else if (settings.RegularExpression.IsMatch(f.Name)) | |
{ | |
node.HasMatch = true; | |
if (!string.IsNullOrEmpty(settings.ExpressionReplace)) | |
node.Name=settings.RegularExpression.Replace(node.Name,settings.ExpressionReplace); | |
else if (!settings.OnlyUseMatches) { | |
node.Name = f.Name; | |
} | |
} | |
list.Add(node); | |
} | |
// the rest of the code following the '} ... }' could go in here to be able to handle more than | |
// one input directory. | |
if (settings..SortPre) list.Sort(delegate(Node a, Node b){ return a.OldFile.Name.CompareTo(b.OldFile.Name); }); | |
if (settings.SortPost) list.Sort(delegate(Node a, Node b){ return a.OldFile.Name.CompareTo(b.NameExt); }); | |
if (settings.Reverse) list.Reverse(); | |
if (list.Count > 0) { | |
DirectoryInfo newout = new DirectoryInfo(outputDir); | |
string temp = list[0].OldFile.Directory.Parent.FullName; | |
if (settings.OutputDir[1]==':') newout = new DirectoryInfo(settings.OutputDir); | |
else newout = new DirectoryInfo(Path.Combine(temp,settings.OutputDir)); | |
if (!newout.Exists) newout.Create(); | |
Console.WriteLine(newout.FullName); | |
int i=0; | |
foreach (Node s in list) | |
{ | |
s.OldFile.CopyTo(Path.Combine(newout.FullName,string.Format(s.NameExt,i)),true); | |
Console.WriteLine("Old: {0,-9}, New: {1,-9}",s.OldFile.Name,string.Format(s.NameExt,i++)); | |
} | |
list.Clear(); | |
} | |
} | |
} | |
Console.ReadKey(); | |
} | |
} | |
class Program | |
{ | |
// public FileInfo AppExecutable { get { return new FileInfo(Assembly.GetExecutingAssembly().Location); } } | |
// public FileInfo AppCaller { get { return new FileInfo(Assembly.GetCallingAssembly().Location); } } | |
// public FileInfo AppEntry { get { return new FileInfo(Assembly.GetEntryAssembly().Location); } } | |
// Environment.CurrentDirectory | |
// things that are needed: | |
// (1) only rename matched regular expressions. | |
// only regex flag | |
// (2) cbz/cbr compression configuration | |
// look in windows registry | |
// look for uninstall | |
// look in environment | |
// (2A) CBZ/R Creation From Directory as input COMMAND STRING | |
// (2B) Execute the command | |
public static void Main(string[] args) | |
{ | |
Rename r = new Rename(){ Args=new List<string>(args) }; | |
r.Run(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"> | |
<PropertyGroup> | |
<ProjectGuid>{86612E18-F5ED-4265-AB67-47E1142C2A6C}</ProjectGuid> | |
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |
<OutputType>Exe</OutputType> | |
<RootNamespace>xrename</RootNamespace> | |
<AssemblyName>xrename</AssemblyName> | |
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | |
<TargetFrameworkProfile>Client</TargetFrameworkProfile> | |
<AppDesignerFolder>Properties</AppDesignerFolder> | |
<NoWin32Manifest>False</NoWin32Manifest> | |
<AllowUnsafeBlocks>False</AllowUnsafeBlocks> | |
<NoStdLib>False</NoStdLib> | |
<TreatWarningsAsErrors>False</TreatWarningsAsErrors> | |
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath> | |
<WarningLevel>4</WarningLevel> | |
</PropertyGroup> | |
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> | |
<PlatformTarget>AnyCPU</PlatformTarget> | |
<BaseAddress>4194304</BaseAddress> | |
<RegisterForComInterop>False</RegisterForComInterop> | |
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> | |
<FileAlignment>4096</FileAlignment> | |
</PropertyGroup> | |
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> | |
<OutputPath>bin\Debug\</OutputPath> | |
<DebugSymbols>True</DebugSymbols> | |
<DebugType>Full</DebugType> | |
<Optimize>False</Optimize> | |
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> | |
<DefineConstants>DEBUG;TRACE</DefineConstants> | |
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath> | |
</PropertyGroup> | |
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> | |
<OutputPath>bin\Release\</OutputPath> | |
<DebugSymbols>False</DebugSymbols> | |
<DebugType>None</DebugType> | |
<Optimize>True</Optimize> | |
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> | |
<DefineConstants>TRACE</DefineConstants> | |
</PropertyGroup> | |
<ItemGroup> | |
<Reference Include="System" /> | |
<Reference Include="System.Core"> | |
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |
</Reference> | |
<Reference Include="System.Data" /> | |
<Reference Include="System.Data.DataSetExtensions"> | |
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |
</Reference> | |
<Reference Include="System.Drawing" /> | |
<Reference Include="System.Xml" /> | |
<Reference Include="System.Xml.Linq"> | |
<RequiredTargetFramework>3.5</RequiredTargetFramework> | |
</Reference> | |
</ItemGroup> | |
<ItemGroup> | |
<Compile Include="commander.cs" /> | |
<Compile Include="xrename.cs" /> | |
</ItemGroup> | |
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |
</Project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment