Split string issues with null position - c#

I have a string of the days of the week. I parse it in C# and store each day in a separate variable. For example:
string weekdayName = "Mon,Tue,Wed,Thu,Fri,Sat,Sun";
And the I split them using ',' as a delimiter:
var weekDayName = weekDay.Split(',');
var firstDay = weekDayName[0];
var secondDay = weekDayName[1];
var thirdDay = weekDayName[2];
var fourthDay = weekDayName[3];
var fifthDay = weekDayName[4];
var sixDay = weekDayName[5];
var seventhDay = weekDayName[6];
Everything works. However, the string dynamically changes. A user assigns the days of the week. For example a string weekDayName could only contain "Mon,Tue". But the problem i'm running into is if not all the position contains value it will fail.
Index was outside the bounds of the array.
I have tried:
if (weekDayName[5].Length >0)
{
var sixDay = weekDayName[5];
}
But it still fails...
How can I check and grab the value of the existing data, if some of the position are missing I just ignore them?
What I'm trying to achieve is:
DateTime currentDay = new DateTime();
currentDay = DateTime.Now;
if (currentDay.ToString("ddd") == firstDay || currentDay.ToString("ddd") == seconday)
{
// I will check the currentDay against every day of the week
//do something
}

Your index out of range is not coming from where you think. I am of course assuming this since you tried to check length on an element that was never set if the user enters Mon,Tue.
var enteredDays = weekDay.Split(',');
for(var i = 0; i < enteredDays.Length; i++)
{
var day = enteredDays[i];
if(i == 0)
first = day;
else if(i == 1)
second = day;
... etc....
}
Now you can check String.IsNullOrEmpty(..yourDay..) when you need to use the values you pulled from the array. You can't use .Length on them because they are null and will blow up unless you default them all to string.Empty.

There must be some smarter way of doing this, but since i do not know where the string originates from, it is hard for me to make a better solution.
However, given the current requirements, you could do something like:
string weekdayName = "Mon,Tue,Wed,Thu,Fri,Sat,Sun";
List<String> weekDaysList = weekdayName.Split(',').ToList();
foreach (var weekDay in weekDaysList.Take(2))
{
if (weekDay == DateTime.Now.ToString("ddd"))
{
// do something
break;
}
}

If you're willing to try Linq (which is a language feature of C# 3.5 and higher, just include the System.Linq namespace) you could do it like this:
string[] names = weekdayName
.Split(',')
.Select(s => s.Trim())
.Where(s => s.Length > 0)
.ToArray();
The names array now contains all non-empty day names, without any leading or trailing spaces.

Wow that's a lot of code for a simple check, As mentioned by other members you can use LINQ to merge all validations in single query something like :
string weekdayName = "Mon,Tue,Wed,Thu,Fri,Sat,Sun";
var wc = weekdayName.Split(',');
if (wc.Any(str => str.Contains(DateTime.Today.DayOfWeek.ToString().Substring(0,3))))
{
}
Try this and let me know if you have any concerns.

Related

How to replace a string in a text file which starts with a specific word and ends with a special character in C#?

