Auto Incrementing file names? - c#

I have a list of files like so
abc.txt
pas.txt
tempr.txt
What I would like to do is to append english alphabets to theese file names ..
the result should look like this
abc_a.txt
pas_b.txt
tempr_c.txt
This process should continue till the last character (i.e 'z'). if there are more files then the file names would become
abc_a.txt
pas_b.txt
tempr_c.txt
.................
filename_z.txt
anotherfilename_a001.txt
Notice that the counter was again reset to the first character except an integer was attached to it.
This is the code that i have right now. Please note that it is NOT working ..
string alphabets= "abcdefghijklmnopqrstuvwxyz";
List<string> filenames = new List<string>();
filenames.Add("test1.txt");
filenames.Add("newfile.cs");
filenames.Add("test2.txt");
filenames.Add("newfile2.cs");
string currentFileNmae = string.Empty;
foreach(string s in filenames) {
char usedAlphabet = new char();
for(int i = 0;i<=alphabets.Length-1;i+=11) {
usedAlphabet.Dump();
alphabets[i].Dump();
if(usedAlphabet != alphabets[i] )
{
if(currentFileNmae!= s)
{
string.Format("{0}--{1}",s,alphabets[i]).Dump();
usedAlphabet = alphabets[i];
currentFileNmae = s;
}
}
break;
}
}
I am part of a team that's building a file renamer tool for our internal purposes and hence i need this code. This is part of the our enumertation functionality that we have planned.
Please suggest.
thanks

Try starting here:
using System.Diagnostics;
using System.IO;
string filename = #"C:\Foo\Bar.txt";
for (int count = 0; count < 100; count++)
{
char letter = (char)((int)'a' + count % 26);
string numeric = (count / 26) == 0 ? "" : (count / 26).ToString("000");
Debug.Print(Path.GetFileNameWithoutExtension(filename) + "_" + letter + numeric + Path.GetExtension(filename));
}
Substitute your own loop to go through the filenames and use Path to manipulate the pieces/parts of the names.
The renaming, IIRC, can be handled by File.Move. Surround it with a try/catch to implement the name collision logic.

Had no coffee yet, but this should do.
List<string> files = new List<string>();
int charIndex = 0;
int numericIndex = -1;
foreach (var file in files.Select(path => new FileInfo(path)))
{
// Create new Filename - This may needs some tuning
// to really remove only the extension ad the end
// It doesnt take care of things like
// file.bmp.bmp.bmp ...
string newFileName = String.Format("{0}_{1}{2}.{3}",
file.FullName.Replace(file.Extension,String.Empty),
(char)(charIndex++ + 97),
(numericIndex > -1 ? String.Format("{0:D4}", numericIndex) : String.Empty),
file.Extension);
// Rename the File
file.MoveTo(newFileName);
// Increment Counters.
if (charIndex > 25)
{
charIndex = 0;
numericIndex++;
}
}

You can try something like this
const string directory = #"C:\\wherever";
string[] fiNames = new string[]{ "abc", "pas", "etc",};
char[] alphabet = "abcdefghijklmnopqrstuvwxyz".ToCharArray();
int x = 0;
string ending = "";
for(int i = fiNames.Count()-1; i>=0; i--)
{
if(x%26==0)
{
x=0
if( ending=="")
ending="1";
else
ending=(System.Convert.ToInt32(ending)+1).ToString();
}
System.IO.File.Move(directory+fiNames[i], fiNames[i]+alphabet[x].ToString()+ending);
x++;
}

Related

C#: Need to split a string into a string[] and keeping the delimiter (also a string) at the beginning of the string

