# Mass file renaming via regex

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.

• 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". – drekbour May 17 '20 at 21:47

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

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("    ")
.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.

• 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. – diedomkop May 23 '20 at 19:42
• @diedomkop I have updated my answer with another simplified code, I avoided using expressions to make it readable and easy to edit. – iSR5 May 24 '20 at 4:06
• There's no benefit in using StringBuilder in this code. Since you call ToString, the new string gets created anyway. – Roland Illig May 24 '20 at 7:56
• @RolandIllig yes, it would create one string per iteration instead of multiple strings just for the name! – iSR5 May 24 '20 at 13:11
• 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. – user73941 May 24 '20 at 14:36