3
\$\begingroup\$

I have over 2500 files in a directory tree- some of them are numbered, some of them aren't. eg.

1. That night it rained.epub
The sparrow returns at dawn.epub
001. Tomorrow is a new day.epub
000.1. We are the children.epub

I created my C# code to iterate through all the directories and rename the numbered files to look neater, but at the same time should leave the unnumbered file unaltered like so:

001. That night it rained.epub
The sparrow returns at dawn.epub
001. Tomorrow is a new day.epub
000.1. We are the children.epub

My coding looks like this:

class Program
{
static string path = @"C:\Users\Anja\Desktop\reekse";
static string name;
static string rpath;
static int numberperiod;
static string number;
static string newname;
static string movepath;
static void Main(string[] args)
 {
 foreach (var file in Directory.GetFiles(path, "*.epub", SearchOption.AllDirectories)) //searches for all the epub files even if there are 20 subdirectories between the file and the main directory
 {
 name = System.IO.Path.GetFileName(file);//gets the filename sans the path
 rpath = System.IO.Path.GetDirectoryName(file);//gets the path sans the file
 numberperiod = name.IndexOf(".");//find the location of the 1st . (remember-zerobasing is used)
 if (numberperiod == 1)//first period - meaning no 0's is used in numbering
 {
 number = name.Substring(0, numberperiod + 1);//pick up the number as well as the . that follows the numbering
 name = name.TrimStart(number.ToCharArray());//convert the number to char and trim it
 name = name.TrimStart('.', ' ', ' ');// remove any potential blankspaces and . that may be at the start of the filename
 newname = "00" + number + " " + name; // create a name that has the 0's, the number, adequite spacing, and the name
 }
 if (numberperiod == 2)//same as above but the numbering contains two digits
 {
 number = name.Substring(0, numberperiod + 1);
 name = name.TrimStart(number.ToCharArray());
 name = name.TrimStart('.', ' ', ' ');
 newname = "0" + number + " " + name;
 }
 if (numberperiod == 3)//files containing 3 digits
 {
 number = name.Substring(0, numberperiod + 1);
 if (number == "000.")// in case the file has odd numbering as in the example
 {
 number = name.Substring(0, numberperiod + 3);
 name = name.TrimStart(number.ToCharArray());
 name = name.TrimStart('.', ' ', ' ');
 newname = number + " " + name;
 }
 else
 {
 name = name.TrimStart(number.ToCharArray());
 name = name.TrimStart('.', ' ', ' ');
 newname = number + " " + name;
 }
 }
 Console.WriteLine(newname.ToString());
 movepath = Path.Combine(rpath, newname);
 File.Move(file, movepath);
 }
 }
}

The coding works perfectly fine, but it just seems so tedious; I'm positive that there must be a simpler way of doing this like regex or Linq.

Can someone please help? I'm not any good when it comes to either Linq or regex. Can someone please help me rewrite this code to make it simpler?

asked May 16, 2020 at 15:22
\$\endgroup\$
1
  • \$\begingroup\$ I cannot address the code you've written directly but I think the gut feeling that brought you here is because files + renaming + regex are very much shell-scripting territory. A compiled language is simply not "the tool for the job". \$\endgroup\$ Commented May 17, 2020 at 21:47

1 Answer 1

2
\$\begingroup\$

using Regex.Replace with a help of PadLeft would do this in a single line. so your work can be simplified to :

foreach (var file in Directory.GetFiles(path, "*.epub", SearchOption.AllDirectories)) 
{
 var fileName = System.IO.Path.GetFileName(file);
 var filePath = System.IO.Path.GetDirectoryName(file);//gets the path sans the file 
 var strName = Regex.Replace(fileName, @"^((\d+\.){1}(\d\.)?\s+)", m => m.Groups[0].Value.Trim().PadLeft(4, '0').PadRight(8));
 File.Move(file, Path.Combine(filePath, strName));
}

The regex should covers any string with the same pattern in your provided sample.

UPDATE :

To make it more readable for you, you can use the following :

var regex = new Regex(@"^([0-9]+\.?\.\s)");
var fileName = new StringBuilder();
foreach (var file in Directory.GetFiles(path, "*.epub", SearchOption.AllDirectories))
{
 fileName.Append(Path.GetFileName(file));
 var filePath = System.IO.Path.GetDirectoryName(file);
 var match = regex.Match(fileName.ToString());
 if (match.Success)
 {
 fileName.Clear();
 fileName
 .Append(match.Value.Trim().PadLeft(4, '0'))
 .Append(" ")
 .Append(file.Substring(match.Value.Length).Trim());
 }
 fileName.Replace(fileName.ToString(), Path.Combine(Path.GetDirectoryName(file), fileName.ToString()));
 File.Move(filePath, fileName.ToString());
 fileName.Clear(); 
}

Using StringBuilder is a must in your case, since you're dealing with a list of files name, and since string is immutable, using StringBuilder will avoid creating a new string for each filename which would save your memory and also optimize the performance.

answered May 19, 2020 at 5:56
\$\endgroup\$
7
  • \$\begingroup\$ Thank you so much for helping me renumber my files. It works like a charm! But can you please help me solve the Whitespace-issue? I want 4 whitespace-characters to be added between the number and the files actual name. ("001.----Each dash represents a whitespace-character) I want it to be look neat. \$\endgroup\$ Commented May 23, 2020 at 19:42
  • \$\begingroup\$ @diedomkop I have updated my answer with another simplified code, I avoided using expressions to make it readable and easy to edit. \$\endgroup\$ Commented May 24, 2020 at 4:06
  • \$\begingroup\$ There's no benefit in using StringBuilder in this code. Since you call ToString, the new string gets created anyway. \$\endgroup\$ Commented May 24, 2020 at 7:56
  • \$\begingroup\$ @RolandIllig yes, it would create one string per iteration instead of multiple strings just for the name! \$\endgroup\$ Commented May 24, 2020 at 13:11
  • \$\begingroup\$ If you rewrite the replace line in the first version to var strName = Regex.Replace(fileName, @"^((\d+\.){1}(\d\.)?\s+)", m => m.Groups[0].Value.Trim().PadLeft(4, '0').PadRight(8)); it will work with regex only. \$\endgroup\$ Commented May 24, 2020 at 14:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.