I think I am too dumb to solve this problem...
I have some formulas which need to be "translated" from one syntax to another.
Let's say I have a formula that goes like that (it's a simple one, others have many "Ceilings" in it):
string formulaString = "If([Param1] = 0, 1, Ceiling([Param2] / 0.55) * [Param3])";
I need to replace "Ceiling()" with "Ceiling(; 1)" (basically, insert "; 1" before the ")").
My attempt is to split the fomulaString at "Ceiling(" so I am able to iterate through the string array and insert my string at the correct index (counting every "(" and ")" to get the right index)
What I have so far:
//splits correct, but loses "CEILING("
string[] parts = formulaString.Split(new[] { "CEILING(" }, StringSplitOptions.None);
//splits almost correct, "CEILING(" is in another group
string[] parts = Regex.Split(formulaString, #"(CEILING\()");
//splits almost every letter
string[] parts = Regex.Split(formulaString, #"(?=[(CEILING\()])");
When everything is done, I concat the string so I have my complete formula again.
What do I have to set as Regex pattern to achieve this sample? (Or any other method that will help me)
part1 = "If([Param1] = 0, 1, ";
part2 = "Ceiling([Param2] / 0.55) * [Param3])";
//part3 = next "CEILING(" in a longer formula and so on...
As I mention in a comment, you almost got it: (?=Ceiling). This is incomplete for your use case unfortunately.
I need to replace "Ceiling()" with "Ceiling(; 1)" (basically, insert "; 1" before the ")").
Depending on your regex engine (for example JS) this works:
string[] parts = Regex.Split(formulaString, #"(?<=Ceiling\([^)]*(?=\)))");
string modifiedFormula = String.join("; 1", parts);
The regex
(?<=Ceiling\([^)]*(?=\)))
(?<= ) Positive lookbehind
Ceiling\( Search for literal "Ceiling("
[^)] Match any char which is not ")" ..
* .. 0 or more times
(?=\)) Positive lookahead for ")", effectively making us stop before the ")"
This regex is a zero-assertion, therefore nothing is lost and it will cut your strings before the last ")" in every "Ceiling()".
This solution would break whenever you have nested "Ceiling()". Then your only solution would be writing your own parser for the same reasons why you can't parse markup with regex.
Regex.Replace(formulaString, #"(?<=Ceiling\()(.*?)(?=\))","$1; 1");
Note: This will not work for nested "Ceilings", but it does for Ceiling(), It will also not work fir Ceiling(AnotherFunc(x)). For that you need something like:
Regex.Replace(formulaString, #"(?<=Ceiling\()((.*\((?>[^()]+|(?1))*\))*|[^\)]*)(\))","$1; 1$3");
but I could not get that to work with .NET, only in JavaScript.
This is my solution:
private string ConvertCeiling(string formula)
{
int ceilingsCount = formula.CountOccurences("Ceiling(");
int startIndex = 0;
int bracketCounter;
for (int i = 0; i < ceilingsCount; i++)
{
startIndex = formula.IndexOf("Ceiling(", startIndex);
bracketCounter = 0;
for (int j = 0; j < formula.Length; j++)
{
if (j < startIndex) continue;
var c = formula[j];
if (c == '(')
{
bracketCounter++;
}
if (c == ')')
{
bracketCounter--;
if (bracketCounter == 0)
{
// found end
formula = formula.Insert(j, "; 1");
startIndex++;
break;
}
}
}
}
return formula;
}
And CountOccurence:
public static int CountOccurences(this string value, string parameter)
{
int counter = 0;
int startIndex = 0;
int indexOfCeiling;
do
{
indexOfCeiling = value.IndexOf(parameter, startIndex);
if (indexOfCeiling < 0)
{
break;
}
else
{
startIndex = indexOfCeiling + 1;
counter++;
}
} while (true);
return counter;
}

C# - split a RichTextBox line in two based on the caret position

I've got a RichTextBox, here referred to as box.
string currentline = box.Lines[box.GetLineFromCharIndex(box.SelectionStart)];
That line there fetches the line the caret is in. It works excellently.
However, I have a need to get two strings from this. The first is everything on that line UP to the caret, and the second is everything on that line AFTER it.
For instance, if the line is How is you|r day going?, with | representing the caret, I would get How is you and r day going?, separately.
I wrote this monstrosity, which works:
string allbefore = box.Text.Substring(0, box.SelectionStart);
string allafter = box.Text.Substring(box.SelectionStart, box.Text.Length - box.SelectionStart);
string linebefore = "";
for (int i = 0; i < allbefore.Length; i++)
{
linebefore += allbefore[i];
if (allbefore[i] == '\n')
linebefore = "";
}
string lineafter = "";
for (int i = 0; i < allafter.Length; i++)
{
if (allafter[i] == '\n')
break;
else
lineafter += allafter[i];
}
It gives me the result I want, but involves looping through EVERY character in the entire box, which just hurts. Is there an easy way to do this I'm just missing? Thanks.
This might do the trick for you
string currentline = box.Lines[box.GetLineFromCharIndex(box.SelectionStart)];
var listOfStrings = new List<string>();
string[] splitedBox = currentline.Split('|');
foreach(string sp in splitedBox)
{
string[] lineleft = sp.Split('\n');
listOfStrings.Add(lineleft[lineleft.Count() - 1]);
}
In the first approach we are splitting the line by char | than finding if we have any \n if it exsist we are taking the values accordingly
Another approach could be
string box = "How is \n you|r day \n going?";
bool alllinesremoved = true;
while(alllinesremoved)
{
if(box.Contains('\n'))
{
if(box.IndexOf('\n') > box.IndexOf('|'))
{
box = box.Remove(box.IndexOf('\n'), (box.Length - box.IndexOf('\n')));
}
else
{
box = box.Remove(0, box.IndexOf('\n') + 1);
}
}
else
{
alllinesremoved = false;
}
}
string[] splitedBox = box.Split('|');
in the second approach we are removing the characters before and after the \n and then splitting the string. I think the second one seems more good to me.
Have you tried using line.split? Not sure if this is what you want.
Store the position of \n using indexOf and, if >= 0, that is, the string contains it, use substring and assign the value otherwise.
string allbefore = box.Text.Substring(0, box.SelectionStart);
string allafter = box.Text.Substring(box.SelectionStart, box.Text.Length - box.SelectionStart);
int newLinePos = allBefore.lastIndexOf("\n");
string lineBefore = ((newLinePos >= 0) ? (allBefore.substring(newLinePos + 1)) : (allBefore));
newLinePos = allafter.indexOf("\n");
string lineAfter = ((newLinePost >= 0) ? (allAfter.substring(0, newLinePos)) : (allAfter));

How to delete a specific record (fixed length) includes data from a .txt file?

I am new in C# and I am making project but I can't make this delete part ..
If I save my data in .txt file in one line, but contain many fixed length record with no delimiter, if each record has fixed length and each field has fixed length and saved in file like this
1ahly2zamalek
how do I delete, for example the record 2zamalek from line with entering to the program id=2?
public team()
{
Team_ID_Len = 5;
Team_Name_Len = 10;
Team_Rec_Len = 15; ;
Team_ID = new char[Team_ID_Len];
Team_Name = new char[Team_Name_Len];
}
Sounds like you're looking for Substring. Give it a start (length of record * how many), and the length (length of record).
Actually, you might want to create the string as string s = part1+part2 where part1 is the substring from 0 till the start of the record, and part2 is the start of the NEXT record, until the end.
Then just save it.
Your number is your delimiter, split with a char array
using System;
using System;
public static class Program
{
public static void Main()
{
string words = "1sdklfjlsdf2lksjdf3sfd4sfd5fsd6fsd7fsd8fsd9sfd10aslkdfj11jklh12hjk";
int deleteRecordId = 11;
string [] split = words.Split(new Char [] {'1', '2','3','4','5','6','7','8','9','0'});
string newString = "";
int j = 0;
for( int i = 0; i < split.Length; i++)
{
if ( j == deleteRecordId)
{
//ignore this record
Console.WriteLine("ignore i = " + i);
j++;
}
else
{
Console.WriteLine("i = " + i);
if(!( split[i] == ""))
{
newString += j + split[i];
j++;
}
}
}
Console.WriteLine(newString);
}
}
then WriteAll to the file

C# How can I compare two word strings and indicate which parts are different

For example if I have...
string a = "personil";
string b = "personal";
I would like to get...
string c = "person[i]l";
However it is not necessarily a single character. I could be like this too...
string a = "disfuncshunal";
string b = "dysfunctional";
For this case I would want to get...
string c = "d[isfuncshu]nal";
Another example would be... (Notice that the length of both words are different.)
string a = "parralele";
string b = "parallel";
string c = "par[ralele]";
Another example would be...
string a = "ato";
string b = "auto";
string c = "a[]to";
How would I go about doing this?
Edit: The length of the two strings can be different.
Edit: Added additional examples. Credit goes to user Nenad for asking.
I must be very bored today, but I actually made UnitTest that pass all 4 cases (if you did not add some more in the meantime).
Edit: Added 2 edge cases and fix for them.
Edit2: letters that repeat multiple times (and error on those letters)
[Test]
[TestCase("parralele", "parallel", "par[ralele]")]
[TestCase("personil", "personal", "person[i]l")]
[TestCase("disfuncshunal", "dysfunctional", "d[isfuncshu]nal")]
[TestCase("ato", "auto", "a[]to")]
[TestCase("inactioned", "inaction", "inaction[ed]")]
[TestCase("refraction", "fraction", "[re]fraction")]
[TestCase("adiction", "ad[]diction", "ad[]iction")]
public void CompareStringsTest(string attempted, string correct, string expectedResult)
{
int first = -1, last = -1;
string result = null;
int shorterLength = (attempted.Length < correct.Length ? attempted.Length : correct.Length);
// First - [
for (int i = 0; i < shorterLength; i++)
{
if (correct[i] != attempted[i])
{
first = i;
break;
}
}
// Last - ]
var a = correct.Reverse().ToArray();
var b = attempted.Reverse().ToArray();
for (int i = 0; i < shorterLength; i++)
{
if (a[i] != b[i])
{
last = i;
break;
}
}
if (first == -1 && last == -1)
result = attempted;
else
{
var sb = new StringBuilder();
if (first == -1)
first = shorterLength;
if (last == -1)
last = shorterLength;
// If same letter repeats multiple times (ex: addition)
// and error is on that letter, we have to trim trail.
if (first + last > shorterLength)
last = shorterLength - first;
if (first > 0)
sb.Append(attempted.Substring(0, first));
sb.Append("[");
if (last > -1 && last + first < attempted.Length)
sb.Append(attempted.Substring(first, attempted.Length - last - first));
sb.Append("]");
if (last > 0)
sb.Append(attempted.Substring(attempted.Length - last, last));
result = sb.ToString();
}
Assert.AreEqual(expectedResult, result);
}
Have you tried my DiffLib?
With that library, and the following code (running in LINQPad):
void Main()
{
string a = "disfuncshunal";
string b = "dysfunctional";
var diff = new Diff<char>(a, b);
var result = new StringBuilder();
int index1 = 0;
int index2 = 0;
foreach (var part in diff)
{
if (part.Equal)
result.Append(a.Substring(index1, part.Length1));
else
result.Append("[" + a.Substring(index1, part.Length1) + "]");
index1 += part.Length1;
index2 += part.Length2;
}
result.ToString().Dump();
}
You get this output:
d[i]sfunc[shu]nal
To be honest I don't understand what this gives you, as you seem to completely ignore the changed parts in the b string, only dumping the relevant portions of the a string.
Here is a complete and working console application that will work for both examples you gave:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string a = "disfuncshunal";
string b = "dysfunctional";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < a.Length; i++)
{
if (a[i] != b[i])
{
sb.Append("[");
sb.Append(a[i]);
sb.Append("]");
continue;
}
sb.Append(a[i]);
}
var str = sb.ToString();
var startIndex = str.IndexOf("[");
var endIndex = str.LastIndexOf("]");
var start = str.Substring(0, startIndex + 1);
var mid = str.Substring(startIndex + 1, endIndex - 1);
var end = str.Substring(endIndex);
Console.WriteLine(start + mid.Replace("[", "").Replace("]", "") + end);
}
}
}
it will not work if you want to display more than one entire section of the mismatched word.
You did not specify what to do if the strings were of different lengths, but here is a solution to the problem when the strings are of equal length:
private string Compare(string string1, string string2) {
//This only works if the two strings are the same length..
string output = "";
bool mismatch = false;
for (int i = 0; i < string1.Length; i++) {
char c1 = string1[i];
char c2 = string2[i];
if (c1 == c2) {
if (mismatch) {
output += "]" + c1;
mismatch = false;
} else {
output += c1;
}
} else {
if (mismatch) {
output += c1;
} else {
output += "[" + c1;
mismatch = true;
}
}
}
return output;
}
Not really good approach but as an exercise in using LINQ: task seem to be find matching prefix and suffix for 2 strings, return "prefix + [+ middle of first string + suffix.
So you can match prefix (Zip + TakeWhile(a==b)), than repeat the same for suffix by reversing both strings and reversing result.
var first = "disfuncshunal";
var second = "dysfunctional";
// Prefix
var zipped = first.ToCharArray().Zip(second.ToCharArray(), (f,s)=> new {f,s});
var prefix = string.Join("",
zipped.TakeWhile(c => c.f==c.s).Select(c => c.f));
// Suffix
var zippedReverse = first.ToCharArray().Reverse()
.Zip(second.ToCharArray().Reverse(), (f,s)=> new {f,s});
var suffix = string.Join("",
zippedReverse.TakeWhile(c => c.f==c.s).Reverse().Select(c => c.f));
// Cut and combine.
var middle = first.Substring(prefix.Length,
first.Length - prefix.Length - suffix.Length);
var result = prefix + "[" + middle + "]" + suffix;
Much easier and faster approach is to use 2 for loops (from start to end, and from end to start).

