I've the following string that I get from a method. I would like to parse it and make pairs. The order of input string will not change.
INPUT:
ku=value1,ku=value2,ku=value3,ku=value4,ku=value5,lu=value6,lu=value7,lu=value8,lu=value9
OUTPUT
Name value1
Title value2
School value3
.
.
.
Age value9
I think I can read through the string and assign value to the left hand side as I go and so on. However, I am very new to C#.
Use string.Split and split imput string to list key-value pair then split each pair to key and value. Tahts all.
You can do something like this:
void Main()
{
string str = "ku=value1,ku=value2,ku=value3,ku=value4,ku=value5,lu=value6,lu=value7,lu=value8,lu=value9";
var tempStr = str.Split(',');
var result = new List<KeyValue>();
foreach(var val in tempStr)
{
var temp = val.Split('=');
var kv = new KeyValue();
kv.Name = temp[0];
kv.Value = temp[1];
result.Add(kv);
}
}
public class KeyValue
{
public string Name {get;set;}
public string Value{get;set;}
}
If you don't need the first part you can do this using String split as follow
Split String on , using String.Split method creating sequence of string {"ku=value1","ku=value2",...}
Use Linq's Select method to apply an additional transformation
Use Split again on each item on the '=' character
Select the item to the right of the '=', at index 1 of the newly split item
Loop through everything and print your results
Here's the code
var target = "ku=value1,ku=value2,ku=value3,ku=value4,ku=value5,lu=value6,lu=value7,lu=value8,lu=value9";
var split = target.Split(',').Select(a=>a.Split('=')[1]).ToArray();
var names = new[]{"Name","Title","School",...,"Age"};
for(int i=0;i<split.Length;i++)
{
Console.WriteLine(names[i]+"\t"+split[i]);
}
If you want to find out more about how to use these methods you can look at the MSDN documentation for them :
String.Split(char[]) Method
Enumerable.Select Method
I suggest to try this way. Split() plus regular expression
string inputString = "ku=value1,ku=value2,ku=value3,ku=value4,ku=value5,lu=value6,lu=value7,lu=value8,lu=value9";
string pattern = "(.*)=(.*)";
foreach(var pair in inputString.Split(','))
{
var match = Regex.Match(pair,pattern);
Console.WriteLine(string.Format("{0} {1}",match.Groups[1].Value, match.Groups[2].Value));
}
Related
I'm trying to remove an element/item/entry from a split string.
Let's say I got the string [string_] as follows:
string string_ = "one;two;three;four;five;six";
Then I split this string to get each, let's say, item:
string[] item = (string_.Split(";"));
I have no informations other than from variables. Depending on the user choice, I can get an item value and index.
Let's say that for this example, the user chose "four" which is the index "3".
How can I make my string look like the index 3 have been deleted, as string_ would be equal to the following:
"one;two;three;five;six"
I've tried multiple things and it seems like the only solution is to go through a char method.
Is that true or did I miss something?
EDIT to suggested already_posted_answer :
Not quite the same question as my ITEM could be placed anywhere in my splitted string depending on the user selection.
First of all you need to write better variable names, string_ is a horrible name. Even something like "input" is way better.
string input = "one;two;three;four;five;six";
Next, you are on the right track by using Split(). This will return an array of string:
string[] splitInput = input.Split(";");
The resulting string array will look like this:
//string[0] = one
//string[1] = two
//string[2] = three
//string[3] = four
//string[4] = five
//string[5] = six
Removing with known index
If you want to remove a specific element from the array, you could make the result of Split() a List<T> by using ToList() instead and utilize the RemoveAt() method of the resulting List<T>:
List<string> splitList = input.Split(';').ToList();
splitList.RemoveAt(3);
//Re-create the string
string outputString = string.Join(";", splitList);
//output is: "one;two;three;five;six"
Remove all strings that match an input
If you need to remove items from the list without knowing their index but knowing the actual string, you can use LINQ's Where() to filter out the matching items:
//Get the input from the user somehow
string userInput = Console.ReadLine();
IEnumerable<string> filteredList = input.Split(';')
.Where(x => string.Compare(x, userInput, true) != 0);
//Re-create the string
string outputString = string.Join(";", filteredList);
I made a fiddle to demonstrate both methods here
You can convert an array of string to list by following:
var list = new List<string>(item);
Once the list is created, you can easily remove an element:
var index = list.IndexOf("four");
list.RemoveAt(index);
Join the string back:
var result = String.Join(";", list.ToArray());
Result:
You can convert your string array into a List<string>, and since you have the index of the item to be removed, you can remove the item using RemoveAt, then join the items back into one string.
Here's a complete console application example:
static void Main(string[] args)
{
string string_ = "one;two;three;four;five;six";
string[] items = (string_.Split(';'));
Console.WriteLine("Please select an item to remove:");
for (int i = 0;i<items.Length;i++)
{
Console.WriteLine(string.Format("{0}- {1}", (i + 1).ToString(), items[i]));
}
int num = 0;
int.TryParse(Console.ReadLine(), out num);
if (num > 0 && num <= items.Length)
{
List<string> itemsList = items.ToList();
itemsList.RemoveAt(num - 1);
string newString = string.Join(";", itemsList);
Console.WriteLine(string.Format("The new string is: {0}", newString));
}
else
{
Console.WriteLine("Invalid number!");
}
Console.ReadLine();
}
Hope that helps.
We can employ LINQ.
Initial plan is to split the string, then create a union of two enumerables: before and after the item. Something like this:
// preconditions
const int idx = 3;
string string_ = "one;two;three;four;five;six";
// actual transformation
string[] item = (string_.Split(';'));
var iterator = item.Take(idx).Concat(item.Skip(idx + 1));
// output the results
var result = string.Join(";", iterator);
Console.Write(result);
Would this work for you?
If you create a new string like this, then replace the value of string_ with the value of the new string.
string string_ = "one;two;three;four;five;six";
string newstring = string_.Replace("four", "");
string_ = newstring.Replace(";;", ";");
I'm searching for a solution to this case:
I have a Method inside a DLL that receive a string that contains some words as "placeholders/parameters" that will be replaced by a result of another specific method (inside dll too)
Too simplificate: It's a query string received as an argument to be on a method inside a DLL, where X word that matchs a specifc case, will be replaced.
My method receive a string that could be like this:
(on .exe app)
string str = "INSERT INTO mydb.mytable (id_field, description, complex_number) VALUES ('#GEN_COMPLEX_ID#','A complex solution', '#GEN_COMPLEX_ID#');"
MyDLLClass.MyMethod(str);
So, the problem is: if i replace the #GEN_COMPLEX_ID# on this string, wanting that a different should be on each match, it not will happen because the replaced executes the function in a single shot (not step by step). So, i wanna help to implement this: a step by step replace of any text (like Find some word, replace, than next ... replace ... next... etc.
Could you help me?
Thanks!
This works pretty well for me:
string yourOriginalString = "ab cd ab cd ab cd";
string pattern = "ab";
string yourNewDescription = "123";
int startingPositionOffset = 0;
int yourOriginalStringLength = yourOriginalString.Length;
MatchCollection match = Regex.Matches(yourOriginalString, pattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
foreach (Match m in match)
{
yourOriginalString = yourOriginalString.Substring(0, m.Index+startingPositionOffset) + yourNewDescription + yourOriginalString.Substring(m.Index + startingPositionOffset+ m.Length);
startingPositionOffset = yourOriginalString.Length - yourOriginalStringLength;
}
If what you're asking is how to replace each placeholder with a different value, you can do it using the Regex.Replace overload which accepts a MatchEvaluator delegate, and executes it for each match:
// conceptually, something like this (note that it's not checking if there are
// enough values in the replacementValues array)
static string ReplaceMultiple(
string input, string placeholder, IEnumerable<string> replacementValues)
{
var enumerator = replacementValues.GetEnumerator();
return Regex.Replace(input, placeholder,
m => { enumerator.MoveNext(); return enumerator.Current; });
}
This is, of course, presuming that all placeholders look the same.
Pseudo-code
var split = source.Split(placeholder); // create array of items without placeholders
var result = split[0]; // copy first item
for(int i = 1; i < result.Length; i++)
{
bool replace = ... // ask user
result += replace ? replacement : placeholder; // to put replacement or not to put
result += split[i]; // copy next item
}
you should use the split method like this
string [] placeholder = {"#Placeholder#"} ;
string[] request = cd.Split(placeholder, StringSplitOptions.RemoveEmptyEntries);
StringBuilder requetBuilding = new StringBuilder();
requetBuilding.Append(request[0]);
int index = 1;
requetBuilding.Append("Your place holder replacement");
requetBuilding.Append(request[index]);
index++; //next replacement
// requetBuilding.Append("Your next place holder replacement");
// requetBuilding.Append(request[index]);
Suppose I am given a following text (in a string array)
engine.STEPCONTROL("00000000","02000001","02000043","02000002","02000007","02000003","02000008","02000004","02000009","02000005","02000010","02000006","02000011");
if("02000001" == 1){
dimlevel = 1;
}
if("02000001" == 2){
dimlevel = 3;
}
I'd like to extract the strings that's in between the quotation mark and put it in a separate string array. For instance, string[] extracted would contain 00000000, 02000001, 02000043....
What is the best approach for this? Should I use regular expression to somehow parse those lines and split it?
Personally I don't think a regular expression is necessary. If you can be sure that the input string is always as described and will not have any escape sequences in it or vary in any other way, you could use something like this:
public static string[] ExtractNumbers(string[] originalCodeLines)
{
List<string> extractedNumbers = new List<string>();
string[] codeLineElements = originalCodeLines[0].Split('"');
foreach (string element in codeLineElements)
{
int result = 0;
if (int.TryParse(element, out result))
{
extractedNumbers.Add(element);
}
}
return extractedNumbers.ToArray();
}
It's not necessarily the most efficient implementation but it's quite short and its easy to see what it does.
that could be
string data = "\"00000000\",\"02000001\",\"02000043\"".Replace("\"", string.Empty);
string[] myArray = data.Split(',');
or in 1 line
string[] data = "\"00000000\",\"02000001\",\"02000043\"".Replace("\"", string.Empty).Split(',');
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];
}
}
Need some ideas how to solve this problem.
I have a template file what describes the line in the text file. For example:
Template
[%f1%]|[%f2%]|[%f3%]"[%f4%]"[%f5%]"[%f6%]
Text file
1234|1234567|123"12345"12"123456
Now i need to read in the fields from the text file. In the template file fields are described with [%some name%]. Allso in the template file there is set what the field separators are, in this example here there are | and ". The lenght of the fields can change through different files but the separators will stay the same. What would be the best way to read in the template and by template read in the text file?
EDIT: Text file has multiple rows, like this:
1234|1234567|123"12345"12"123456"\r\n
1234|field|123"12345"12"asdasd"\r\n
123sd|1234567|123"asdsadf"12"123456"\r\n
45gg|somedata|123"12345"12"somefield"\r\n
EDIT2: Ok, lets make it even harder. Some fields can contain binary data and i know the starting and end position of the binary data field. I should be able to mark those fields in the template and then the parser will know that this field is binary. How to solve this problem?
I would create a regex based on the template and then parse the text file using that:
class Parser
{
private static readonly Regex TemplateRegex =
new Regex(#"\[%(?<field>[^]]+)%\](?<delim>[^[]+)?");
readonly List<string> m_fields = new List<string>();
private readonly Regex m_textRegex;
public Parser(string template)
{
var textRegexString = '^' + TemplateRegex.Replace(template, Evaluator) + '$';
m_textRegex = new Regex(textRegexString);
}
string Evaluator(Match match)
{
// add field name to collection and create regex for the field
var fieldName = match.Groups["field"].Value;
m_fields.Add(fieldName);
string result = "(.*?)";
// add delimiter to the regex, if it exists
// TODO: check, that only last field doesn't have delimiter
var delimGroup = match.Groups["delim"];
if (delimGroup.Success)
{
string delim = delimGroup.Value;
result += Regex.Escape(delim);
}
return result;
}
public IDictionary<string, string> Parse(string text)
{
var match = m_textRegex.Match(text);
var groups = match.Groups;
var result = new Dictionary<string, string>(m_fields.Count);
for (int i = 0; i < m_fields.Count; i++)
result.Add(m_fields[i], groups[i + 1].Value);
return result;
}
}
You can parse the template using regular expressions. An expression like this will match each field definition and separator:
Match m = Regex.Match(template, #"^(\[%(?<name>.+?)%\](?<separator>.)?)+$")
The match will contain two named groups for (name and separator), each of which will contain a number of captures for each time they matched in the input string. In your example, the separator group would have one less capture than the name group.
You can then iterate over the captures, and use the results to extract the fields from the input string and store the values, like this:
if( m.Success )
{
Group name = m.Groups["name"];
Group separator = m.Groups["separator"];
int index = 0;
Dictionary<string, string> fields = new Dictionary<string, string>();
for( int x = 0; x < name.Captures.Count; ++x )
{
int separatorIndex = input.Length;
if( x < separator.Captures.Count )
separatorIndex = input.IndexOf(separator.Captures[x].Value, index);
fields.Add(name.Captures[x].Value, input.Substring(index, separatorIndex - index));
index = separatorIndex + 1;
}
// Do something with results.
}
Obviously in a real program you'd have to account for invalid input and such, which I didn't do here.
I would do this with a few lines of code. Loop through your template row, grabbing all text between "[" as the variable name and everything else as a terminator. Read all the text to the terminal, assign it to the variable name, repeat.
1- Use API for that sscanf(line, format, __arglist) check here
2- Use string split Like:
public IEnumerable<int> GetDataFromLines(string[] lines)
{
//handle the output data
List<int> data = new List<int>();
foreach (string line in lines)
{
string[] seperators = new string[] { "|", "\"" };
string[] results = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
foreach (string result in results)
{
data.Add(int.Parse(result));
}
}
return data;
}
Test it with line:
line = "1234|1234567|123\"12345\"12\"123456";
string[] lines = new string[] { line };
GetDataFromLines(lines);
//output list items are:
1234
1234567
123
12345
12
123456