C# - customizing image name converted to string - c#

I have a method that copies selected image from an OpenFileDialog to a defined location, and I want to check if an image with the same name exists, and if so to change the name on the fly.
Here is my method:
public void SaveImage(IList<AppConfig> AppConfigs, string ImageNameFilter)
{
string imgPath = AppConfigs[0].ConfigValue.ToString();
Int32 i = 0;
StringBuilder sb = new StringBuilder(selectedFileName);
while (File.Exists(imgPath + "\\" + ImageNameFilter + selectedFileName))
{
sb.Insert(i, 0);
i++;
//ImageNameFilter += (i++).ToString();
}
File.Copy(selectedFile, imgPath + "\\" + ImageNameFilter + selectedFileName);
}
ImageNameFilter is a custom filter that is added at the beginning of each image and the users need this prefix to be able to recognize what the image is used for, only by seeing the prefix. selectedFileName is the name of the image taken with SafeFileName, which means it looks like this - imageName.jpeg.
There are several problems that I have with this code. Firstly, I wanted to change the name like this - imageName1.jpeg, imageName2.jpeg, imageName3.jpeg...imageName14.jpeg.., but if I'm using selectedFileName with the += everything is added, even after the .jpeg, which is not what I want. The only solution that I can think of is to use regex, but I really want to find another way.
Also, incrementing i++ and adding it with += leads to unwanted result which is :
imageName1.jpeg, imageName12.jpeg, imageName123.jpeg...imageName1234567.jpeg.
So, how can I get the result I want and the compromise I see here is to add underscore _ right after the ImageNameFilter and then add i at the beginning of selectedFileName rather in the end as it is by default. But adding something to the beginning of the string is also something I don't know how to do. As you may see I tried StringBuiledr + Insert, but I don't get the expected result.