I am developing an app which offers management of a production process by reading and writing to a text file. First of all, it reads from the text file and puts the information into a datagridview like:
And then it should be possible to update the information in the text file when a cell value is changed.
Here is the example test file:
567,Eindhoven,IGT,21,Stripping_e=20/05/2020,Stripping_s=21/05/2020,Stripping_f=,Cleaning_e=23/05/2020,Cleaning_s=27/05/2020,Cleaning_f=28/05/2020,Paint_e=28/05/2020,Paint_s=28/05/2020,Paint_f=29/05/2020,Cabinet_e=29/05/2020,Cabinet_s=31/05/2020,Cabinet_f=,Table_e=,Table_s=,Table_f=05/06/2020,Stand_e=05/06/2020,Stand_s=08/06/2020,Stand_f=,Display_e=08/06/2020,Display_s=11/06/2020,Display_f=,UControls_e=15/06/2020,UControls_s=,UControls_f=,Test_e=19/06/2020,Test_s=,Test_f=20/06/2020,Prepack_e=21/06/2020,Prepack_s=22/06/2020,Prepack_f=,Endpack_e=27/06/2020,Endpack_s=28/06/2020,Endpack_f=,Release_e=30/06/2020,Release_s=,Release_f=,
What I want to do is basically replace the date stored in the file with the new one entered in the cell. For example for Cleaning_e=23/05/2020, I want to check if the string starts with Cleaning_e= and ends with , replace it with Cleaning_e=12/09/2020, i.e. entered new date in the cell.
My current code is:
private void ExportToTextFile(int selectedDate)
{
string filename = dataGridView1.Rows[clickedRow].Cells[0].Value.ToString();
// TextWriter writer = new StreamWriter($"../../{filename}.txt");
var text = new StringBuilder();
foreach (string s in File.ReadAllLines($"../../{filename}.txt"))
{
/* if (clickedColumn == 3 && selectedDate == 0)
text.AppendLine(s.Replace("Stripping_e=", $"Stripping_e={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
else if (clickedColumn == 3 && selectedDate == 1)
text.AppendLine(s.Replace("Stripping_s=", $"Stripping_s={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
else if (clickedColumn == 3 && selectedDate == 2)
text.AppendLine(s.Replace("Stripping_f=", $"Stripping_f={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
else if (clickedColumn == 3 && selectedDate == 3)
text.AppendLine(s.Replace("Stripping_d=", $"Stripping_d={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
else */if (clickedColumn == 4 && selectedDate == 0)
{
text.AppendLine(s.Replace("Cleaning_e=", $"Cleaning_e={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
}/*
else if (clickedColumn == 4 && selectedDate == 1)
text.AppendLine(s.Replace("Cleaning_s=", $"Cleaning_s={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
else if (clickedColumn == 4 && selectedDate == 2)
text.AppendLine(s.Replace("Cleaning_f=", $"Cleaning_f={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));
else if (clickedColumn == 4 && selectedDate == 3)
text.AppendLine(s.Replace("Cleaning_d=", $"Cleaning_d={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}"));*/
}
using (var file = new StreamWriter(File.Create($"../../{filename}.txt")))
{
file.Write(text.ToString());
}
}
After I did text.AppendLine(s.Replace("Cleaning_e=",$"Cleaning_e={dataGridView1.Rows[clickedRow].Cells[clickedColumn].Value.ToString()}")); it wrote into the file: Cleaning_e=12/09/202023/05/2020.
How do I make sure to get rid of the old date entered before I append the new date?
I tried removing this string and writing into the index of the removed string, but I could not make it work. I also tried using regex but I was not successful.
Thanks in advance!
In order to replace it with Regex you can use
var testText = "some other stuff Cleaning_e=12/43/4555, some more ";
var newValue = "78/65/0000";
var rx = new Regex(#"Cleaning_e=(\d\d/\d\d/\d\d\d\d)?");
var result = rx.Replace(testText, $"Cleaning_e={newValue}");
this will replace the date. Beware that this replaces every occurance of Cleaning_e and requires the date format to be exactly to have axactly 2 2 and 4 Digits. If the number of digits vary, you can use
var rx = new Regex(#"Cleaning_e=(\d+/\d+/\d+)?");
instead.
I'd rather recomment to parse this into a proper structure and change the values there rather than Manipulating the text file directly.
If it were me... I'd first parse the file by breaking all of the fields at the command (using string.Split):
private const string SomeStuff =
"567,Eindhoven,IGT,21,Stripping_e=20/05/2020,Stripping_s=21/05/2020,Stripping_f=,Cleaning_e=23/05/2020,Cleaning_s=27/05/2020,Cleaning_f=28/05/2020,Paint_e=28/05/2020,Paint_s=28/05/2020,Paint_f=29/05/2020,Cabinet_e=29/05/2020,Cabinet_s=31/05/2020,Cabinet_f=,Table_e=,Table_s=,Table_f=05/06/2020,Stand_e=05/06/2020,Stand_s=08/06/2020,Stand_f=,Display_e=08/06/2020,Display_s=11/06/2020,Display_f=,UControls_e=15/06/2020,UControls_s=,UControls_f=,Test_e=19/06/2020,Test_s=,Test_f=20/06/2020,Prepack_e=21/06/2020,Prepack_s=22/06/2020,Prepack_f=,Endpack_e=27/06/2020,Endpack_s=28/06/2020,Endpack_f=,Release_e=30/06/2020,Release_s=,Release_f=,";
var fields = SomeStuff.Split(new[]{','}, StringSplitOptions.None);
At that point, you'd have a collection of strings. Then I'd create a regex like the following:
private const string ParsePattern = #"(?<key>[a-zA-Z0-9_]+)=(?<date>\d{2}/\d{2}/\d{4})";
private static readonly Regex ParseRegex = new Regex(ParsePattern);
That regex looks for any number of letters, numbers or underscores, followed by "=" followed by two digits, a slash, another two digits, another slash and finally four more digits. The "group" before the equals sign will be named "key" and the date after the equals sign named "date".
Finally, I'd build a list of fields that don't have a date and a dictionary to hold field-name/date combinations:
var noDateStrings = new List<string>();
var dateDictionary = new Dictionary<string, DateTime>();
With that in had, I'd loop through my parsed collection of strings. If there's a match to the regex, I'd take the two components and put them in the dictionary. If there's no match, then I'd stick them into my no-match List<string>:
foreach (var field in fields)
{
var patternMatches = ParseRegex.Matches(field);
if (patternMatches.Count == 0)
{
noDateStrings.Add(field);
}
else
{
var groups = patternMatches[0].Groups;
var date = DateTime.ParseExact(groups["date"].ToString(), "dd/mm/yyyy",
CultureInfo.InvariantCulture);
dateDictionary.Add(groups["key"].ToString(), date);
}
}
You have all the information you need here to do whatever you'd like.
One final thing to note. I almost always advocate for using TryParse instead of Parse when parsing things. However, in this case, I know that the string matches a date pattern. Unless that string represents an illegal date (say 32/13/2020), then it will parse fine.

Sorting months according to calendar year

I currently have some code that can sort strings in alphabetic order. I would like for it to sort the months according to the calendar year. I have seen ways to do it on this website but cant apply them to my code specifically. What would I need to add to make it sort in order (January, February etc etc).
Code to read months to array:
var month1Values = File
.ReadAllLines(monthFilePath)
.Select(x => new { Name = monthFilePath, Sort = DateTime.ParseExact(x, "MMMM", CultureInfo.InvariantCulture) })
.ToArray();
Code to sort:
if (SortFile == 3)
{
comparison1 = string.Compare(fileData[index].MonthValues,
fileData[index + 1].MonthValues) > 0;
if (comparison1)
{
temp = fileData[index].MonthValues;
fileData[index].MonthValues = fileData[index + 1].MonthValues;
fileData[index + 1].MonthValues = temp;
swap = true;
}
}
Error appears where asterix is:
for (var index = 0; index < datasize; index++)
{
fileData[index] = new FileData
{
DayValues = day1Values[index],
MonthValues = *month1Values[index]*,
};
}
Error reads cannot convert type '< annonymous type: string Name, System.DateTime Sort >' to 'string'. How do I fix this problem?
You are creating anonymous data types in your Select instruction (first code box, line 3) instead of relying on DateTime type. The runtime don't know how to cast your anonymous type to String.
This should work as expected:
.Select(x => DateTime.ParseExact(x, "MMMM", CultureInfo.InvariantCulture))
Be aware that normal DateTime->String cast involves creating a full date from only month given; this involves assuming that day and year is current with hour, minute and second zeroed out.

Read specific values out of a text-file and put them in a list

I have a text-file with many lines, each line looks like this:
"string string double double" between each value is a space. I'd like to read out the first string and last double of every line and put these two values in a existing list. That is my code so far, but it doesnt really work.
private void bOpen_Click(object sender, RoutedEventArgs e)
{
bool exists = File.Exists(#"C:\Users\p2\Desktop\Liste.txt");
if (exists == true)
{
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(#"C:\Users\p2\Desktop\Liste.txt"))
{
Vgl comp = new Vgl();
comp.name = Abzahlungsdarlehenrechner.zgName;
comp.gErg = Abzahlungsdarlehenrechner.zgErg;
GlobaleDaten.VglDaten.Add(comp);
int i = 0;
string line = File.ReadLines(#"Liste.txt").Skip(0).Take(1).First();
while ((line = sr.ReadLine()) != null)
{
sb.Append((line));
listBox.Items.Add(line);
GlobaleDaten.VglDaten.Add(comp);
i++;
}
}
}
I have already read this, but it didnt help How do I read specific value[...]
You can try Linq:
var source = File
.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(line => line.Split(' '))
.Select(items => new Vgl() {
name = items[0],
gErg = double.Parse(items[3])
});
// If you want to add into existing list
GlobaleDaten.VglDaten.AddRange(source);
// If you want to create a new list
//List<Vgl> list = source.ToList();
how about
List<Vgl> Result = File.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(x => new Vgl()
{
name = x.Split(' ').First(),
gErg = decimal.Parse(x.Split(' ').Last(), NumberStyles.AllowCurrencySymbol)
})
.ToList();
I would avoid storing money within doulbe values because this could lead to rounding issues. Use decimal instead. Examples here: Is a double really unsuitable for money?
You can use:
string[] splitBySpace = line.Split(' ');
string first = splitBySpace.ElementAt(0);
decimal last = Convert.ToDecimal(splitBySpace.ElementAt(splitBySpace.Length - 1));
Edit : To Handle Currency symbol:
string[] splitBySpace = line.Split(' ');
string pattern = #"[^0-9\.\,]+";
string first = splitBySpace.ElementAt(0);
string last = (new Regex(pattern)).Split(splitBySpace.ElementAt(splitBySpace.Length - 1))
.FirstOrDefault();
decimal lastDecimal;
bool success = decimal.TryParse(last, out lastDecimal);
I agree with #Dmitry and fubo, if you are looking for alternatives, you could try this.
var source = File
.ReadLines(#"C:\Users\p2\Desktop\Liste.txt")
.Select(line =>
{
var splits = line.Split(' '));
return new Vgl()
{
name = splits[0],
gErg = double.Parse(splits[3])
};
}
use string.split using space as the delimiter on line to the string into an array with each value. Then just access the first and last array element. Of course, if you aren't absolutely certain that each line contains exactly 4 values, you may want to inspect the length of the array to ensure there are at least 4 values.
reference on using split:
https://msdn.microsoft.com/en-us/library/ms228388.aspx
Read the whole file as a string.
Split the string in a foreach loop using \r\n as a row separator. Add each row to a list of strings.
Iterate through that list and split again each record in another loop using space as field separator and put them into another list of strings.
Now you have all the four fields containig one row. Now just use First and Last methods to get the first word and the last number.

How to remove comma separated duplicated string values and get last two values

I want to remove comma separated duplicate string values like :
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
And i want to output like this:
String str1 = "6,2";
please tell how to do this i'll my self but i can't solve this
A wild ride with Linq. Probably there is a better way, but this is the first one I could think of.
string str = "2,4,3,12,25,2,4,3,6,2,2,2";
List<string> uniques = str.Split(',').Reverse().Distinct().Take(2).Reverse().ToList();
string newStr = string.Join(",", uniques);
Console.WriteLine(newStr);
Split the string at the comma to get the sequence
Apply the Reverse op, you get 2 2 2 6 .... 4 2
Apply the Distinct, you get 2,6,3,4,25,12
Take the first 2 elements (2,6)
Reverse them 6,2
Join in a new string with the comma sep.
Pretty basic but works in your case
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
String[] arr = str.Split(',');
String penultimate = "";
String ultimate = "";
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] != ultimate)
{
penultimate = ultimate;
ultimate = arr[i];
}
}
Console.WriteLine("{0},{1}", penultimate, ultimate);
Here is a suggestion:
string item = "";
var lastTwoUnique= str.Split(',') //split the string on ,
//now, take the next element from the array as long as it's
//not equal to the previous element (which we store in item)
.Where((st) => st==item ? false : (item = st) == item) //** see comment below
.Reverse() //reverse collection
.Take(2) //take two (two last)
.Reverse() //reverse back
.ToList(); //make it a list
var answer = string.Join(",", lastTwoUnique);
This solution keeps the data intact, so if you want you could store the unique list, then do many queries on that list. Solutions using Distinct() will, for instance, not keep every occurrence of 2 in the list.
This solution has the intermediate result (after Where) of: 2,4,3,12,25,2,4,3,6,2. While distinct will be:2,4,3,12,25,6
** The line .Where((st) => st==item ? false : (item = st) == item) may seem odd, so let me explain:
Where takes a lambda function that returns true for items that should be taken, and false for the items that should be ignored. So st will become each sub string from the Split.
Now, let's investigate the actual function:
st==item //is this st equal to the previous item?
? false //then return false
: (item = st) == item //if it's not equal, then assign `item` to the current `st`
//and compare that to item and get `true`
You could use the .Distinct() extension method.
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
var oldArray=str.Split(',').Reverse();
var collectionWithDistinctElements = oldArray.Distinct().ToArray();
var reverse=collectionWithDistinctElements.Reverse();
//take two element
var twoElements=reverse.ToList().Take(2);
//last join them
var resultArray=string.Join(",", twoElements);
Another solution, which I've attempted to keep quite simple:
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
var holder = new string[2];
foreach (var x in str.Split(','))
{
if(holder.Last() != x)
{
holder[0] = holder[1];
holder[1] = x;
}
}
var result = string.Join(",", holder);
This will iterate over the comma-separated items, all the time keeping the two last seen distinct items in holder.
String str = "2,4,3,12,25,2,4,3,6,2,2,2";
string str = s1;
var uniques = str.Split(',').Reverse().Distinct().Take(3).Reverse().Take(2).ToList();
string newStr = string.Join(",", uniques.ToArray());
This will give me correct output that is 3,6 thats i want.
Thanks to all the Guys that give me ans.
This will definitely work
string str = "2,4,3,12,25,2,4,3,6,2,2,2";
List<string> uniques = new List<string>()
uniques = str.Split(',').Reverse().Distinct().Take(2).Reverse().ToList();
string newStr = string.Join(",", uniques);

How to break this string?

I have a string "10/15/2010"
I want to split this string into 10, 15, 2010 using c#, in VS 2010. i am not sure how to do this. If someone can tell me what function to use, it would be awesome.
Thank you so much!!
You probably want to call
DateTime date = DateTime.Parse("10/15/2010", CultureInfo.InvariantCulture);
string str = "10/15/2010";
string[] parts = str.split('/');
You now have string array parts that holds parts of that initial string.
Take a look at String.Split().
string date = "10/15/2010";
string[] dateParts = date.Split('/');
Or do like a saw in a recent program (in Fortran which I am translating to C# below) ..
string[] parts = "10/15/2010".Split('/');
if( parts[0] == "01" ) month = 1;
if( parts[0] == "02" ) month = 2;
if( parts[0] == "03" ) month = 3;
if( parts[0] == "04" ) month = 4;
...
you get the idea. It kills me when people code it something crazy instead of calling a built in function to do the same thing.
( please don't flag me down, this is just a joke, not a real answer to the question )
Depending on how you plan to consume the information, you can choose strings, like has already been suggested, or parse it into a date then pull out the pieces.
DateTime date = DateTime.Parse("10/15/2010");
int y = date.year;
int m = date.Month;
int d = date.Day;
"10/15/2010".Split('/')
Assuming you wanted the "split" elements to be strings as well:
string date = "10/15/2010";
string[] split = date.Split('/');
var date = "10/15/2010";
var split = date.Split('/')
Simple:
string[] pieces = "10/15/2010".Split ('/');
Using String.Split.

Categories

Resources