I have to split this:
string text = "John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
A logic must be created that will separately extract data from this record:
first name;
last name;
place of birth.
In other words, the displayed String must be edited using the method of the String class and each person's data must be extracted separately. The main method to use is to classify Strings on multiple parts.
string text = " John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
string[] textArray = text.Split('"', ' ');
Console.WriteLine("Date: ");
foreach (string str in textArray)
{
for (int i = 0; i < textArray.Length; i++)
{
string[] FirstName = textArray[i].Split(' ');
string[] LastName = textArray[i].Split('.');
string[] BirthPlace = textArray[i].Split('/');
Console.WriteLine($"First name: {FirstName} Last Name: {LastName} BirthPlace: {BirthPlace}");
}
}
For some reason you were iterating your array twice.
string text = " John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
string[] textArray = text.Trim().Split(" ");
Console.WriteLine($"Date: {DateTime.Now} ");
String[] delimiters = { ".", "/" };
for (int i = 0; i < textArray.Length; i++)
{
String[] parts = textArray[i].Split(delimiters,StringSplitOptions.None);
Console.WriteLine($"First name: {parts[0]} Last Name: {parts[1]} BirthPlace: {parts[2]}");
}
}
using System.Text.RegularExpressions;
string pattern = #" *(?<FirstName>\w+)\.(?<LastName>\w+)/(?<BirthPlace>\w+)";
string input = " John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
MatchCollection m = Regex.Matches(input, pattern, RegexOptions.IgnoreCase);
foreach (Match match in m)
{
Console.WriteLine($"First name: {match.Groups["FirstName"]} Last Name: {match.Groups["LastName"]} BirthPlace: {match.Groups["BirthPlace"]}");
}
You're not using the split method properly. Also would be nice to structure the parsing in a Try method which handles errors also. Here's an example:
static bool TryParseRecord(string record, out string firstName, out string lastName, out string birthPlace)
{
firstName = lastName = birthPlace = "";
record = record.Trim();
if (string.IsNullOrEmpty(record))
{
return false;
}
// parse for birth place
var stringSplit = record.Split('/');
if (stringSplit.Length == 2)
{
record = stringSplit[0];
birthPlace = stringSplit[1];
}
else
{
return false;
}
// parse for names
stringSplit = record.Split('.');
if (stringSplit.Length == 2)
{
firstName = stringSplit[0];
lastName = stringSplit[1];
}
else
{
return false;
}
return !string.IsNullOrEmpty(birthPlace) && !string.IsNullOrEmpty(firstName) && !string.IsNullOrEmpty(lastName);
}
With this, your main would become something like:
static void Main()
{
var text = " John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
var textArray = text.Split(' ');
Console.WriteLine("Date: ");
foreach (var entry in textArray)
{
if (TryParseRecord(entry, out var FirstName, out var LastName, out var BirthPlace))
{
Console.WriteLine($"First name: {FirstName}, Last Name: {LastName}, Birth place: {BirthPlace}");
}
}
}
I would start by defining a class to hold the data.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PlaceOfBirth { get; set; }
public Person(string firstName, string lastName, string placeOfBirth)
{
FirstName = firstName;
LastName = lastName;
PlaceOfBirth = placeOfBirth;
}
}
I would then define a class to do the extracting.
The original string seperates each Person by a space, so the first thing we need is to split on the space character. This gives an array with three strings.
John.Davidson/Belgrade
Michael.Barton/Krakow
Ivan.Perkinson/Moscow
Again we can use the Split() function to first split the string to get the names and the place of birth, and then to seperate the first name and the last name.
string[] data = personData.Split('/');
string[] names = data[0].Split('.');
Lastly we simple loop the array, and call the constructor for the Person. Combine it all in a class:
public class PersonDataExtractor
{
public static List<Person> ExtractData(string text)
{
string[] peopleData = text.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries);
var personDataList = new List<Person>();
foreach (string personData in peopleData)
{
string[] data = personData.Split('/');
string[] names = data[0].Split('.');
string firstName = names[0];
string lastName = names[1];
string placeOfBirth = data[1];
personDataList.Add(new Person(firstName, lastName, placeOfBirth));
}
return personDataList;
}
}
This is also easy to unit test. Here with xUnit
public class PersonDataExtractorTests
{
[Fact]
public void ExtractPersonData_ValidInput_ExtractsDataCorrectly()
{
// Arrange
string text = "John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
// Act
var personDataList = PersonDataExtractor.ExtractData(text);
// Assert
Assert.Equal(3, personDataList.Count);
Assert.Equal("John", personDataList[0].FirstName);
Assert.Equal("Davidson", personDataList[0].LastName);
Assert.Equal("Belgrade", personDataList[0].PlaceOfBirth);
Assert.Equal("Michael", personDataList[1].FirstName);
Assert.Equal("Barton", personDataList[1].LastName);
Assert.Equal("Krakow", personDataList[1].PlaceOfBirth);
Assert.Equal("Ivan", personDataList[2].FirstName);
Assert.Equal("Perkinson", personDataList[2].LastName);
Assert.Equal("Moscow", personDataList[2].PlaceOfBirth);
}
}
we do it in python like this:
text = " John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow"
for record in text.split(" "):
if record != "":
temp, city = record.split("/")
name, surname = temp.split(".")
print(f"First name: {name} Last Name: {surname} BirthPlace: {city}")
and I converted it to c#:
using System;
public class Program
{
public static void Main()
{
string text = " John.Davidson/Belgrade Michael.Barton/Krakow Ivan.Perkinson/Moscow";
string[] textArray = text.Split('"', ' ');
foreach (string str in textArray)
{
if(str == ""){
continue;
}
string[] temp = str.Split('/');
string city = temp[1];
temp = temp[0].Split('.');
string name = temp[0];
string surname = temp[1];
Console.WriteLine("First name: "+name+" Last Name: "+surname+" BirthPlace: "+city);
}
}
}
Related
Goal: parse name when user enters name, and have a message box display with first middle and last name. Right now it only works when you type in three names, if you try two it crashes, and I'm sure it's cause of my array but Im not sure where I'm wrong. Super novice, learning on my own so any help would be greatly appreciated!!
P.S. GUI the user sees is just an entry block for them to enter their name into one line, spacing between each word.
private void btnParseName_Click(object sender, System.EventArgs e)
{
string fullName = txtFullName.Text;
fullName = fullName.Trim();
string[] names = fullName.Split(' ');
string firstName = "";
string firstLetter = "";
string otherFirstLetters = "";
if (names[0].Length > 0)
{
firstName = names[0];
firstLetter = firstName.Substring(0, 1).ToUpper();
otherFirstLetters = firstName.Substring(1).ToLower();
}
string secondName = "";
string secondFirstLetter = "";
string secondOtherLetters = "";
if (names[1].Length > 0)
{
secondName = names[1];
secondFirstLetter = secondName.Substring(0, 1).ToUpper();
secondOtherLetters = secondName.Substring(0).ToLower();
}
string thirdName = "";
string thirdFirstLetter = "";
string thirdOtherLetters = "";
if (names[2].Length > 0)
{
thirdName = names[2];
thirdFirstLetter = thirdName.Substring(0, 1).ToUpper();
thirdOtherLetters = thirdName.Substring(0).ToLower();
}
MessageBox.Show(
"First Name: " + firstLetter + otherFirstLetters + "\n\n" +
"Middle Name: " + secondFirstLetter + secondOtherLetters + "\n\n" +
"Last Name: " + thirdFirstLetter + thirdOtherLetters);
Here is the working example how you can do it:
public class FullName
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public FullName()
{
}
public FullName(string fullName)
{
var nameParts = fullName.Split(new [] {' '}, StringSplitOptions.RemoveEmptyEntries);
if (nameParts == null)
{
return;
}
if (nameParts.Length > 0)
{
FirstName = nameParts[0];
}
if (nameParts.Length > 1)
{
MiddleName = nameParts[1];
}
if (nameParts.Length > 2)
{
LastName = nameParts[2];
}
}
public override string ToString()
{
return $"{FirstName} {MiddleName} {LastName}".TrimEnd();
}
}
Usage example:
class Program
{
static void Main(string[] args)
{
var fullName = new FullName("first middle last");
Console.WriteLine(fullName);
Console.ReadLine();
}
}
You need to check for and handle the second name being empty. Initialising the string will prevent the crash, then checking for input.
string secondName = "";
string secondFirstLetter = "";
string secondOtherLetters = "";
if(names.Length > 2)
{
secondName = names[1];
secondFirstLetter = secondName.Substring(0, 1).ToUpper();
secondOtherLetters = secondName.Substring(0).ToLower();
}
In fact it would be worth intialising all your variables or managing user input validation.
As mentioned in another answer you need assign middle name only when third name exists.
Below approach which uses Dictionary.TryGetValue method and C#7 feature for out parameters.
var textInfo = System.Globalization.CultureInfo.CurrentCulture.TextInfo;
var names = fullName.Split(' ')
.Where(name => string.IsNullOrWhiteSpace(name) == false)
.Select(textInfo.ToTitleCase)
.Select((Name, Index) => new { Name, Index })
.ToDictionary(item => item.Index, item => item.Name);
names.TryGetValue(0, out string firstName);
names.TryGetValue(1, out string middleName);
if (names.TryGetValue(2, out string lastName) == false)
{
lastName = middleName;
middleName = null;
}
// Display result
var result = new StringBuilder();
result.AppendLine("First name: ${firstName}");
result.AppendLine("Middle name: ${middleName}");
result.AppendLine("Last name: ${lastName}");
MessageBox.Show(result.ToString());
I know your question has been answered, and there are many ways you could look at handling this, but here is my suggestion with some explanations along the way:
private void button1_Click(object sender, EventArgs e)
{
string fullName = "Jean Claude Van Dam";
fullName = fullName.Trim();
// So we split it down into tokens, using " " as the delimiter
string[] names = fullName.Split(' ');
string strFormattedMessage = "";
// How many tokens?
int iNumTokens = names.Length;
// Iterate tokens
for(int iToken = 0; iToken < iNumTokens; iToken++)
{
// We know the token will be at least one letter
strFormattedMessage += Char.ToUpper(names[iToken][0]);
// We can't assume there is more letters (they might have used an initial)
if(names[iToken].Length > 1)
{
// Add them (make it lowercase)
strFormattedMessage += names[iToken].Substring(1).ToLower();
// Don't need to add "\n\n" for the last token
if(iToken < iNumTokens-1)
strFormattedMessage += "\n\n";
}
// Note, this does not take in to account names with hyphens or names like McDonald. They would need further examination.
}
if(strFormattedMessage != "")
{
MessageBox.Show(strFormattedMessage);
}
}
This example avoids having all of the variables. And it makes use of the operator [].
Hope this helps you too ... :)
public static string getMiddleName(string fullName)
{
var names = fullName.Split(' ');
string firstName = names[0];
string middleName = "";// names[1];
var index = 0;
foreach (var item in names)
{
if (index > 0 && names.Length -1 > index)
{
middleName += item + " ";
}
index++;
}
return middleName;
}
I need to see if string starts with a given string but I am getting ambiguity, here is my code:
string input = "balance1234";
string[] arr = new string[]
{
"bal",
"balance",
};
foreach (string s in arr)
{
if (input.StartsWith(s))
{
var rq= input.Replace(s, "");
}
}
If input is balance1234 , the if condition has to satisfy only with balance, but in my code it is satisfying with bal first.
Here is the solution (using the Hint given by Mr. Skeet):
string input = "balance1234";
string[] arr = new string[]
{
"bal",
"balance",
};
string rq = input;
foreach (string s in arr.OrderByDescending(x => x.Length))
{
if (input.StartsWith(s))
{
rq = input.Replace(s, "");
break;
}
}
Iam making a program that syncs to a DB, and it takes in names, so i want to split the parsed in string into 2 strings after the last "space".
e.g. splitting the name "John Doe Jackson" into:
john Doe and Jackson
so far what ive done i getting the last name:
public static string getLastName(string fullname)
{
string lastName = fullname.Split(' ').LastOrDefault();
}
how to return the rest of the string so i have something like:
firstName: John Doe
lastName: Jackson
EDIT: made it by doing it like this, isnt the cleanest way, but it gets the job done!
public static string getLastName(string fullname)
{
string lastName = fullname.Split(' ').LastOrDefault();
Console.WriteLine(lastName);
return lastName;
}
public static string getFirstName(string fullname)
{
var parts = fullname.Split(' ');
var lastName = parts.LastOrDefault();
var firstName = string.Join(" ", parts.Take(parts.Length - 1));
return firstName;
}
You could try something like this:
var parts = fullname.Split(' ');
var lastName = parts.LastOrDefault();
var firstName = string.Join(" ",parts.Take(parts.Length-1));
I'd do:
var lastSpaceIndex = fullName.LastIndexOf(' ');
var firstName = fullName.Substring(0, lastSpaceIndex);
var lastName = fullName.Substring(lastSpaceIndex+1);
See it in action here
You can use string.Join
public static string getFirstName(string fullname)
{
return string.join(" ",fullname.Split(' ').Take(fullname.Split(' ').Count()-1));
}
Another version based on accepted answer but protecting for string null/empty and in case of no spaces in fullName leaving input as firstName
if (string.IsNullOrWhiteSpace(fullName))
return new KeyValuePair<string, string>(string.Empty, string.Empty);
var parts = fullName.Trim().Split(' ');
if (parts.Length == 1)
return new KeyValuePair<string, string>(parts[0], string.Empty);
var firstName = string.Join(" ", parts.Take(parts.Length - 1));
var lastName = parts.LastOrDefault();
return new KeyValuePair<string, string>(firstName, lastName);
string name = "John Doe Jackson";
var names = name.Split(' ');
string firstname = names[0] + " " + names[1];
string lastname = names[2];
I am reading rows out of a text file and storing them to an array. I now need to then loop through the items in every array position. I can loop through the rows in the document but I need to loop through the array values as well.
Here is my code for reading the text file and building the array :
public class people
{
public string name;
public int empid;
public string address;
}
private void read()
{
using (StreamReader sr = new StreamReader(#"E:\test.txt"))
{
while (sr.Peek() >= 0) << This loops through the rows in the text doc
{
string str;
string[] strArray;
str = sr.ReadLine();
strArray = str.Split(',');
people new_people = new people();
new_people.name = strArray[0];
new_people.empid = int.Parse(strArray[1]); // << I need to be able to loop through each of
new_people.address = strArray[2]; // these and add each on to my query string
peoples.Add(new_people);
listBox1.Items.Add(new_people.name + new_people.empid + new_people.address); //< this displays
// the array values
}
}
I need something like this :
foreach (string foo in new_people.name[0] )
{
cmd.Parameters.Add("#1", SqlDbType.VarChar).Value = foo ;
// then do this for every item in the array for that position
cmd.Parameters.Add("#2", SqlDbType.VarChar).Value = (next set of values);
cmd.Parameters.Add("#3", SqlDbType.VarChar).Value = (next set of values);
cmd.ExecuteNonQuery();
}
Creating your own constructor will help you to create instances of Person class (person is singular, people is plural):
public class Person
{
public string Name;
public int Empid;
public string Address;
public Person(string name, int empid, string address)
{
Name = name;
Empid = empid;
Address = address;
}
}
private void read()
{
using (StreamReader sr = new StreamReader(#"E:\test.txt"))
{
while (sr.Peek() >= 0)
{
string str;
string[] strArray;
str = sr.ReadLine();
strArray = str.Split(',');
Person newPerson = new Person(strArray[0], int.Parse(strArray[1]), strArray[2]);
people.Add(newPerson);
listBox1.Items.Add(newPerson.Name + newPerson.Empid + newPerson.Address);
}
}
You can then loop through all names:
int i = 0;
foreach (Person p in people)
cmd.Parameters.Add("#" + (i++), SqlDbType.VarChar).Value = p.Name;
cmd.ExecuteNonQuery();
I have multiple file in a folder with a naming convention
Name_MoreName_DDMMYYYY_SomeNumber_HHMMSS.txt
How can I get the file which has oldest Date and Time (i.e. oldest DDMMYYYY and HHMMSS).
Ex:
Name_MoreName_22012012_SomeNumber_072334.txt
Name_MoreName_22012012_SomeNumber_072134.txt
Name_MoreName_24012012_SomeNumber_072339.txt
Name_MoreName_22012012_SomeNumber_072135.txt
So the oldest file will be
Name_MoreName_22012012_SomeNumber_072134.txt
how can i take the oldest file only ?
Edit
This is what I have done so far.. in a forach loop I am reading file name one by one
private void FileInformation(string fileName, ref string concatFile)
{
try
{
string completeFileName = fileName.Trim();
string[] fileComponenets = completeFileName.Split('_');
string fileDate = string.Empty;
string fileTime = string.Empty;
if (fileComponenets.Length > 0)
{
fileDate = fileComponenets[4].Replace(".txt", "").Trim();
fileTime = fileComponenets[2].ToString();
concatFile = fileDate + "-" + fileTime;
}
}
catch (Exception ex)
{
}
}
-- Main function
string fileStats = string.Empty;
foreach (string filePath in arrFileCollection)
{
if (filePath.ToLower().Contains("Name_MoreName_")&&
filePath.ToLower().Contains(".txt"))
{
string concatFile = string.Empty;
FileInformation(filePath.Replace(dirPath, ""), ref concatFile);
fileStats = fileStats + "," + concatFile;
}
}
Now I am getting all date time in a string with comma seperated value. Now I am stuck up. How can I take the smallest among them and get the related file
EDIT2
Note: Framework is .NET 2.0
string oldestFile = Directory.EnumerateFiles(path)
.OrderBy(file => ExtractDateTimeFrom(file))
.First(); // FirstOrDefault
And write method which will parse your file name and extract date from it:
public static DateTime ExtractDateTimeFrom(string fileName)
{
Regex regex = new Regex(#".+_(\d\d\d\d\d\d\d\d)_.+_(\d\d\d\d\d\d).txt");
var match = regex.Match(fileName);
string dateString = match.Groups[1].Value + match.Groups[2].Value;
return DateTime.ParseExact(dateString, "ddMMyyyyHHmmsss", null);
}
.NET 2.0 Simplest solution:
string oldestFile = "";
DateTime oldestDate = DateTime.Max;
foreach(string fileName in Directory.GetFiles(path))
{
DateTime date = ExtractDateTimeFrom(fileName);
if (date < oldestDate)
{
oldestFile = fileName;
oldestDate = date;
}
}
something like this maybe?
string[] filePaths = Directory.GetFiles(#"c:\MyDir\");
Regex rex = new Regex(#"^.*_(\d+)\.txt");
int date = int.MaxValue;
int oldestdate = int.MaxValue;
String oldestfile;
foreach(String filePath in filePaths)
{
Match match = rex.Match(filePath);
if(match.Success)
date = int.Parse(match.Groups[0].Value);
if (date < oldestdate)
{
oldestdate = date;
oldestfile = filePath;
}
}
Use DirectoryInfo and FileInfo classes. For example, just to give idea:
IOrderedEnumerable<FileInfo> filesInfo = new DirectoryInfo("D:\\")
.EnumerateFiles()
.OrderBy(f=>f.FullName);
UPDATE: For .NET 2.0, I would suggest you to separate the comparison logic from your main code... so why not create a custom type implementing IComparable interface.
public class CustomFileInfo :IComparable<CustomFileInfo>
{
public string Name { get; set; }
public string MoreName { get; set; }
public DateTime FileDate { get; set; }
public int Number { get; set; }
public DateTime FileTime { get; set; }
public CustomFileInfo(string fileNameString)
{
string[] fileNameStringSplited = fileNameString.Split('_');
this.Name = fileNameStringSplited[0];
this.MoreName = fileNameStringSplited[1];
this.FileDate = DateTime.ParseExact(fileNameStringSplited[2], "ddMMyyyy", null);
this.Number = int.Parse(fileNameStringSplited[3]);
this.FileTime = DateTime.ParseExact(fileNameStringSplited[4], "HHmmss", null);
}
public int CompareTo(CustomFileInfo other)
{
// add more comparison criteria here
if (this.FileDate == other.FileDate)
return 0;
if (this.FileDate > other.FileDate)
return 1;
return -1;
}
}
And then in your code, you may simple get files using DirectoryInfo and compare each files...
FileInfo[] filesInfo = new DirectoryInfo("D:\\").GetFiles();
//set first file initially as minimum
CustomFileInfo oldestFileInfo = new CustomFileInfo(filesInfo[0].FullName);
for (int i = 1; i < filesInfo.Length; i++)
{
CustomFileInfo currentFileInfo = new CustomFileInfo(filesInfo[i].FullName);
//compare each file and keep the oldest file reference in oldestFileInfo
if (oldestFileInfo.CompareTo(currentFileInfo) < 0)
oldestFileInfo = currentFileInfo;
}
You may optimize code for use and customize the comparison code as per your criteria.
Use This:
Updated
List<string> address = new List<string>() { "Name_MoreName_22012011_SomeNumber_072334.txt",
"Name_MoreName_22012012_SomeNumber_072134.txt",
"Name_MoreName_24012012_SomeNumber_072339.txt",
"Name_MoreName_22012012_SomeNumber_072135.txt",};
DateTimeFormatInfo dtfi = new DateTimeFormatInfo();
dtfi.ShortDatePattern = "dd-MM-yyyy";
dtfi.DateSeparator = "-";
address = address.OrderBy(s => Convert.ToDateTime((s.Split('_')[2]).Insert(2, "-").Insert(5, "-"), dtfi)).ToList();
string oldest = address[0];