Splitting a string after the last space - c#

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];

Related

String text split

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);
}
}
}

SQLite on C#. Select query does not work with string of letters

I'm learning C# since the past week and databases since a couple of days ago, so if you see something dodgy and you ask yourself "Why did he do that like that?", the answer is probably going to be "Because that's all I know for the moment".
In the title I said "of letters" because if I use a string of numbers, it works.
I have a tiny database with three columns. Id (int), FirstName (text) and LastName (text).
Id is unique, primary key and autoincrements. FirstName is unique. The three are not null.
In that database I have two records:
Id FirstName LastName
3- 6666 2222
4- Test O'Test
This is my method:
public static bool isOnDb(string nombre, string apellido)
{
bool flag = false;
{
try
{
using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString()))
{
string tempName = "Test"; // This is temporarily replacing the argument 'nombre'
int tempNum= 3; // More testing. See below
//cnn.Query<Person>($"select * from Person where FirstName = { tempName }", new DynamicParameters());
// This four lines below are just for testing. They are going to be deleted
var output = cnn.Query<Person>($"select * from Person where FirstName = { tempName }", new DynamicParameters());
var person = output.First();
Console.WriteLine("Funciona");
Console.WriteLine($"{ person.Id } - { person.FullName }");
flag = true;
return flag;
}
}
catch (Exception)
{
Console.WriteLine("Derecho a excepcion");
return flag;
}
}
}
Basically, if tempName = "Test", it falls into an exception. But if tempName = "6666" it returns the row.
I also tried selecting by id. That's why tempNum is there.
int tempNum= 4;
var output = cnn.Query<Person>($"select * from Person where Id = { tempNum }", new DynamicParameters());
Well in SQLite the strings are signified by '' so when you pass FirstName = { tempName } and its FirstName = Test it looks for the column called Test in Table person rather than equating it to the 'Test' string
So you can do:
var output = cnn.Query<Person>($"select * from Person where FirstName = '{ tempName }'");
Or better yet:
var people = cnn.Query<Person>("SELECT * FROM PERSON WHERE FirstName = #FirstName", new { FirstName = tempName });

Split full name into first, last and titles

example of the column
I have a column called FULLNAME which consists of a variation of FIRSTNAME and SURNAME separated by a space, and TITLE, FIRSTNAME and SURNAME, all separated by a space. So for example, I could have JOHN SMITH or DR JOHN SMITH.
I am using C# in Visual Studios.
I loop through each of these as per:
foreach (DataRow dr in spreadsheetdata.Tables["EPABase"].Rows)
And my array for the title is as:
title[0] = "Mr";
title[1] = "Mrs";
title[2] = "Miss";
title[3] = "Ms";
title[4] = "Dr";
title[5] = "Rev";
title[6] = "Hon";
title[7] = "Mx";
title[8] = "Other";
It doesn't matter which way around I work, but it's probably easier to get the SURNAME first because it'll always be the the last set of characters in a string, up to the first space value from the right. If I an get this into it's own string of SURNAME, then remove it from the original FULLNAME string, I can then use my array to see if the first set of characters from the left up to the first space appears in it, and if so use as the TITLE string, but if not, use the remaining string after the deletion of the SURNAME to be the FIRSTNAME string.
Just a bit stuck as to how to achieve the first step of this, getting the SURNAME out. I have tried LASTINDEXOF, but this is an integer value, and I need string.
If you are sure that First name or Last Name don't have space in it, you try something like this:
string[] fullNames = { "John Smith", "Dr John Smith" };
string[] titles = { "Mr", "Mrs", "Dr" };
foreach (var item in fullNames)
{
var details = item.Split(' ');
if (titles.Contains(details[0]))
{
Console.WriteLine($"Title: { details[0]} ");
Console.WriteLine($"First Name: { details[1]} ");
Console.WriteLine($"Last Name: { details[2]} ");
}
else
{
Console.WriteLine($"First Name: { details[0]} ");
Console.WriteLine($"Last Name: { details[1]} ");
}
}
To get the surname you can do something as follows:
foreach (DataRow dr in spreadsheetdata.Tables["EPABase"].Rows)
{
var value = dr["FULLNAME"].ToString();
var elementsOfName = value.Split(" ");
var lastName = elementsOfName[elementsOfName.Length - 1];
Console.WriteLine(lastName);
}

separate first middle last name C#

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 cannot modify a variable from a closure, why?

I wanted to see if I can write some c# code in a javascript-fashion way but I got an unexpected behaviour. I know c# is not broken but I don´t understand what is wrong and why it doesn´t do what I think it should.
Code:
class Program
{
static void Main(string[] args)
{
var person = CreatePerson(new{
FirstName = "Lucas",
LastName = "Ontivero",
Age = 34
});
Console.WriteLine("Name....... : {0}", person.FullName);
Console.WriteLine("IsJuvenile. : {0}", person.IsJuvenile);
person.SetFirstName("Pablo");
Console.WriteLine("Name....... : {0}", person.FullName);
Console.ReadKey();
}
static private dynamic CreatePerson(dynamic cfg)
{
string firstName = cfg.FirstName;
string lastName = cfg.LastName;
var age = cfg.Age;
return new{
FullName = string.Format("{0} {1}", firstName, lastName),
FirstName = firstName,
LastName = lastName,
SetFirstName = new Action<string>(fn => firstName= fn),
SetLastName = new Action<string>(ln => lastName = ln),
IsJuvenile = age < 18
};
}
}
Output:
Name....... : Lucas Ontivero
IsJuvenile. : False
Name....... : Lucas Ontivero
But I expected:
Name....... : Lucas Ontivero
IsJuvenile. : False
Name....... : Pablo Ontivero
Why firstName doesn´t change?
It does... but FullName does not. It is computed inside CreatePerson and stored as a string, not a property evaluating to a string later.
You could use lambdas to cause delayed evaluation, as you did with SetFirstName.
It gives you fist assignment of FullName.
You need to re-assign FullName
FullName = string.Format("{0} {1}", firstName, lastName)
On SetFirstName Function

Categories