Basically you need to separate the base file name from the extension (use the helpful methods on Path to do this) before starting the loop, and then keep producing filenames. Each candidate will not be produced based on the last one (it's just based on fixed information and the current iteration count), so you don't need to involve a StringBuilder at all.
Here's one neat way to do it in two steps. First, set up the bookkeeping:
var canonicalFileName = ImageNameFilter + selectedFileName;
var baseFileName = Path.GetFileNameWithoutExtension(canonicalFileName);
var extension = Path.GetExtension(canonicalFileName);
Then do the loop -- here I 'm using LINQ instead of a loop statement because I can, but there's no essential difference from a stock while loop:
var targetFileName = Enumerable.Range(1, int.MaxValue - 1)
.Select(i => Path.Combine(imgPath, baseFileName + i + extension))
.First(file => !File.Exists(file));
File.Copy(selectedFile, targetFileName);

Use Path.GetFileNameWithoutExtension or String.TrimEnd('.') to get the FileName without extension. You can use FileInfo to get the extension as well.

Related

How can I print all the positions in my array on a TextMesh on Unity?

I have a 3D text linked to a public TextMesh. I want all the elements on my public string array to be displayed on that 3D text. When I try to run it on a for loop it runs through all the strings in my array and prints the last position. What I need it to do is to display in that TextMesh all of the strings in my array. I tried to do it with a foreach loop as well, but same result.
This is what I tried:
for (int i = 0; i < myShoppingList.Length; i++){
listText.text = (myShoppingList[i] + "\n");
}
When I hit play, I can only see the last position in my array in the 3DText (although I know it has run through all of them). This is the foreach loop I tried and got the same result with:
foreach (string item in myShoppingList) {
listText.text = (item + "\n");
}
Basically what I need is a way for it to say
listText.text = (myShoppingList[0] + "\n" + myShoppingList[1] + "\n" + myShoppingList[2] + etc.)
I could do it like that, but then if I want to add an item to my list (my string array) I would have to get into this code and add another position at then end. So maybe there is a smart way to do this that I am not seeing!
Any thoughts? Thank you for your time!!!
= will assign the variable to a new value. It's replacing the old text with the current element's.
Instead, you want to append it. That's the + operator.
You can append the new text to the existing contents of listText.text and assign the result of that to listText.text itself (listText.text = listText.text + moreString), or, more conveniently, use the += operator, with is the shorthand for appending followed by assigning to self (listText.text += moreString).
Alternatively, instead of using a loop, you could use the string.Join() method, which will take an IEnumerable or an array, and join all the items with any string (like a newline character, in your case).
For example:
listText.Text = string.Join("\n", myShoppingList);

Incrementer not working inside string replace

I'm attempting to read a line from a file (csv header) and create a column list that prepends "c[num]_" in front of each column with this code:
int colCount=0;
string line = "col1,col2,col3,col4,col5";
string ColumnList = "([" + (++colCount).ToString() + "_" + line.Replace(",", "],[c" + (++colCount).ToString() + "_") + "]";
I know it's not elegant, but I'm also not sure why my colCount variable doesn't increment inside the replace?? It results with a string like:
([c0_col1],[c1_col2],[c1_col3],[c1_col4],[c1_col5])
The counter increments the first time and then not again inside the replace. Any insights? I think it might be better written with a Regex ReplaceEvaluator but I haven't been able to piece that together yet either.
The paramter of the Replace method is string, and the expression you've entered there is just a string. The count will always be 2. It's not a Func, it a string.
You can use the following Linq to easily achieve the conversion you'd like:
string ColumnList = string.Join(",", line.Split(',').Select((s, i) => $"[c{i + 1}_{s}]"));

How Can I split A String from the end to some character I want

How can I split a string from the end to some character I want.
Let me explain in example
"C:\Users\Esat\Desktop\BilimResimler\1620855_759701257391419_1132489417_n.jpg"
and I want to cut this part 1620855_759701257391419_1132489417_n.jpg but I have a lot of image and image names always changing so i can not use substring metod.So how can i do this ?
just to add to the answers - if this refers to a file that physically exists on disk, then why not let fileinfo do the work for you?
var path = #"C:\Users\Esat\Desktop\BilimResimler\1620855_759701257391419_1132489417_n.jpg";
System.IO.FileInfo myImageFile = new System.IO.FileInfo(path);
Console.WriteLine(myImageFile.Name); // gives 1620855_759701257391419_1132489417_n.jpg
You can search for the last "\" character and eliminate everything from it, including him.
OR
From 0 to the index of the length of "C:\Users\Esat\Desktop\BilimResimler\" - 1 (37 - 1 if I counted correctly) keep the string and eliminate everything else.
This should do it
string imageNameAndPath=#"C:\Users\Esat\Desktop\BilimResimler\1620855_759701257391419_1132489417_n.jpg"
imageNameAndPath=imageNameAndPath.Substring(0, imageNameAndPath.LastIndexOf('/'));
string FileName = Path.GetFileName(Path)
You can also get your file name using below code.
var path = #"C:\Users\Esat\Desktop\BilimResimler\1620855_759701257391419_1132489417_n.jpg";
string ImgPath = path.Substring(path.LastIndexOf(#"\") + 1);

Sort FileSystemInfo[] by Name

I have probably spent about 500 hours Googling this and reading MSDN documentation and it still refuses to work the way I want.
I can sort by name for files like this:
01.png
02.png
03.png
04.png
I.e. all the same file length.
The second there is a file with a longer file length everything goes to hell.
For example in the sequence:
1.png
2.png
3.png
4.png
5.png
10.png
11.png
It reads:
1.png, 2.png then 10.png, 11.png
I don't want this.
My Code:
DirectoryInfo di = new DirectoryInfo(directoryLoc);
FileSystemInfo[] files = di.GetFileSystemInfos("*." + fileExtension);
Array.Sort<FileSystemInfo>(files, new Comparison<FileSystemInfo>(compareFiles));
foreach (FileInfo fri in files)
{
fri.MoveTo(directoryLoc + "\\" + prefix + "{" + operationNumber.ToString() + "}" + (i - 1).ToString("D10") +
"." + fileExtension);
i--;
x++;
progressPB.Value = (x / fileCount) * 100;
}
// compare by file name
int compareFiles(FileSystemInfo a, FileSystemInfo b)
{
// return a.LastWriteTime.CompareTo(b.LastWriteTime);
return a.Name.CompareTo(b.Name);
}
It's not a matter of the file length particularly - it's a matter of the names being compared in lexicographic order.
It sounds like in this particular case you want to get the name without the extension, try to parse it as an integer, and compare the two names that way - you could fall back to lexicographic ordering if that fails.
Of course, that won't work if you have "debug1.png,debug2.png,...debug10.png"...you'd need a more sophisticated algorithm in that case.
You're comparing the names as strings, even though (I'm assuming) you want them sorted by number.
This is a well-known problem where "10" comes before "9" because the first character in 10 (1) is less than the first character in 9.
If you know that the files will all consist of numbered names, you can modify your custom sort routine to convert the names to integers and sort them appropriately.
Your code is correct and working as expected, just the sort is performed alphabetically, not numerically.
For instance, the strings "1", "10", "2" are in alphabetical order. Instead if you know your filenames are always just a number plus ".png" you can do the sort numerically. For instance, something like this:
int compareFiles(FileSystemInfo a, FileSystemInfo b)
{
// Given an input 10.png, parses the filename as integer to return 10
int first = int.Parse(Path.GetFileNameWithoutExtension(a.Name));
int second = int.Parse(Path.GetFileNameWithoutExtension(b.Name));
// Performs the comparison on the integer part of the filename
return first.CompareTo(second);
}
I ran into this same issue, but instead of sorting the list myself, I changed the filename by using 6 digit '0' padded key.
My list now looks like this:
000001.jpg
000002.jpg
000003.jpg
...
000010.jpg
But, if you can't change the filenames, you're going to have to implement your own sorting routine to deal with the alpha sort.
How about a bit of linq and regex to fix the ordering?
var orderedFileSysInfos =
new DirectoryInfo(directoryloc)
.GetFileSystemInfos("*." + fileExtension)
//regex below grabs the first bunch of consecutive digits in file name
//you might want something different
.Select(fsi => new{fsi, match = Regex.Match(fsi.Name, #"\d+")})
//filter away names without digits
.Where(x => x.match.Success)
//parse the digits to int
.Select(x => new {x.fsi, order = int.Parse(x.match.Value)})
//use this value to perform ordering
.OrderBy(x => x.order)
//select original FileSystemInfo
.Select(x => x.fsi)
//.ToArray() //maybe?

Path functions for URL

I want to use functions of Path class (GetDirectoryName, GetFileName, Combine,etc.) with paths in URL format with slash (/).
Example of my path:
"xxx://server/folder1/folder2/file"
I tried to do the job with Path functions and in the end just replaced the separator.
I've found that the GetDirectoryName function does not correctly replace the slashes:
Path.GetDirectoryName(#"xxx://server/folder/file") -> #"xxx:\server\folder"
Like you see one slash is lost.
How can I cause the Path functions to use the 'alternative' separator?
Can I use another class with the same functionality?
I'm afraid GetDirectoryName, GetFileName, Combine,etc. use Path.DirectorySeparatorChar in the definition and you want Path.AltDirectorySeparatorChar.
And since Path is a sealed class, I think the only way to go about is string replacement.You can replace Path.DirectorySeparatorChar('\') with Path.AltDirectorySeparatorChar('/') and Path.VolumeSeparatorChar(':') with ":/"
For GetDirectoryName(), you can use
pageRoot = uri.Remove(uri.LastIndexOf('/') + 1);
Have you considered using a combination of System.Uri, System.UriBuilder, and (if necessary) custom System.UriParser subclass(es)?
If the URI is a local file URI of the form file://whatever then you can call string path = new Uri(whatever).LocalPath and call the Path methods on it. If you cannot guarantee the Uri is to a local path, you cannot guarantee components of the Uri correspond to machines, folders, files, extensions, use directories, separator characters, or anything else.
Long time after...I was looking for a solution and found this topic, so i decided to make my (very simple) code
string dirRootUpdate = string.Empty;
string fileNameupdate = string.Empty;
string pathToGetUpdate = string.Empty;
string[] _f = Properties.Settings.Default.AutoUpdateServerUrl.Split('/');
for (int i = 0; i < _f.Count() - 1; i++)
{
dirRootUpdate += _f[i];
if (i == 0) // is the first one
{
dirRootUpdate += "/";
}
else if (i != _f.Count() - 2) // not the last one ?
{
dirRootUpdate += "/";
}
}
fileNameupdate = _f[_f.Count() - 1];
the setting "Properties.Settings.Default.AutoUpdateServerUrl" contains the string to be verified
Works fine, may require some refination to look better.
Hope could help someone

Categories