I have a string that contains a first and last name and I wanted to split into two separate strings so I used this code:
string Delname = bkDel.ContactName;
string[] Deltmp = Delname.Split(' ');
string DelFirstName = Deltmp[0];
string DelLastName = Deltmp[1];
It works fine if there is a first and last name but this causes an error if the name string only contains a first name:
Index was outside the bounds of the array.
since Deltmp[1] is null.
Is there a way to check the name string so if it only contains one string then don't try and split?
You can either check on the length of the array:
if (Deltmp.Length > 1)
//Assign to vars
Or you can check if the input string contains spaces:
if (Delname.Contains(" "))
//Do split
For example:
string[] Deltmp = Delname.Split(' ');
if (Deltmp.Length > 1)
//Assign to both
else
//Assign to only one
You could do a simple check like this.
if(Delname.Split(' ').Count() > 1)
{
// Has First and Last Name
}
else
{
// Has Single Name
}
You can use Delname.Trim(' ') method to delete spaces from start and end, and then check string with Delname.Contains(" "))
What about checking the input with regular expressions? Here is a simple regex pattern, but you may need to get more sophisticated depending on your supported language requirements.
Regex reg = new Regex(#"[A-Za-z]+ [A-Za-z]+");
string Delname = bkDel.ContactName;
Delname = Delname.Trim()
if (!reg.IsMatch(Delname)){
// Don't split
return;
}
string[] Deltmp = Delname.Split(' ');
string DelFirstName = Deltmp[0];
string DelLastName = Deltmp[1];
Related
Super new to C# apologize upfront. My goal is to sort a given string. Each word in the string will contain a single number. This number is the position the word should have in the result. Numbers can be from 1 to 9. So 1 will be the first word (not 0).
My plan of attack is to split the string, having one variable of int data-type (int lookingForNum) and the other variable turning that into a String data-type(string stringLookingForNum), then for each loop over the array looking to see if any elements contain string stringLookingForNum, if they do I add it to an emptry string variable, lastly add 1 to int variable lookingForNum. My issue seems to be with the if statement with the Contains method. It will not trigger the way I currently have it written. Hard coding in if (word.Contains("1")) will trigger that code block but running it as written below will not trigger the if statement.Please can anyone tell my WHY!?!? I console.log stringLookingForNum and it is for sure a string data type "1"
This noobie would appreciate any help. Thanks!
string testA = "is2 Thi1s T4est 3a"; //--> "Thi1s is2 3a T4est"
string[] arrayTestA = testA.Split(' ');
string finalString = string.Empty;
int lookingForNum = 1; //Int32
foreach (string word in arrayTestA){
string stringLookingForNum = lookingForNum.ToString();
//Don't understand why Contains is not working as expected here)
if (word.Contains(stringLookingForNum)){
finalString = finalString + $"{word} ";
}
lookingForNum++;
}
you need this - look for the string with 1, the look for the string with 2 etc. Thats not what you are doing
you look at the first string and see if it contains one
then look at the second one and see if it contains 2
....
int lookingForNum = 1;
while(true){ // till the end
string stringLookingForNum = lookingForNum.ToString();
bool found = false;
foreach (string word in arrayTestA){
if (word.Contains(stringLookingForNum)){
finalString = finalString + $"{word} ";
found = true;
break;
}
}
if(!found) break;
lookingForNum++;
}
To sort you should simply use OrderBy, and since you need to sort by number inside a word - just Find and extract a number from a string
string testA = "is2 Thi1s T4est 3a";
var result = testA.Split().OrderBy(word =>
Int32.Parse(Regex.Match(word, #"\d+").Value));
Console.WriteLine(string.Join(" ", result));
So what I am trying to do is as follows :
example of a string is A4PC
I am trying to replace for example any occurance of "A" with "[A4]" so I would get and similar any occurance of "4" with "[A4]"
"[A4][A4]PC"
I tried doing a normal Replace on the string but found out I got
"[A[A4]]PC"
string badWordAllVariants =
restriction.Value.Replace("A", "[A4]").Replace("4", "[A4]")
since I have two A's in a row causing an issue.
So I was thinking it would be better rather than the replace on the string I need to do it on a character per character basis and then build up a string again.
Is there anyway in Linq or so to do something like this ?
You don't need any LINQ here - String.Replace works just fine:
string input = "AAPC";
string result = input.Replace("A", "[A4]"); // "[A4][A4]PC"
UPDATE: For your updated requirements I suggest to use regular expression replace
string input = "A4PC";
var result = Regex.Replace(input, "A|4", "[A4]"); // "[A4][A4]PC"
This works well for me:
string x = "AAPC";
string replace = x.Replace("A", "[A4]");
EDIT:
Based on the updated question, the issue is the second replacement. In order to replace multiple strings you will want to do this sequentially:
var original = "AAPC";
// add arbitrary room to allow for more new characters
StringBuilder resultString = new StringBuilder(original.Length + 10);
foreach (char currentChar in original.ToCharArray())
{
if (currentChar == 'A') resultString.Append("[A4]");
else if (currentChar == '4') resultString.Append("[A4]");
else resultString.Append(currentChar);
}
string result = resultString.ToString();
You can run this routine with any replacements you want to make (in this case the letters 'A' and '4' and it should work. If you would want to replace strings the code would be similar in structure but you would need to "look ahead" and probably use a for loop. Hopefully this helps!
By the way - you want to use a string builder here and not strings because strings are static which means space gets allocated every time you loop. (Not good!)
I think this should do the trick
string str = "AA4PC";
string result = Regex.Replace(str, #"(?<Before>[^A4]?)(?<Value>A|4)(?<After>[^A4]?)", (m) =>
{
string before = m.Groups["Before"].Value;
string after = m.Groups["After"].Value;
string value = m.Groups["Value"].Value;
if (before != "[" || after != "]")
{
return "[A4]";
}
return m.ToString();
});
It is going to replace A and 4 that hasn't been replaced yet for [A4].
from textbox inside winform I'm taking user input as csv and I'm putting them into string array where I iterate trough that array to create some object with first and last names.
if(txtAuthors.Text != string.Empty)
{
if(txtAuthors.Text.Contains(","))
{
if (authorsInput.Count() > 0)
{
foreach (string name in authorsInput)
{
name.TrimStart();
string[] firstAndLastName = name.Split(' ');
string fname = firstAndLastName[0];
string lname = firstAndLastName[1];
}
}
}
}
Problem is that only first author before first comma is added as it should (fname and lname) and other only lastname. So I've tried as you can see to trim name to remove whitespace from array members but problem is still the same.
What I'm doing wrong here?
update:this now works
string[] firstAndLastName = name.TrimStart().Split(' ');
but I still don't know why this don't work
name.TrimStart();
string[] firstAndLastName = name.Split(' ');
Calling name.TrimStart() doesn't result in a variable name without initial blanks because strings are immutable objects.
You cannot modify a string in place. You always need to assign the result of the operation to a new string.
Your second option works because it is like:
string newname = name.TrimStart();
string[] firstAndLastName = newname.Split(' ');
Also, notice that I use a new variable for the result of the TrimStart. This is required if you do that inside the foreach loop because it is not allowed to change the foreach iteration variable
You can use Trim() cuts all whitespaces before and after
'fname = fname.Trim();'
I have a name which is made of a prefix a type and name , i want to retrieve the name part.
Prefix always remains same but Type can change.
I have the following code to get the name part:
string prefix = "Prefix-";
string str =prefix + "Type-hello-j---.xml";
str = Path.GetFileNameWithoutExtension(str);
str = str.Substring(prefix.Length);
str = str.Substring(str.IndexOf('-') + 1);
In the above example the name part is: hello-j---
Is there any efficient/better way to do the same in C# ?
You can use an overload of string.Split() that lets you specify the number of parts:
string fileName = "Prefix-Type-hello-j---.xml";
string withoutExtension = Path.GetFileNameWithoutExtension(str);
var parts = str.Split(new[]{'-'}, 3);
string name = parts[2];
If this is always the structure of your string, this would work :
string name = str.Split(new[]{'-'})[2];
I'm assuming you only want "hello". If you want the rest of the name you could use the overloaded method as #KingCronus suggested :
string name = str.Split(new[]{'-'}, 3)[2];
You can also create an extension function that works like String.IndexOf but that gets the position of the nth occurrence of the specified character:
public static int IndexOfWithCount(this string input, char character, int occurenceNumber)
{
int count = 0;
for (int numCaracter = 0; numCaracter < input.Length; numCaracter++)
if (input[numCaracter] == character)
{
count++;
if (count == occurenceNumber)
return numCaracter;
}
return -1;
}
To use it:
string nameWithoutExt = Path.GetFileNameWithoutExtension(str);
string result = nameWithoutExt.Substring(nameWithoutExt.IndexOfWithCount('-', 2) + 1);
It depends how you define efficient but if lines of code fits your defintion how about:
var str = "prefix-Type-hello-j---.xml";
var name = Regex.Match(str, #"(.+?-)(.+?-)(?<name>.+)\.").Groups["name"].Value;
The first two capturing groups consume the prefix and the the type then the namedgroup consumes the name until the extension starts.
This code assumes there is always a match, if there is not it will throw a nullreference exception.
See Regex.Match
I cannot believe I am having trouble with this following string
String filter = "name=Default;pattern=%%;start=Last;end=Now";
This is a short and possibly duplicate question, but how would I split this string to get:
string Name = "Default";
string Pattern = "%%" ;
string start = "Last" ;
string end = "Now" ;
Reason why I ask is my deadline is very soon, and this is literally the last thing I must do. I'm Panicking, and I'm stuck on this basic command. I tried:
pattern = filter.Split(new string[] { "pattern=", ";" },
StringSplitOptions.RemoveEmptyEntries)[1]; //Gets the pattern
startDate = filter.Split(new string[] { "start=", ";" },
StringSplitOptions.RemoveEmptyEntries)[1]; //Gets the start date
I happen to get the pattern which I needed, but as soon as I try to split start, I get the value as "Pattern=%%"
What can I do?
Forgot to mention
The list in this string which needs splitting may not be in any particular order . this is a single sample of a string which will be read out of a stringCollection (reading these filters from Properties.Settings.Filters
Using string.Split this is a two stage process.
In the first case split on ; to get an array of keyword and value pairs:
string[] values = filter.Split(';');
Then loop over the resultant list splitting on = to get the keywords and values:
foreach (string value in values)
{
string[] pair = value.Split('=');
string key = pair[0];
string val = pair[1];
}
String filter = "name=Default;pattern=%%;start=Last;end=Now";
string[] temp = filter.Split('=');
string name = temp[1].Split(';')[0];
string pattern = temp[2].Split(';')[0];
string start = temp[3].Split(';')[0];
string end = temp[4].Split(';')[0];
This should do the trick:
string filter = "name=Default;pattern=%%;start=Last;end=Now";
// Make a dictionary.
var lookup = filter
.Split(';')
.Select(keyValuePair => keyValuePair.Split('='))
.ToDictionary(parts => parts[0], parts => parts[1]);
// Get values out of the dictionary.
string name = lookup["name"];
string pattern = lookup["pattern"];
string start = lookup["start"];
string end = lookup["end"];
The start date ends up at the thrird position in the array:
startDate = filter.Split(new string[] { "start=", ";" }, StringSplitOptions.RemoveEmptyEntries)[2];
Instead of splitting the string once for each value, you might want to split it into the separate key-value pairs, then split each pair:
string[] pairs = filter.Split(';');
string[] values = pairs.Select(pair => pair.Split('=')[1]).ToArray();
string name = values[0];
string pattern = values[1];
string start = values[2];
string end = values[3];
(This code of course assumes that the key-value pairs always come in the same order.)
You could also split the string into intersperced array, so that every other item is a key or a value:
string[] values = filter.Split(new string[] { "=", ";" }, StringSplitOptions.None);
string name = values[1];
string pattern = values[3];
string start = values[5];
string end = values[7];
Edit:
To handle key-values in any order, make a lookup from the string, and pick values from it:
ILookup<string, string> values =
filter.Split(';')
.Select(s => s.Split('='))
.ToLookup(p => p[0], p => p[1]);
string name = values["name"].Single();
string pattern = values["pattern"].Single();
string start = values["start"].Single();
string end = values["end"].Single();
You can use SingleOrDefault if you want to support values being missing from the string:
string name = values["name"].SingleOrDefault() ?? "DefaultName";
The lookup also supports duplicate key-value pairs. If there might be duplicates, just loop through the values:
foreach (var string name in values["name"]) {
// do something with the name
}
Well I tried something like this:
var result = "name=Default;pattern=%%;start=Last;end=Now".Split(new char[]{'=',';'});
for(int i=0;i<result.Length; i++)
{
if(i%2 == 0) continue;
Console.WriteLine(result[i]);
}
and the output is:
Default
%%
Last
Now
Is this what you want?
You see, the thing is now that your Split on filter a second time still starts from the beginning of the string, and it matches against ;, so since the string hasn't changed, you still retrieve previous matches (so your index accessor is off by X).
You could break this down into it's problem parts, such that:
var keyValues = filter.Split(';');
var name = keyValues[0].Split('=')[1];
var pattern = keyValues[1].Split('=')[1];
var start = keyValues[2].Split('=')[1];
var end = keyValues[3].Split('=')[1];
Note that the above code is potentially prone to error, and as such should be properly altered.
You can use the following:
String filter = "name=Default;pattern=%%;start=Last;end=Now";
string[] parts = filter.Split(';');
string Name = parts[0].Substring(parts[0].IndexOf('=') + 1);
string Pattern = parts[1].Substring(parts[1].IndexOf('=') + 1);
string start = parts[2].Substring(parts[2].IndexOf('=') + 1);
string end = parts[3].Substring(parts[3].IndexOf('=') + 1);
Use this:
String filter = "name=Default;pattern=%%;start=Last;end=Now";
var parts = filter.Split(';').Select(x => x.Split('='))
.Where(x => x.Length == 2)
.Select(x => new {key = x[0], value=x[1]});
string name = "";
string pattern = "";
string start = "";
string end = "";
foreach(var part in parts)
{
switch(part.key)
{
case "name":
name = part.value;
break;
case "pattern":
pattern = part.value;
break;
case "start":
start = part.value;
break;
case "end":
end = part.value;
break;
}
}
If you don't need the values in named variables, you only need the second line. It returns an enumerable with key/value pairs.
My solution has the added benefits that the order of those key/value pairs in the string is irrelevant and it silently ignores invalid parts instead of crashing.
I found a simple solution on my own too. Most of your answers would have worked if the list would have been in the same order every single time, but it wont be. the format however, will always stay the same. The solution is a simple iteration using a foreach loop, and then checking if it starts with a certain word, namely, the word I am looking for, like Name, Pattern etc.
Probably not the most cpu efficient way of doing it, but it is C# for dummies level. Really brain-fade level.
Here is my beauty.
foreach (string subfilter in filter.Split(';')) //filter.Split is a string [] which can be iterated through
{
if (subfilter.ToUpper().StartsWith("PATTERN"))
{
pattern = subfilter.Split('=')[1];
}
if (subfilter.ToUpper().StartsWith("START"))
{
startDate = subfilter.Split('=')[1];
}
if (subfilter.ToUpper().StartsWith("END"))
{
endDate = subfilter.Split('=')[1];
}
}