Using Regex Array with String Array - c#

I'm trying to make a program where a user can input an array of serial numbers and have each corresponding product show up.
Suppose I know that Product A always starts with "C02", Product B always ends in "X02", and Product C always contains "A1700". Then if the user input was "C02HGV32,N93XA1700D,J3429X02", it would return "C02HGV32: Product A; N93XA1700D: Product C; J3429X02: Product B".
How would I get an array of Regex expressions to compare against the array of strings? Here's what I have:
using System.Text.RegularExpressions;
public class ReturnProduct{
public Regex[] compareAgainst = new Regex[3]{#"[C02]*",#"*[X02]",#"*[A1700]*"}; //Clearly not the right way, but not sure how else to do it
...
public string getTheProduct(string input){
string[] compareString = input.Split(",");
for (int a = 0; a < compareString.Length; a++){
for (int b = 0; b < compareAgainst.Length; b++){
//Do something Regex-y with compareString[a] and compareAgainst[b]
}
}

If the requirements of these codes are so simple you can use String.Contains, String.StartsWith and String.EndsWith. You can create a Dictionary to hold product names and functions to check if a given string has the pattern for a product.
var dict = new Dictionary<string, Predicate<string>>
{
["Product A"] = s => s.StartsWith("C02"),
["Product B"] = s => s.EndsWith("X02"),
["Product C"] = s => s.Contains("A1700")
};
string GetProductName(string serialNum)
{
foreach(var keyVal in dict)
{
if(keyVal.Value(serialNum))
return keyVal.Key;
}
return "No product name found";
}
List<(string, string)> GetProductNames(string str)
{
var productCodes = str.Split(',');
var productNames = new List<(string, string)>(); // list of tuples (string, string)
foreach(var serialNum in productCodes)
{
productNames.Add((serialNum, GetProductName(serialNum)));
}
return productNames;
}
Usage:
var userString = "C02HGV32,N93XA1700D,J3429X02";
List<(string serialNum, string name)> productNames = GetProductNames(userString);
foreach(var tuple in productNames)
{
Console.WriteLine($"{tuple.serialNum} : {tuple.name}");
}
If you specifically want to use Regex, you can use the following patterns:
var regexDict = new Dictionary<string, Regex>
{
["Product A"] = new Regex("^C02"), //'^' means beginning of string
["Product B"] = new Regex("X02$"), //'$' means end of string
["Product C"] = new Regex("A1700") //given string anywhere
};
string GetProductName(string serialNum)
{
foreach(var keyVal in regexDict)
{
if(keyVal.Value.IsMatch(serialNum))
return keyVal.Key;
}
return "No product name found";
}
List<(string, string)> GetProductNames(string str)
{
var productCodes = str.Split(',');
var productNames = new List<string>();
foreach(var serialNum in productCodes)
{
productNames.Add((serialNum, GetProductName(serialNum)));
}
return productNames;
}

Define a class for your products:
public class Product
{
public string Name { get; set; }
public Regex Expr { get; set; }
}
then create an array with all your regexes:
var regexes = new[]
{
new Product
{
Name = "Product A",
Expr = new Regex("^C02")
},
new Product
{
Name = "Product B",
Expr = new Regex("X02$")
},
new Product
{
Name = "Product C",
Expr = new Regex("A1700")
}
};
now you can use LINQ query:
var input = "C02HGV32,N93XA1700D,J3429X02";
var result = string.Join("; ",
input.Split(',')
.Select(s => new {regexes.FirstOrDefault(p => p.Expr.IsMatch(s))?.Name, Value = s})
.Select(x => $"{x.Value}: {x.Name}"));
result would be
C02HGV32: Product A; N93XA1700D: Product C; J3429X02: Product B

Regex syntax:
"^C02.*" - Starts with C02 followed by any number of characters including 0 characters.
"^.*X02" - Starts with any number of characters including 0 characters and ends with X02.
"^.A1700.*" - Starts and ends with any number of characters, and contains A1700 somewhere.
public static void GetTheProduct(string input, List<Regex> regList)
{
List<string> compareString = input.Split(new char[] { ',' }).ToList();
foreach (string item in compareString)
{
if (regList[0].Match(item).Success)
Console.WriteLine("{0} : {1}", item, "Product A");
else if (regList[1].Match(item).Success)
Console.WriteLine("{0} : {1}", item, "Product B");
else if (regList[2].Match(item).Success)
Console.WriteLine("{0} : {1}", item, "Product C");
}
}
static void Main(string[] args)
{
List<Regex> regexList = new List<Regex>() { new Regex("^C02.*"), new Regex("^.*X02"), new Regex("^.*A1700.*") };
GetTheProduct("C02HGV32,N93XA1700D,J3429X02", regexList);
Console.ReadLine();
}
You could also generalize the method and avoid hardcoding Product names.
Like so:
public static void GetTheProduct(string input, Dictionary<string, Regex> regDictionary)
{
List<string> compareString = input.Split(new char[] { ',' }).ToList();
foreach (string item in compareString)
{
string key = regDictionary.First(x => x.Value.IsMatch(item)).Key;
Console.WriteLine("{0} : {1}", item, key);
}
}
static void Main(string[] args)
{
Dictionary<string, Regex> regDictionary = new Dictionary<string, Regex>();
regDictionary.Add("Product A", new Regex("^C02.*"));
regDictionary.Add("Product B", new Regex("^.*X02"));
regDictionary.Add("Product C", new Regex("^.*A1700.*"));
GetTheProduct("C02HGV32,N93XA1700D,J3429X02", regDictionary);
Console.ReadLine();
}

Related

creating array of bad names to check and replace in c#

I'm looking to create a method that loops through an list and replaces with matched values with a new value. I have something working below but it really doesnt follow the DRY principal and looks ugly.
How could I create a dictionary of value pairs that would hold my data of values to match and replace?
var match = acreData.data;
foreach(var i in match)
{
if (i.county_name == "DE KALB")
{
i.county_name = "DEKALB";
}
if (i.county_name == "DU PAGE")
{
i.county_name = "DUPAGE";
}
}
In your question, you can try to use linq and Replace to make it.
var match = acreData.data.ToList();
match.ForEach(x =>
x.county_name = x.county_name.Replace(" ", "")
);
or you can try to create a mapper table to let your data mapper with your value. as #user2864740 say.
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("DE KALB", "DEKALB");
dict.Add("DU PAGE", "DUPAGE");
var match = acreData.data;
string val = string.Empty;
foreach (var i in match)
{
if (dict.TryGetValue(i.county_name, out val))
i.county_name = val;
}
If this were my problem and it is possible a county could have more than one common misspelling I would create a class to hold the correct name and the common misspellings. The you could easily determine if the misspelling exists and correct if. Something like this:
public class County
{
public string CountyName { get; set; }
public List<string> CommonMisspellings { get; set; }
public County()
{
CommonMisspellings = new List<string>();
}
}
Usage:
//most likely populate from db
var counties = new List<County>();
var dekalb = new County { CountyName = "DEKALB" };
dekalb.CommonMisspellings.Add("DE KALB");
dekalb.CommonMisspellings.Add("DE_KALB");
var test = "DE KALB";
if (counties.Any(c => c.CommonMisspellings.Contains(test)))
{
test = counties.First(c => c.CommonMisspellings.Contains(test)).CountyName;
}
If you are simply replacing all words in a list containing space without space, then can use below:
var newList = match.ConvertAll(word => word.Replace(" ", ""));
ConvertAll returns a new list.
Also, I suggest not to use variable names like i, j, k etc..but use temp etc.
Sample code below:
var oldList = new List<string> {"DE KALB", "DE PAGE"};
var newList = oldList.ConvertAll(word => word.Replace(" ", ""));
We can try removing all the characters but letters and apostroph (Cote d'Ivoire has it)
...
i.country_name = String.Concat(i.country_name
.Where(c => char.IsLetter(c) || c == '\''));
...
I made a comment under answer of #Kevin and it seems it needs further explanation. Sequential searching in list does not scale well and unfortunately for Kevin, that is not my opinion, asymptotic computational complexity is math. While searching in dictionary is more or less O(1), searching in list is O(n). To show a practical impact for solution with 100 countries with 100 misspellings each, lets make a test
public class Country
{
public string CountryName { get; set; }
public List<string> CommonMisspellings { get; set; }
public Country()
{
CommonMisspellings = new List<string>();
}
}
static void Main()
{
var counties = new List<Country>();
Dictionary<string, string> dict = new Dictionary<string, string>();
Random rnd = new Random();
List<string> allCountryNames = new List<string>();
List<string> allMissNames = new List<string>();
for (int state = 0; state < 100; ++state)
{
string countryName = state.ToString() + rnd.NextDouble();
allCountryNames.Add(countryName);
var country = new Country { CountryName = countryName };
counties.Add(country);
for (int miss = 0; miss < 100; ++miss)
{
string missname = countryName + miss;
allMissNames.Add(missname);
country.CommonMisspellings.Add(missname);
dict.Add(missname, countryName);
}
}
List<string> testNames = new List<string>();
for (int i = 0; i < 100000; ++i)
{
if (rnd.Next(20) == 1)
{
testNames.Add(allMissNames[rnd.Next(allMissNames.Count)]);
}
else
{
testNames.Add(allCountryNames[rnd.Next(allCountryNames.Count)]);
}
}
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
List<string> repairs = new List<string>();
foreach (var test in testNames)
{
if (counties.Any(c => c.CommonMisspellings.Contains(test)))
{
repairs.Add(counties.First(c => c.CommonMisspellings.Contains(test)).CountryName);
}
}
st.Stop();
Console.WriteLine("List approach: " + st.ElapsedMilliseconds.ToString() + "ms");
st = new System.Diagnostics.Stopwatch();
st.Start();
List<string> repairsDict = new List<string>();
foreach (var test in testNames)
{
if (dict.TryGetValue(test, out var val))
{
repairsDict.Add(val);
}
}
st.Stop();
Console.WriteLine("Dict approach: " + st.ElapsedMilliseconds.ToString() + "ms");
Console.WriteLine("Repaired count: " + repairs.Count
+ ", check " + (repairs.SequenceEqual(repairsDict) ? "OK" : "ERROR"));
Console.ReadLine();
}
And the result is
List approach: 7264ms
Dict approach: 4ms
Repaired count: 4968, check OK
List approach is about 1800x slower, actually more the thousand times slower in this case. The results are as expected. If that is a problem is another question, it depends on concrete usage pattern in concrete application and is out of scope of this post.

Group multiple rows containing index and create list of custom objects for each index

I have got a List of strings (read from a file) in this order and format and need to convert into List of class.
1.0.1.0.1, Type: DateTime, Value: 06/03/2013 11:06:10
1.0.1.0.2, Type: DateTime, Value: 06/03/2014 11:06:10
1.0.1.0.3, Type: DateTime, Value: 06/03/2015 11:06:10
1.0.1.0.4, Type: DateTime, Value: 06/03/2016 11:06:10
1.0.1.0.5, Type: DateTime, Value: 06/03/2017 11:06:10
1.0.1.1.1, Type: Integer, Value: 1
1.0.1.1.2, Type: Integer, Value: 2
1.0.1.1.3, Type: Integer, Value: 3
1.0.0.1.4, Type: Integer, Value: 4
1.0.1.1.5, Type: Integer, Value: 5
1.0.1.2.1, Type: String, Value: Hello
1.0.1.2.2, Type: String, Value: Hello1
1.0.1.2.3, Type: String, Value: Hello2
1.0.1.2.4, Type: String, Value: Hello3
1.0.1.2.5, Type: String, Value: Hello4
Here is my class
public class MyData
{
public DateTime DateTime {get;set;}
public int Index {get;set;}
public string Value {get;set;}
}
Now What I wanted is to convert it into a list of C# class
Something like this...
List<MyData> myDataList = new List<MyData>();
MyData data1 = new MyData();
data1.DateTime = "06/03/2013 11:06:10";
data1.Index = 1;
data1.Value = "Hello";
myDataList.Add(data1);
MyData data2 = new MyData();
data2.DateTime = "06/03/2014 11:06:10";
data2.Index = 2;
data2.Value = "Hello1";
myDataList.Add(data2);
and so on..
This is what I have tried so far.
List<List<string>> allLists = lines
.Select(str => new { str, token = str.Split('.') })
.Where(x => x.token.Length >= 4)
.GroupBy(x => string.Concat(x.token.Take(4)))
.Select(g => g.Select(x => x.str).ToList())
.ToList();
Do I really need to iterate or can I modify My LINQ to get me desired output ?
Here is my iteration.
foreach (var list in allLists)
{
MyData data = new MyData();
var splittedstring = list[0].Split(',').ToList();
if (splittedstring.Count == 3)
{
var valueData = splittedstring [2];
var indexof = valueData.IndexOf(':');
var value = valueData.Substring(indexof + 1);
// But Over here, how will get DateTime and Index ?
data.Value = value;
}
}
First, fix your GroupBy: string.Concat(x.token.Take(4)) may create uncertainties when dot-separated numbers are ambiguous. For example, 1.23.4.5 and 12.3.4.5 would both produce "12345" string. Use string.Join with some non-numeric separator instead:
.GroupBy(x => string.Join("|", x.token.Take(4)))
Now for the main part of your question an easy fix would be to add a static method that parses the list of three strings, and use it in your LINQ query:
List<MyData> dataList = lines
.Select(str => new { str, token = str.Split('.') })
.Where(x => x.token.Length >= 4)
.GroupBy(x => string.Concat(x.token.Take(4)))
.Select(g => g.Select(x => x.str).ToList())
.Where(list => list.Count == 3)
.Select(MyDataFromList)
.ToList();
...
private static MyData MyDataFromList(List<string> parts) {
if (parts.Count != 3) {
throw new ArgumentException(nameof(parts));
}
var byType = parts
.Select(ToTypeAndValue)
.ToDictionary(t => t.Item1, t => t.Item2)
return new MyData {
DateTime = DateTime.Parse(byType["DateTime"])
, Index = int.Parse(byType["Integer"])
, Value = byType["String"]
};
}
private static Tuple<string,string> ToTypeAndValue(string s) {
var tokens = s.Split(',');
if (tokens.Length != 3) return null;
var typeParts = tokens[1].Split(':');
if (typeParts.Length != 2 || typeParts[0] != "Type") return null;
var valueParts = tokens[2].Split(':');
if (valueParts.Length != 2 || valueParts[0] != "Value") return null;
return Tuple.Create(typeParts[1].Trim(), typeParts[2].Trim());
}
Note that the above code makes an assumption that the three types are unique (hence the use of Dictionary<string,string>). This is required, because the structure of your data provides no other way to tie the values to fields of MyData.
You can do this using regular expressions. It would look like:
public List<MyData> GetData(string str){
var regexDate = new Regex(#"\d\.\d\.\d\.\d\.(?<id>\d).*DateTime.*Value:\s*(?<val>.*)");
var regexInteger = new Regex(#"\d\.\d\.\d\.\d\.(?<id>\d).*Integer.*Value:\s*(?<val>.*)");
var regexString = new Regex(#"\d\.\d\.\d\.\d\.(?<id>\d).*String.*Value:\s*(?<val>.*)");
var dict = new Dictionary<int, MyData>();
foreach (Match myMatch in regexDate.Matches(str))
{
if (!myMatch.Success) continue;
var index = int.Parse(myMatch.Groups["id"].Value);
dict[index] = new MyData()
{
Index = index,
DateTime = DateTime.ParseExact(myMatch.Groups["val"].Value, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture)
};
}
foreach (Match myMatch in regexInteger.Matches(str))
{
if (!myMatch.Success) continue;
var index = int.Parse(myMatch.Groups["id"].Value);
dict[index].Index = Int32.Parse(myMatch.Groups["val"].Value);
}
foreach (Match myMatch in regexString.Matches(str))
{
if (!myMatch.Success) continue;
var index = int.Parse(myMatch.Groups["id"].Value);
dict[index].Value = myMatch.Groups["val"].Value;
}
return dict.Values
}
Here is my solution to your problem. I have already tested it, you can test it to here: Raw To Custom List
string text = rawData;
//Raw Data Is the exact data you read from textfile without modifications.
List<MyData> myDataList = new List<MyData>();
string[] eElco = text.Split( new[] { Environment.NewLine }, StringSplitOptions.None );
var tmem = eElco.Count();
var eachP = tmem / 3;
List<string> unDefVal = new List<string>();
foreach (string rw in eElco)
{
String onlyVal = rw.Split(new[] { "Value: " } , StringSplitOptions.None)[1];
unDefVal.Add(onlyVal);
}
for (int i = 0; i < eachP; i++)
{
int ind = Int32.Parse(unDefVal[i + eachP]);
DateTime oDate = DateTime.ParseExact(unDefVal[i], "dd/MM/yyyy hh:mm:ss",System.Globalization.CultureInfo.InvariantCulture);
MyData data1 = new MyData();
data1.DateTime = oDate;
data1.Index = ind;
data1.Value = unDefVal[i + eachP + eachP];
myDataList.Add(data1);
Console.WriteLine("Val1 = {0}, Val2 = {1}, Val3 = {2}",
myDataList[i].Index,
myDataList[i].DateTime,
myDataList[i].Value);
}
Here is my solution, using Regex. It could be improved by providing a conditional regex match based on the matched type named group(string), but I think the concept is clearer this way, and the regex easier to work with. As it stands, the date format is not validated to be as OP wrote them, they are assumed to be as OP wrote them.
This solution is tolerant to some extra spaces and parameters containing commas, but intolerant to inexact matches, i.e. extra fields added or removed in the rows in the future, etc.
The idea is to first parse the rows to a more "friendly" format, and then group the friendly format by index and return the MyData rows by iterating each group (by index).
Regex r = new Regex(#"^(?<fieldName>(\d\.)+(?<index>\d*)), *Type: *(?<dataType>.*), *Value: (?<dataValue>.*)$");
public class MyData
{
public DateTime DateTime { get; set; }
public int Index { get; set; }
public string Value { get; set; }
}
class LogRow
{
public int Index { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}
//In a parser I would rather not be too defensive, I let exceptions bubble up
IEnumerable<LogRow> ParseRows(IEnumerable<string> lines)
{
foreach (var line in lines)
{
var match = r.Matches(line).AsQueryable().Cast<Match>().Single();
yield return new LogRow()
{
Index = int.Parse(match.Groups["index"].Value),
Type = match.Groups["dataType"].Value,
Value = match.Groups["dataValue"].Value
};
}
}
IEnumerable<MyData> RowsToData(IEnumerable<LogRow> rows)
{
var byIndex = rows.GroupBy(b => b.Index).OrderBy(b=> b.Key);
//assume that rows exist for all MyData fields for a given index
foreach (var group in byIndex)
{
var rawRow = group.ToDictionary(g => g.Type, g => g);
var date = DateTime.ParseExact(rawRow["DateTime"].Value, "dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
yield return new MyData() { Index = group.Key, DateTime = date, Value = rawRow["String"].Value };
}
}
Usage:
var myDataList = RowsToData(ParseRows(File.ReadAllLines("input.txt"))).ToList();
I'd just go for the manual approach... and since that list of integers at the start contains indices for the objects and for the properties, it'd only be logical to use these instead of the type strings.
Using a Dictionary, you can use that object-index to make a new object at the moment you find any of its properties, and store it using that index. And whenever you encounter another properties for the same index, you retrieve the object and fill in that property on it.
public static List<MyData> getObj(String[] lines)
{
Dictionary<Int32, MyData> myDataDict = new Dictionary<Int32, MyData>();
const String valueStart = "Value: ";
foreach (String line in lines)
{
String[] split = line.Split(',');
// Too many fail cases; I just ignore any line that stops matching at any point.
if (split.Length < 3)
continue;
String[] numData = split[0].Trim().Split('.');
if (numData.Length < 5)
continue;
// Using the 4th number as property identifier. Could also use the
// type string, but switch/case on a numeric value is more elegant.
Int32 prop;
if (!Int32.TryParse(numData[3], out prop))
continue;
// Object index, used to reference the objects in the Dictionary.
Int32 index;
if (!Int32.TryParse(numData[4], out index))
continue;
String typeDef = split[1].Trim();
String val = split[2].TrimStart();
if (!val.StartsWith(valueStart))
continue;
val = val.Substring(valueStart.Length);
MyData data;
if (myDataDict.ContainsKey(index))
data = myDataDict[index];
else
{
data = new MyData();
myDataDict.Add(index, data);
}
switch (prop)
{
case 0:
if (!"Type: DateTime".Equals(typeDef))
continue;
DateTime dateVal;
// Don't know if this date format is correct; adapt as needed.
if (!DateTime.TryParseExact(val, "dd/MM/yyyy HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dateVal))
continue;
data.DateTime = dateVal;
break;
case 1:
if (!"Type: Integer".Equals(typeDef))
continue;
Int32 numVal;
if (!Int32.TryParse(val, out numVal))
continue;
data.Index = numVal;
break;
case 2:
if (!"Type: String".Equals(typeDef)) continue;
data.Value = val;
break;
}
}
return new List<MyData>(myDataDict.Values);
}

Conditionally binding dropdownlist in asp.net

I have a string in this particular format
string LogInIDs = 124,345, 876 | 765,322, 98 | 565,99
All the numbers in the string are Unique LogIn ID. Using the Pipe symbol, the grouping is done of id's. Now, Suppose the LogInID is 345, then i need to bind other numbers (in this case 124 & 876) which are in the group in a dropdown. The below function is what i have made to retrieve the other numbers.
Can anybody come up with any better idea or suggestion
public static List<string> RetrieveAffCodes(string LogInIDs , string LogInID)
{
List<string> _finale = new List<string>();
string[] sep1 = new string[1];
sep1[0] = "|";
int count = LogInIDs.Count(x => x == '|');
string[] groups = new string[count + 1];
groups = LogInIDs.Split(sep1, StringSplitOptions.RemoveEmptyEntries);
foreach (string g in groups)
{
string p = g;
string[] sep2 = new string[1];
sep2[0] = ",";
int counter = p.Count(x => x == ',');
string[] final_list = new string[counter + 1];
final_list = p.Split(sep2, StringSplitOptions.RemoveEmptyEntries);
foreach (string _f in final_list)
{
if (_f.Trim() == LogInID)
{
_finale = AddLogInIDs(final_list, final_list.Count());
}
}
}
return _finale;
}
private static List<string> AddLogInIDs(string[] final_list, int p)
{
List<string> _finale = new List<string>();
foreach (var item in final_list)
{
_finale.Add(item.Trim());
}
return _finale;
}
Any suggestions will be embraced.
Thanks for your time and patience.
Note: The string will be expanding up to 200 groups
try this..
public static List<string> RetrieveAffCodes(string logInIDs, string logInID)
{
return logInIDs
.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
.Where(a => a.Split(',').Any(c => c.Trim().Equals(logInID)))
.Select(a => a.Split(',').ToList()).FirstOrDefault();
}
Would this work for you?
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
string LogInIDs = "124,345,876|765,322,98 |565,99";
Console.WriteLine(string.Join("\n", RetrieveAffCodes(LogInIDs, "322")));
Console.WriteLine(string.Join("\n", RetrieveAffCodes(LogInIDs, "565")));
}
public static IEnumerable<string> RetrieveAffCodes(string logInIDs , string logInID)
{
//We split the list
var list = logInIDs.Split('|');
//We look for an item with the logInID, if found (?) we split using ',' and then we remove the item
var match = list
.Select(i => i.Split(',').Select(item => item.Trim()))
.FirstOrDefault(i => i.Contains(logInID))?
.Where(i => i != logInID);
if(match != null)
{
return match;
}
return new List<string>();
}
}
Source code: https://dotnetfiddle.net/M2FyNk

Linq query to take the value from Array with matching sub string value

I have a string - filterArg and array of string - arrayColDef as shown in below code. I am trying to split the string filterArg by |~| and trying to get the value from filterArg by matching arrayColDef value.
Can any one let me know how to get the value ToDo commented in the code
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
string filterArg = "ZipCode=2130|~|ZipPlace=KNAPPER";
string[] arrayColDef = { "ZipCode", "Space", "ZipPlace" };
foreach (var item in arrayColDef)
{
var key = item;
var value = filterArg.Split(new string[] { "|~|" }, StringSplitOptions.RemoveEmptyEntries);//TODO: here value should hold = 2130 for first itteration
ht.Add(item, value);
}
}
I think you get complicated iterating over arrayColDef, it's easier to iterate through splited string and extract the values.
You can do something like below.
static void Main(string[] args)
{
Hashtable ht = new Hashtable();
string filterArg = "ZipCode=2130|~|ZipPlace=KNAPPER";
string[] arrayColDef = { "ZipCode", "Space", "ZipPlace" };
var properties = filterArg.Split(new string[] { "|~|" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var property in properties)
{
var nameValue = property.Split(arrayColDef, StringSplitOptions.RemoveEmptyEntries);
var item = property.Split('=').First(); // get key
var value = nameValue.First().TrimStart('='); // get value
ht.Add(item, value);
}
}
Hashtable ht = new Hashtable();
string filterArg = "ZipCode=2130|~|ZipPlace=KNAPPER";
string[] arrayColDef = { "ZipCode", "Space", "ZipPlace" };
var filterArr = filterArg.Split(new string[] { "|~|" }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split('='));
foreach (var item in arrayColDef)
{
var key = item;
var v = filterArr.FirstOrDefault(x => x[0] == item);
if (v != null&&v.Length>1)
{
ht.Add(item, v[1]);
}
}
foreach (var key in ht.Keys)
{
Console.WriteLine("Key:{0} Value:{1}", key, ht[key]);
}
Space has been ignored
The filter split in
var value = filterArg.Split(new string[] { "|~|" }, StringSplitOptions.RemoveEmptyEntries);//TODO: here value should hold = 2130 for first itteration
returns an array. You can get the final value by filtering and replacing with linq:
string finalValue = value.Where(m => m.Contains(item)).Select(m => m.Replace(item+"=","")).FirstOrDefault();
The value, then, is in finalValue variable.
Greetings

Inverting case: (aPPLE to Apple, BLUeBeRrY to bluEbErRY)

In my following code, the output is Upper:APPLE and Lower:apple, but I need aPPLE to become Apple, and BLUeBeRrY to become bluEbErRY.
string[] words = {"aPPLE", "BlUeBeRrY", "cHeRry" };
var upperLowerWords = from w in words
select new { Upper = w.ToUpper(),
Lower = w.ToLower() };
foreach (var ul in upperLowerWords)
{
Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper, ul.Lower);
}
Using some more Linq magic:
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };
var upperLowerWords = from w in words
select new
{
Upper = w.ToUpper(),
Lower = w.ToLower(),
Original = w,
Changed = new string(w.Select(s=> char.IsLower(s) ? char.ToUpper(s) : char.ToLower(s)).ToArray())
};
foreach (var ul in upperLowerWords)
{
Console.WriteLine("Original: {0}, Uppercase: {1}, Lowercase: {2}, Changed: {3}", ul.Original, ul.Upper, ul.Lower, ul.Changed );
}
How about throwing in some extension methods:
public static class StringExtensions
{
public static string InvertCases(this string value)
{
if (string.IsNullOrWhiteSpace(value)) return value;
var chars = value.ToCharArray();
for (int i = 0; i < chars.Length; i++)
chars[i] = char.IsLower(chars[i]) ? char.ToUpper(chars[i]) : char.ToLower(chars[i]);
return new string(chars);
}
}
and your use would be
static void Main(string[] args)
{
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };
foreach (var ul in words)
{
Console.WriteLine("Original: {0}, Inverted: {1}", ul, ul.InvertCases());
}
Console.ReadLine();
}
Many ways lead to Rome...
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };
var upperLowerWords = from w in words
select new { Original = w, Changed = ChangeCases(w) };
foreach (var ul in upperLowerWords)
{
Console.WriteLine("Original: {0}, Changed: {1}",
ul.Original, ul.Changed);
}
static string ChangeCases(string input)
{
string result = string.Empty;
foreach (char ch in input)
{
result += Char.IsUpper(ch) ? ch.ToString().ToLower() : ch.ToString().ToUpper();
}
return result;
}
I suggest using Linq with char.IsXXX and char.ToXXX methods
string source = "StaCkOverFloW";
string result = string.Concat(source.Select(c => char.IsLower(c)
? char.ToUpper(c) : char.IsUpper(c)
? char.ToLower(c) : c));
...
// sTAcKoVERfLOw
Console.Write(result);
For ASCII only letters, you can XOR the 6th bit:
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };
var result = words.Select(s => string.Concat(s.Select(c => (char)(c ^ ' '))));
Debug.Print(string.Join(", ", result)); // "Apple, bLuEbErRy, ChErRY"

Categories