Split a string base on multiple delimiters specified by user - c#

Updated: Thank you for the answer, but I disagree that my question is answered by another thread. "Multiple delimiters" and "Multi-Character delimiters" are 2 different questions.
This is my code so far:
List<string> delimiters = new List<string>();
List<string> data = new List<string>
{
"Car|cBlue,Mazda~Model|m3",
//More data
};
string userInput = "";
int i = 1;
//The user can enter a maximum of 5 delimiters
while (userInput != "go" && i <= 5)
{
userInput = Console.ReadLine();
delimiters.Add(userInput);
i++;
}
foreach (string delimiter in delimiters)
{
foreach (string s in data)
{
//This split is not working
//string output[] = s.Split(delimiter);
}
}
So, if the user enters "|c" and "~", the expected output is: "Car", "Blue,Mazda", "Model|m3"
If the user enters "|c", "|m", and ",", then the expected output will be: "Car", "Blue", "Mazda~Model", "3"

Add the user input into the List delimiters.
string data = "Car|cBlue,Mazda~Model|m3";
List<string> delimiters = new List<string>();
delimiters.Add("|c");//Change this to user input
delimiters.Add("|m");//change this to user input
string[] parts = data.Split(delimiters.ToArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (string item in parts)
{
Console.WriteLine(item);
}

String.Split has an overload that does exactly that - you just need to convert your List<string> to a string[] :
string input = "Car|cBlue,Mazda~Model|m3";
List<string> delims = new List<string> {"|c", "~"};
string[] out1 = input.Split(delims.ToArray(),StringSplitOptions.None);
//output:
// Car
// Blue,Mazda
// Model|m3
delims = new List<string> {"|c", "|m", ","};
string[] out2 = input.Split(delims.ToArray(),StringSplitOptions.None).Dump();
//output:
// Car
// Blue
// Mazda~Model
// 3

You can use SelectMany to get the result from all the data strings and ToArray() method to create an array from delimiters
var result = data.SelectMany(s => s.Split(delimiters.ToArray(), StringSplitOptions.None));

Related

Matching 2 strings in C#

I have 2 strings. These 2 strings can differ in size. I want to look at these 2 strings finding matching sequences. Once I find a change I want to print that word in Capital and then continue on in my string until I find another change and so on. I'm not sure how I would go about this I tried looking at words as a whole but I'm having issues with that. Basically I will have 2 string something like this string one="This is a new value" and string two= "This This is a new also brand value". I want go though each string from the start and find the matching sequences e.g. "This is" stop at string realise it has changed as string was added change it to upper case and then carry on. Expected output ="THIS this is a new ALSO BRAND value "
Some code I was trying. I don't think this is the right approach.
static void Main(string[] args)
{
string one = "This is a new value";
string two = "This This is a new also brand value";
var coll = two.Split(' ').Select(p => one.Contains(p) ? p : p.ToUpperInvariant());
Console.WriteLine(string.Join(" ", coll));
Console.ReadKey();
}
Is this what you're looking for? The description isn't fantastic, but judging by the answers this seems to be in the same ballpark, and it uses LINQ for less code and complication.
class Program
{
static void Main(string[] args)
{
string one = "This is text one";
string two = "This is string text two not string one";
var coll = two.Split(' ').Select(p => one.Contains(p) ? p : p.ToUpperInvariant());
Console.WriteLine(string.Join(" ", coll)); // This is STRING text TWO NOT STRING one
Console.ReadKey();
}
}
You can break this out to a separate method and pass your variables in as parameters.
You can convert string to char array and compare chars one by one. You can use the following code i guess.
string one = "this is string one";
string two = "this is string one or two";
char[] oneChar = one.ToCharArray();
char[] twoChar = two.ToCharArray();
int index = 0;
List<char> Diff = new List<char>();
if (oneChar.Length > twoChar.Length)
{
foreach (char item in twoChar)
{
if (item != oneChar[index])
Diff.Add(item);
index++;
}
for (int i = index; i < oneChar.Length; i++)
{
Diff.Add(oneChar[i]);
}
}
else if (oneChar.Length < twoChar.Length)
{
foreach (char item in oneChar)
{
if (item != twoChar[index])
Diff.Add(twoChar[index]);
index++;
}
for (int i = index; i < twoChar.Length; i++)
{
Diff.Add(twoChar[i]);
}
}
else//equal length
{
foreach (char item in twoChar)
{
if (item != oneChar[index])
Diff.Add(item);
}
}
Console.WriteLine(Diff.ToArray());//" or two"
Is that what you need? (Updated)
var value1 = "This is a new Value";
var value2 = "This is also a new value";
var separators = new[] { " " };
var value1Split = value1.Split(separators, StringSplitOptions.None);
var value2Split = value2.Split(separators, StringSplitOptions.None);
var result = new List<string>();
var i = 0;
var j = 0;
while (i < value1Split.Length && j < value2Split.Length)
{
if (value1Split[i].Equals(value2Split[j], StringComparison.OrdinalIgnoreCase))
{
result.Add(value2Split[j]);
i++;
j++;
}
else
{
result.Add(value2Split[j].ToUpper());
j++;
}
}
Console.WriteLine(string.Join(" ", result));
Console.ReadKey();
Note that if for value1="This is a new Value" and value2="This is also a new value" output should be "This is ALSO a new value" than for value1="This is text one" and value2="This is string text two not string one" output will be "This is STRING text TWO NOT STRING one", not "This is STRING TEXT TWO NOT STRING ONE" as you mentioned before.

Split string by List

Split string by List:
I have SplitColl with delimeters:
xx
yy
..
..
And string like this:
strxx
When i try to split string:
var formattedText = "strxx";
var lst = new List<String>();
lst.Add("xx");
lst.Add("yy");
var arr = formattedText.Split(lst.ToArray(), 10, StringSplitOptions.RemoveEmptyEntries);
I have "str" result;
But how to skip this result? I want to get empty array in this case (when delim is a part of a word).
I expect, that when formattedText="str xx", result is str.
EDIT:
I have a many delimeters of address: such as street,city,town,etc.
And i try to get strings like: city DC-> DC.
But, when i get a word like:cityacdc-> i get acdc, but it not a name of a city.
It seems that you are not using your keywords really as delimiters but as search criterion. In this case you could use RegEx to search for each pattern. Here is an example program to illustrate this procedure:
static void Main(string[] args)
{
List<string> delim = new List<string> { "city", "street" };
string formattedText = "strxx street BakerStreet cityxx city London";
List<string> results = new List<string>();
foreach (var del in delim)
{
string s = Regex.Match(formattedText, del + #"\s\w+\b").Value;
if (!String.IsNullOrWhiteSpace(s))
{
results.Add(s.Split(' ')[1]);
}
}
Console.WriteLine(String.Join("\n", results));
Console.ReadKey();
}
This would handle this case:
And I try to get strings like: city DC --> DC
to handle the case where you want to find the word in front of your keyword:
I expect, that when formattedText="str xx", result is str
just switch the places of the matching criterion:
string s = Regex.Match(formattedText, #"\b\w+\s"+ del).Value;
and take the first element at the split
results.Add(s.Split(' ')[0]);
Give this a try, basically what I'm doing is first I remove any leading or tailing delimiters (only if they are separated with a space) from the formattedText string. Then using the remaining string I split it for each delimiter if it has spaces on both sides.
//usage
var result = FormatText(formattedText, delimiterlst);
//code
static string[] FormatText(string input, List<string> delimiters)
{
delimiters.ForEach(d => {
TrimInput(ref input, "start", d.ToCharArray());
TrimInput(ref input, "end", d.ToCharArray());
});
return input.Split(delimiters.Select(d => $" {d} ").ToArray(), 10, StringSplitOptions.RemoveEmptyEntries);
}
static void TrimInput(ref string input, string pos, char[] delimiter)
{
//backup
string temp = input;
//trim
input = (pos == "start") ? input.TrimStart(delimiter) : input.TrimEnd(delimiter);
string trimmed = (pos == "start") ? input.TrimStart() : input.TrimEnd();
//update string
input = (input != trimmed) ? trimmed : temp;
}

Check if a string contains a list of substrings and save the matching ones

This is my situation: I have a string representing a text
string myText = "Text to analyze for words, bar, foo";
And a list of words to search for in it
List<string> words = new List<string> {"foo", "bar", "xyz"};
I'd want to know the most efficient method, if exists, to get the list of the words contained in the text, something like that:
List<string> matches = myText.findWords(words)
There is no special analysis in this query except you have to use Contains method. So you may try this:
string myText = "Text to analyze for words, bar, foo";
List<string> words = new List<string> { "foo", "bar", "xyz" };
var result = words.Where(i => myText.Contains(i)).ToList();
//result: bar, foo
You can use a HashSet<string> and intersect both collections:
string myText = "Text to analyze for words, bar, foo";
string[] splitWords = myText.Split(' ', ',');
HashSet<string> hashWords = new HashSet<string>(splitWords,
StringComparer.OrdinalIgnoreCase);
HashSet<string> words = new HashSet<string>(new[] { "foo", "bar" },
StringComparer.OrdinalIgnoreCase);
hashWords.IntersectWith(words);
A Regex solution
var words = new string[]{"Lucy", "play", "soccer"};
var text = "Lucy loves going to the field and play soccer with her friend";
var match = new Regex(String.Join("|",words)).Match(text);
var result = new List<string>();
while (match.Success) {
result.Add(match.Value);
match = match.NextMatch();
}
//Result ["Lucy", "play", "soccer"]
Playing off of the idea that you want to be able to use myText.findWords(words), you can make an extension method to the String class to do just what you want.
public static class StringExtentions
{
public static List<string> findWords(this string str, List<string> words)
{
return words.Where(str.Contains).ToList();
}
}
Usage:
string myText = "Text to analyze for words, bar, foo";
List<string> words = new List<string> { "foo", "bar", "xyz" };
List<string> matches = myText.findWords(words);
Console.WriteLine(String.Join(", ", matches.ToArray()));
Console.ReadLine();
Results:
foo, bar
Here's a simple solution that accounts for whitespace and punctuation:
static void Main(string[] args)
{
string sentence = "Text to analyze for words, bar, foo";
var words = Regex.Split(sentence, #"\W+");
var searchWords = new List<string> { "foo", "bar", "xyz" };
var foundWords = words.Intersect(searchWords);
foreach (var item in foundWords)
{
Console.WriteLine(item);
}
Console.ReadLine();
}

Extracting variable number of token pairs from a string to a pair of arrays

Here is the requirement.
I have a string with multiple entries of a particular format. Example below
string SourceString = "<parameter1(value1)><parameter2(value2)><parameter3(value3)>";
I want to get the ouput as below
string[] parameters = {"parameter1","parameter2","parameter3"};
string[] values = {"value1","value2","value3"};
The above string is just an example with 3 pairs of parameter values. The string may have 40, 52, 75 - any number of entries (less than 100 in one string).
Like this I have multiple strings in an array. I want to do this operation for all the strings in the array.
Could any one please advice how to achieve this? I'm a novice in c#.
Is using regex a better solution or is there any other method?
Any help is much appreciated.
If you didn't like RegEx's you could do something like this:
class Program
{
static void Main()
{
string input = "<parameter1(value1)>< parameter2(value2)>";
string[] Items = input.Replace("<", "").Split('>');
List<string> parameters = new List<string>();
List<string> values = new List<string>();
foreach (var item in Items)
{
if (item != "")
{
KeyValuePair<string, string> kvp = GetInnerItem(item);
parameters.Add(kvp.Key);
values.Add(kvp.Value);
}
}
// if you really wanted your results in arrays
//
string[] parametersArray = parameters.ToArray();
string[] valuesArray = values.ToArray();
}
public static KeyValuePair<string, string> GetInnerItem(string item)
{
//expects parameter1(value1)
string[] s = item.Replace(")", "").Split('(');
return new KeyValuePair<string, string>(s[0].Trim(), s[1].Trim());
}
}
It might be a wee bit quicker than the RegEx method but certainly not as flexible.
You could use RegEx class in combination with an expression to parse the string and generate these arrays by looping through MatchCollections.
http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx
This does it:
string[] parameters = null;
string[] values = null;
// string SourceString = "<parameter1(value1)><parameter2(value2)><parameter3(value3)>";
string SourceString = #"<QUEUE(C2.BRH.ARB_INVPUSH01)><CHANNEL(C2.MONITORING_CHANNEL)><QMGR(C2.MASTER_NA‌​ME.TRACKER)>";
// string regExpression = #"<([^\(]+)[\(]([\w]+)";
string regExpression = #"<([^\(]+)[\(]([^\)]+)";
Regex r = new Regex(regExpression);
MatchCollection collection = r.Matches(SourceString);
parameters = new string[collection.Count];
values = new string[collection.Count];
for (int i = 0; i < collection.Count; i++)
{
Match m = collection[i];
parameters[i] = m.Groups[1].Value;
values[i] = m.Groups[2].Value;
}

C# String Pattern Matching

I have 2 lists of strings in C# showing the players who have joined and left a particular game. I'm trying to attempt to determine who is still in the game by matching both lists and eliminating the entries of those who have left the game. Please suggest a easy and pain free algorithm to go about doing this. My current code is as follows
string input = inputTextBox.Text;
string[] lines = input.Split(new string[] {"\r\n", "\n"}, StringSplitOptions.None);
List<string> filteredinput = new List<string>();
List<string> joinedlog = new List<string>();
List<string> leftlog = new List<string>();
for (int i = 0; i<lines.Length; i++)
{
if (lines[i].Contains("your game!"))
filteredinput.Add(lines[i]);
}
for (int i =0; i<filteredinput.Count; i++)
{
if (filteredinput[i].Contains("joined"))
joinedlog.Add(filteredinput[i]);
else if (filteredinput[i].Contains("left"))
leftlog.Add(filteredinput[i]);
}
Here is some sample input :
{SheIsSoScrewed}[Ping:|] has joined your game!.
{AngeLa_Yoyo}[Ping:X] has joined your game!.
{SheIsSoScrewed} has left your game!(4).
Are you asking how to get your two lists, or how to find the current players after you've already got the two lists?
The second part can be done with Linq....
List<string> joinedGame;
List<string> leftGame;
List<string> currentInGame
= joinedGame.Where(x => !leftGame.Contains(x)).ToList();
EDIT In response to your comment, having read your question again then obviously the above won't work because you are building your lists in a weird way.
You are storing the whole string in the list, e.g. user_1 has left the game, what you should probably be doing is just storing the user name. If you correct this then the above code does exactly what you want.
A full example:
var input = new List<string>()
{
"user_1 has joined the game",
"user_2 has joined the game",
"user_1 has left the game",
"user_3 has joined the game"
};
var joined = new List<string>();
var left = new List<string>();
foreach(string s in input)
{
var idx = s.IndexOf(" has joined the game");
if (idx > -1)
{
joined.Add(s.Substring(0, idx));
continue;
}
idx = s.IndexOf(" has left the game");
if (idx > -1)
{
left.Add(s.Substring(0, idx));
}
}
var current = joined.Where(x => !left.Contains(x)).ToList();
foreach(string user in current)
{
Console.WriteLine(user + " is still in the game");
}
Intersect and Except are your friends.
Also, if this is the sole purpose of the lists, consider using something like HashSet instead.
How about using List.Find() ?
Link 1 here
Link 2 here
use linq and regex:
var join=new Regex("joined.*?your game");
var joinLog = (from l in lines where join.IsMatch(join) select l).ToList();
var left=new Regex("left.*?your game");
var leftLog = (from l in lines where left.IsMatch(join) select l).ToList();
First you need to extract the player names so you can calculate the difference:
var join=new Regex("{(.*)}[.*joined.*?your game");
var joinedNames = filteredinput.Select(l => join.Match(l)).Where(m => m.Success).Select(m => m.Groups[1]).Distinct();
var left=new Regex("{(.*)}[.*left.*?your game");
var leftNames = filteredinput.Select(l => left.Match(l)).Where(m => m.Success).Select(m => m.Groups[1]).Distinct();
Now calculate the difference:
var playersStillInGame = joinedNames.Except(leftNames);
string input = inputTextBox.Text;
string[] lines = input.Split(new string[] {"\r\n", "\n"}, StringSplitOptions.None);
Regex joinedLeft = new Regex(#"\{([^{}]*)}.*? has (joined|left) your game!");
HashSet<string> inGame = new HashSet<string>();
foreach (string line in lines)
{
Match match = joinedLeft.Match(line);
if (!match.Success)
continue;
string name = match.Groups[1].Value;
string inOrOut = match.Groups[2].Value;
if (inOrOut == "joined")
inGame.Add(name);
else
inGame.Remove(name);
}

Categories