Divide long string into 60 character long lines but don't break words

There has to be a better way to do this.
I just want to split long string into 60 character lines but do not break words. So it doesn't have to add up to 60 characters just has to be less than 60.
The code below is what I have and it works but I'm thinking there's a better way. Anybody?
Modified to use StringBuilder and fixed the problem of removing a repeating word.
Also don't want to use regex because I think that would be less efficient than what I have now.
public static List<String> FormatMe(String Message)
{
Int32 MAX_WIDTH = 60;
List<String> Line = new List<String>();
String[] Words;
Message = Message.Trim();
Words = Message.Split(" ".ToCharArray());
StringBuilder s = new StringBuilder();
foreach (String Word in Words)
{
s.Append(Word + " ");
if (s.Length > MAX_WIDTH)
{
s.Replace(Word, "", 0, s.Length - Word.Length);
Line.Add(s.ToString().Trim());
s = new StringBuilder(Word + " ");
}
}
if (s.Length > 0)
Line.Add(s.ToString().Trim());
return Line;
}
Thanks
Another (now TESTED) sample, very similiar to Keith approach:
static void Main(string[] args)
{
const Int32 MAX_WIDTH = 60;
int offset = 0;
string text = Regex.Replace(File.ReadAllText("oneline.txt"), #"\s{2,}", " ");
List<string> lines = new List<string>();
while (offset < text.Length)
{
int index = text.LastIndexOf(" ",
Math.Min(text.Length, offset + MAX_WIDTH));
string line = text.Substring(offset,
(index - offset <= 0 ? text.Length : index) - offset );
offset += line.Length + 1;
lines.Add(line);
}
}
I ran that on this file with all line breaks manually replaced by " ".
Try this:
const Int32 MAX_WIDTH = 60;
string text = "...";
List<string> lines = new List<string>();
StringBuilder line = new StringBuilder();
foreach(Match word in Regex.Matches(text, #"\S+", RegexOptions.ECMAScript))
{
if (word.Value.Length + line.Length + 1 > MAX_WIDTH)
{
lines.Add(line.ToString());
line.Length = 0;
}
line.Append(String.Format("{0} ", word.Value));
}
if (line.Length > 0)
line.Append(word.Value);
Please, also check this out: How do I use a regular expression to add linefeeds?
Inside a Regular expression, the Match Evaluator function (an anonymous method) does the grunt work and stores the newly sized lines into a StringBuilder. We don't use the return value of Regex.Replace method because we're just using its Match Evaluator function as a feature to accomplish line breaking from inside the regular expression call - just for the heck of it, because I think it's cool.
using System;
using System.Text;
using System.Text.RegularExpressions;
strInput is what you want to convert the lines of.
int MAX_LEN = 60;
StringBuilder sb = new StringBuilder();
int bmark = 0; //bookmark position
Regex.Replace(strInput, #".*?\b\w+\b.*?",
delegate(Match m) {
if (m.Index - bmark + m.Length + m.NextMatch().Length > MAX_LEN
|| m.Index == bmark && m.Length >= MAX_LEN) {
sb.Append(strInput.Substring(bmark, m.Index - bmark + m.Length).Trim() + Environment.NewLine);
bmark = m.Index + m.Length;
} return null;
}, RegexOptions.Singleline);
if (bmark != strInput.Length) // last portion
sb.Append(strInput.Substring(bmark));
string strModified = sb.ToString(); // get the real string from builder
It's also worth noting the second condition in the if expression in the Match Evaluator m.Index == bmark && m.Length >= MAX_LEN is meant as an exceptional condition in case there is a word longer than 60 chars (or longer than the set max length) - it will not be broken down here but just stored on one line by itself - I guess you might want to create a second formula for that condition in the real world to hyphenate it or something.
An other one ...
public static string SplitLongWords(string text, int maxWordLength)
{
var reg = new Regex(#"\S{" + (maxWordLength + 1) + ",}");
bool replaced;
do
{
replaced = false;
text = reg.Replace(text, (m) =>
{
replaced = true;
return m.Value.Insert(maxWordLength, " ");
});
} while (replaced);
return text;
}
I would start with saving the length of the original string. Then, start backwards, and just subtract, since odds are that I would get below 60 faster by starting at the last word and going back than building up.
Once I know how long, then just use StringBuilder and build up the string for the new string.
List<string> lines = new List<string>();
while (message.Length > 60) {
int idx = message.LastIndexOf(' ', 60);
lines.Add(message.Substring(0, idx));
message = message.Substring(idx + 1, message.Length - (idx + 1));
}
lines.Add(message);
You might need to modify a bit to handle multiple spaces, words with >60 chars in them, ...
I tried the original solution and found that it didn't quite work. I've modified it slightly to make it work. It now works for me and solves a problem I had. Thanks.
Jim.
public static List<String> FormatMe(String message)
{
int maxLength = 10;
List<String> Line = new List<String>();
String[] words;
message = message.Trim();
words = message.Split(" ".ToCharArray());
StringBuilder sentence = new StringBuilder();
foreach (String word in words)
{
if((sentence.Length + word.Length) <= maxLength)
{
sentence.Append(word + " ");
}
else
{
Line.Add(sentence.ToString().Trim());
sentence = new StringBuilder(word + " ");
}
}
if (sentence.Length > 0)
Line.Add(sentence.ToString().Trim());
return Line;
}
private void btnSplitText_Click(object sender, EventArgs e)
{
List<String> Line = new List<string>();
string message = "The quick brown fox jumps over the lazy dog.";
Line = FormatMe(message);
}

Categories