From e843a63f211073f3db8b00f0e280cf065298b632 Mon Sep 17 00:00:00 2001 From: Nic Jansma Date: Tue, 1 Feb 2022 20:03:46 -0500 Subject: [PATCH] v1.7.0: /fr option to use RegEx for file matches --- LICENSE | 2 +- README.md | 12 +++-- bin/RR.exe | Bin 9728 -> 10240 bytes source/Program.cs | 78 +++++++++++++++++++++++++----- source/Properties/AssemblyInfo.cs | 6 +-- 5 files changed, 80 insertions(+), 18 deletions(-) diff --git a/LICENSE b/LICENSE index 70a057e..42d83eb 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012 Nic Jansma, http://nicj.net +Copyright (c) 2022 Nic Jansma, http://nicj.net Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index f2483ac..7dfdbba 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Copyright (c) 2021 Nic Jansma +Copyright (c) 2022 Nic Jansma [http://nicj.net](http://nicj.net) # Introduction @@ -18,6 +18,7 @@ file renamer or with a complex regular expression for matching and replacement. /files: include only files /dirs: include only directories (default is to include files only, to include both use /files /dirs) + /fr: use regex for file name matching instead of Windows glob matching ``` You can use [.NET regular expressions](http://msdn.microsoft.com/en-us/library/hs600312.aspx) for the search and @@ -42,14 +43,18 @@ Rename files in the pattern of "`124_xyz.txt`" to "`xyz_123.txt`": RR.exe *.txt "([0-9]+)_([a-z]+)" "$2_$1" -Rename directories (only) +Rename directories (only): RR * "-" "_" /dirs -Rename files and directories +Rename files and directories: RR * "-" "_" /files /dirs +Apply a regular expression to the glob pattern files and directories: + + RR a_\d.txt "a_" "a_0" /fr + # Version History * v1.0 - 2012-01-30: Initial release @@ -60,6 +65,7 @@ Rename files and directories * v1.5 - 2020-07-02: Added support for directories, added length-check (via Alec S. @Synetech) * v1.6 - 2021-05-22: Added `/c` support for case insensitivity (via Alec S. @Synetech) * v1.6.1 - 2021-06-12: Fix `/r` for sub-dirs +* v1.7- 2022-02-01: Added `/fr` option to apply a regex to file matches (instead of Windows glob pattern) # Credits diff --git a/bin/RR.exe b/bin/RR.exe index 4d0224aa2585d4eba21b538668042623011767ab..b77f5c0529c118f04a82ca8bd86e9ee319d5ddc5 100644 GIT binary patch delta 3431 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 Z+f!aY&PJQcU)T6h + /// Matches a list of files/directories to a regular expression + /// + /// List of files or directories + /// Regular expression to match + /// List of files or directories that matched + private static string[] ApplyFileRegex(string[] list, string fileMatch) + { + List matching = new List(); + + Regex regex = new Regex(fileMatch); + + for (int i = 0; i < list.Length; i++) + { + if (regex.IsMatch(list[i])) + { + matching.Add(list[i]); + } + } + + return matching.ToArray(); + } + /// /// Gets the program arguments /// @@ -207,6 +242,7 @@ public static int Main(string[] args) /// Whether or not to force overwrites /// Whether or not to preserve file extensions /// Whether to include directories, files or both + /// Whether to use a RegEx for the file match. If false, Windows glob patterns are used. /// True if argument parsing was successful private static bool GetArguments( string[] args, @@ -218,7 +254,8 @@ private static bool GetArguments( out bool caseInsensitive, out bool force, out bool preserveExt, - out int includeMask) + out int includeMask, + out bool fileMatchRegEx) { // defaults fileMatch = String.Empty; @@ -227,12 +264,13 @@ private static bool GetArguments( bool foundNameReplace = false; - pretend = false; - recursive = false; - force = false; + pretend = false; + recursive = false; + force = false; caseInsensitive = false; - preserveExt = false; - includeMask = 0; + preserveExt = false; + includeMask = 0; + fileMatchRegEx = false; // check for all arguments if (args == null || args.Length < 3) @@ -279,6 +317,10 @@ private static bool GetArguments( { includeMask |= IncludeDirs; } + else if (args[i].Equals("/fr", StringComparison.OrdinalIgnoreCase)) + { + fileMatchRegEx = true; + } else { // if not an option, the rest of the arguments are filename, search, replace @@ -298,6 +340,19 @@ private static bool GetArguments( } } + if (fileMatchRegEx) + { + try + { + Regex regex = new Regex(fileMatch); + } + catch (ArgumentException e) + { + Console.WriteLine("ERROR: File match is not a regular expression!\n"); + return false; + } + } + return !String.IsNullOrEmpty(fileMatch) && !String.IsNullOrEmpty(nameSearch) && foundNameReplace; @@ -325,6 +380,7 @@ private static void Usage() Console.WriteLine(@" /files: include files (default)"); Console.WriteLine(@" /dirs: include directories"); Console.WriteLine(@" (default is to include files only, to include both use /files /dirs)"); + Console.WriteLine(@" /fr: use regex for file name matching instead of Windows glob matching"); return; } } diff --git a/source/Properties/AssemblyInfo.cs b/source/Properties/AssemblyInfo.cs index 3d46b0e..5280b3d 100644 --- a/source/Properties/AssemblyInfo.cs +++ b/source/Properties/AssemblyInfo.cs @@ -16,7 +16,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RenameRegex")] -[assembly: AssemblyCopyright("Copyright © Nic Jansma 2021")] +[assembly: AssemblyCopyright("Copyright © Nic Jansma 2022")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -35,7 +35,7 @@ // Build Number // Revision // -[assembly: AssemblyVersion("1.6.1.0")] -[assembly: AssemblyFileVersion("1.6.1.0")] +[assembly: AssemblyVersion("1.7.0.0")] +[assembly: AssemblyFileVersion("1.7.0.0")] [assembly: CLSCompliant(true)]