Create a list of objects with initialized properties from a string with infos
Create a list of objects with initialized properties from a string with infos
I have a string that looks like that:
random text 12234
another random text
User infos:
User name : John
ID : 221223
Date : 23.02.2018
Job: job1
User name : Andrew
ID : 378292
Date : 12.08.2017
Job: job2
User name : Chris
ID : 930712
Date : 05.11.2016
Job : job3
some random text
And this class:
class User
public string UserName get; set;
public string ID get; set;
public string Date get; set;
public string Job get; set;
public User(string _UserName, string _ID, string _Date, string _Job)
UserName = _UserName
ID = _ID;
Date = _Date;
Job = _Job;
And I want to create a List of Users with informations from that string.
I have tried doing that:
List<User> Users = new List<User>();
string Data = (the data above)
string lines = Data.Split(new string Environment.NewLine , StringSplitOptions.RemoveEmptyEntries);
List<string> UserNames = new List<string>();
List<string> IDs = new List<string>();
List<string> Dates = new List<string>();
List<string> Jobs = new List<string>();
foreach (var line in lines)
if (line.StartsWith("User name : "))
UserNames.Add(Line.Remove(0, 12));
if (Line.StartsWith("ID : "))
IDs.Add(Line.Remove(0, 5));
if (Line.StartsWith("Date : "))
Dates.Add(Line.Remove(0, 7));
if (Line.StartsWith("Job : "))
Jobs.Add(Line.Remove(0, 6));
var AllData = UserNames.Zip(IDs, (u, i) => new UserName = u, ID = i );
foreach (var data in AllData)
Users.Add(new User(data.UserName, data.ID, "date", "job"));
But I can only combine two lists using this code. Also, I have more than 4 values for each user (the string above was just a short example) .
Is there a better method? Thanks.
No, it is just plain text. You can see the example above.
– asfdev991
Sep 4 '18 at 12:45
Welcome to StackOverflow @asfdev991. Please remember to add extra information about the question into the question itself so that future readers don't have to trawl the comments to find it ;)
– Ian
Sep 4 '18 at 12:53
do you read it from a file? is there always this empty line between the entries?
– Mong Zhu
Sep 4 '18 at 13:03
Yes, there is always a empty line between the entries. And the string also has other text in it, so I should ignore it. I have updated the question.
– asfdev991
Sep 4 '18 at 13:07
4 Answers
4
Since it seems to be always 4 lines of information you could go in steps of 4
with a loop through the splitted array lines
. At each step you would split by colon :
and collect the last item, which is the desired value:
4
lines
:
EDIT: In this case I would suggets to look for the START of the data.
int startIndex = Data.IndexOf("User name");
EDIT 2:
also ends with another line of text
then you can use LastIndexOf to find the end of the important information:
int endIndex = Data.LastIndexOf("Job");
int lengthOfLastLine = Data.Substring(endIndex).IndexOf(Environment.NewLine);
endIndex += lengthOfLastLine;
and then simply take a SubString from the startindex on until the end
string lines = Data.Substring(startIndex, endIndex - startIndex)
.Split(new string Environment.NewLine , StringSplitOptions.RemoveEmptyEntries);
List<User> allUsers = new List<UserQuery.User>();
for (int i = 0; i < lines.Length; i += 4)
string name = lines[i].Split(':').Last().Trim();
string ID = lines[i + 1].Split(':').Last().Trim();
string Date = lines[i + 2].Split(':').Last().Trim();
string Job = lines[i + 3].Split(':').Last().Trim();
allUsers.Add(new User(name, ID, Date, Job));
Ahhh, and you should Trim
the spaces away.
This solution should be readable. The hard coded step size of 4
is actually annoying in my solution
Trim
4
Disclaimer: This solution works only as long as the format does not change. If the order of the lines should change, it will return false results
Great idea. I prefer
Remove
to Split()
though.– aloisdg
Sep 4 '18 at 12:57
Remove
Split()
With semicolon it is the same as .csv format
– Fabjan
Sep 4 '18 at 13:00
I forgot to say that the string also ends with another line of text (you can see the updated example in the question). In reality, each entry has 7 lines (not 4 as I said above), so I have changed "i +=4" to "i+=7" and I have added the remaining string (until string ExString = lines[i + 6].Split(':').Last().Trim();) but now I get "Index was outside the bounds of the array."
– asfdev991
Sep 4 '18 at 13:30
@asfdev991 something else you forgot to say ? ;) hehe ok, there is a method: LastIndexOf actually you should have enough information to fix it on your own now ;) You can use it to calculate the real endIndex then take this overload of SubString and get only the important part
– Mong Zhu
Sep 4 '18 at 13:40
Yes, I have fixed the issue.
– asfdev991
Sep 4 '18 at 14:02
Instead of checking each line to add each of them to a a list, you can create your list of User directly. There you go:
Code:
var users = data.Split(new "nn" , StringSplitOptions.None).Select(lines =>
var line = lines.Split(new "n" , StringSplitOptions.None);
return new User(line[0].Substring(11), line[1].Substring(4), line[2].Substring(6), line[3].Substring(5));
);
Try it online!
As @Mong Zhu answer, remove everything before and after. A this point, this is another question I wont try to solve. Remove the noise before and after then parse your data.
The 3rd record (for "chris") is different from the rest
– Tian van Heerden
Sep 4 '18 at 13:26
@TianvanHeerden updated :)
– aloisdg
Sep 4 '18 at 13:38
Yes, I made a mistake.
– asfdev991
Sep 4 '18 at 13:39
For a robust, flexible and self-documenting solution that will allow you to easily add new fields, ignore all the extraneous text and also cater for variations in your file format (this seems to be the case with, for example, no space in "ID:" only in the 3rd record), I would use a Regex
and some LINQ to return a collection of records as follows:
Regex
using System.Text.RegularExpressions;
public class Record
public string Name get; set;
public string ID get; set;
public string Date get; set;
public string Job get; set;
public List<Record> Test()
string s = @"User name : John
ID : 221223
Date : 23.02.2018
Job: job1
User name : Andrew
ID : 378292
Date : 12.08.2017
Job: job2
User name : Chris
ID: 930712
Date : 05.11.2016
Job: job3
";
Regex r = new Regex(@"Usersnames:s(?<name>w+).*?IDs:s(?<id>w+).*?Dates:s(?<date>[0-9.]+).*?Job:s(?<job>ww+)",RegexOptions.Singleline);
r.Matches(s);
return (from Match m in r.Matches(s)
select new Record
Name = m.Groups["name"].Value,
ID = m.Groups["id"].Value,
Date = m.Groups["date"].Value,
Job = m.Groups["job"].Value
).ToList();
The CSV format seems to be what you're looking for (since you want to add some header to this file the actual CSV stars on 6th line):
random text 12234
another random text
User infos:
UserName;ID;Date;Job
John;221223;23.02.2018;job1
Andrew;378292;12.08.2017;job2
Chris;930712;05.11.2016;job3
And then you could read this file and parse it:
var lines = File.ReadAllLines("pathToFile");
var dataStartIndex = lines.IndexOf("UserName;ID;Date;Job");
var Users = lines.Skip(dataStartIndex + 1).Select(s =>
var splittedStr = s.Split(';');
return new User(splittedStr[0], splittedStr[1], splittedStr[2], splittedStr[3]);
).ToList();
If you're working with console entry just skip the header part and let user enter comma separated values for each user on a different string. Parse it in a same way:
var splittedStr = ReadLine().Split(';');
var userToAdd = new User(splittedStr[0], splittedStr[1], splittedStr[2] , splittedStr[3]);
Users.Add(userToAdd);
new User().ToList()
wont work. Also, you dont need it if users
doesnt need to be a list.– aloisdg
Sep 4 '18 at 13:40
new User().ToList()
users
The string above is not in the CSV format. It looks more like a INI file, but with a ":"
– asfdev991
Sep 4 '18 at 13:44
Yup, it's CSV-like file, sorry for typos, I've corrected them
– Fabjan
Sep 4 '18 at 13:53
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
is the string is in withing json format?
– styx
Sep 4 '18 at 12:44