Find a fixed length string with specific string part in C# - c#

I want to find a string of fixed length with specific substring. But I need to do it like we can do in SQL queries.
Example:
I have strings like -
AB012345
AB12345
AB123456
AB1234567
AB98765
AB987654
I want to select strings that have AB at first and 6 characters afterwards. Which can be done in SQL by SELECT * FROM [table_name] WHERE [column_name] LIKE 'AB______' (6 underscores after AB).
So the result will be:
AB012345
AB123456
AB987654
I need to know if there is any way to select strings in such way with C#, by using AB______.

You can use Regular Expressions to filter the result:
List<string> sList = new List<string>(){"AB012345",
"AB12345",
"AB123456",
"AB1234567",
"AB98765",
"AB987654"};
var qry = sList.Where(s=>Regex.Match(s, #"^AB\d{6}$").Success);

Considering you have an string array:
string[] str = new string[3]{"AB012345", "A12345", "AB98765"};
var result = str.Where(x => x.StartsWith("AB") && x.Length == 8).ToList();
The logic is if it starts with AB, and its length is 8. It is your best match.

this should do it
List<string> sList = new List<string>(){
"AB012345",
"AB12345",
"AB123456",
"AB1234567",
"AB98765",
"AB987654"};
List<string> sREsult = sList.Where(x => x.Length == 8 && x.StartsWith("AB")).ToList();
first x.Length == 8 determines the length and x.StartsWith("AB") determines the required characters at the start of the string

This can be achieved by using string.Startwith and string.Length function like this:
public bool CheckStringValid (String input)
{
if (input.StartWith ("AB") && input.Length == 8)
{
return true;
}
else
{
return false;
}
}
This will return true if string matches your criteria.
Hope this helps.

var strlist = new List<string>()
{
"AB012345",
"AB12345",
"AB123456",
"AB1234567",
"AB98765",
"AB987654"
};
var result = strlist.Where(
s => (s.StartsWith("AB") &&(s.Length == 8))
);
foreach(var v in result)
{
Console.WriteLine(v.ToString());
}

Related

How to validate or compare string by omitting certain part of it

I have a string as below
"a1/type/xyz/parts"
The part where 'xyz' exists is dynamic and varies accordingly at any size. I want to compare just the two strings are equal discarding the 'xyz' portion exactly.
For example I have string as below
"a1/type/abcd/parts"
Then my comparison has to be successful
I tried with regular expression as below. Though my knowledge on regular expressions is limited and it did not work. Probably something wrong in the way I used.
var regex = #"^[a-zA-Z]{2}/\[a-zA-Z]{16}/\[0-9a-zA-Z]/\[a-z]{5}/$";
var result = Regex.Match("mystring", regex).Success;
Another idea is to get substring of first and last part omitting the unwanted portion and comparing it.
The comparison should be successful by discarding certain portion of the string with effective code.
Comparison successful cases
string1: "a1/type/21412ghh/parts"
string2: "a1/type/eeeee122ghh/parts"
Comparison failure cases:
string1: "a1/type/21412ghh/parts"
string2: "a2/type/eeeee122ghh/parts/mm"
In short "a1/type/abcd/parts" in this part of string the non-bold part is static always.
Honestly, you could do this using regex, and pull apart the string. But you have a specified delimiter, just use String.Split:
bool AreEqualAccordingToMyRules(string input1, string input2)
{
var split1 = input1.Split('/');
var split2 = input2.Split('/');
return split1.Length == split2.Length // strings must have equal number of sections
&& split1[0] == split2[0] // section 1 must match
&& split1[1] == split2[1] // section 2 must match
&& split1[3] == split2[3] // section 4 must match
}
You can try Split (to get parts) and Linq (to exclude 3d one)
using System.Linq;
...
string string1 = "a1/type/xyz/parts";
string string2 = "a1/type/abcd/parts";
bool result = string1
.Split('/') // string1 parts
.Where((v, i) => i != 2) // all except 3d one
.SequenceEqual(string2 // must be equal to
.Split('/') // string2 parts
.Where((v, i) => i != 2)); // except 3d one
Here's a small programm using string functions to compare the parts before and after the middle part:
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(CutOutMiddle("a1/type/21412ghh/parts"));
Console.WriteLine("True: " + CompareNoMiddle("a1/type/21412ghh/parts", "a1/type/21412ghasdasdh/parts"));
Console.WriteLine("False: " + CompareNoMiddle("a1/type/21412ghh/parts", "a2/type/21412ghh/parts/someval"));
Console.WriteLine("False: " + CompareNoMiddle("a1/type/21412ghh/parts", "a1/type/21412ghasdasdh/parts/someappendix"));
}
private static bool CompareNoMiddle(string s1, string s2)
{
var s1CutOut = CutOutMiddle(s1);
var s2CutOut = CutOutMiddle(s2);
return s1CutOut == s2CutOut;
}
private static string CutOutMiddle(string val)
{
var fistSlash = val.IndexOf('/', 0);
var secondSlash = val.IndexOf('/', fistSlash+1);
var thirdSlash = val.IndexOf('/', secondSlash+1);
var firstPart = val.Substring(0, secondSlash);
var secondPart = val.Substring(thirdSlash, val.Length - thirdSlash);
return firstPart + secondPart;
}
}
returns
a1/type/parts
True: True
False: False
False: False
This solution should cover your case, as said by others, if you have a delimiter use it. In the function below you could change int skip for string ignore or something similar and within the comparison loop if(arrayStringOne[i] == ignore) continue;.
public bool Compare(string valueOne, string valueTwo, int skip) {
var delimiterOccuranceOne = valueOne.Count(f => f == '/');
var delimiterOccuranceTwo = valueTwo.Count(f => f == '/');
if(delimiterOccuranceOne == delimiterOccuranceTwo) {
var arrayStringOne = valueOne.Split('/');
var arrayStringTwo = valueTwo.Split('/');
for(int i=0; i < arrayStringOne.Length; ++i) {
if(i == skip) continue; // or instead of an index you could use a string
if(arrayStringOne[i] != arrayStringTwo[i]) {
return false;
}
}
return true;
}
return false;
}
Compare("a1/type/abcd/parts", "a1/type/xyz/parts", 2);

How to perform word search using LINQ?

I have a list which contains the name of suppliers. Say
SuppId Supplier Name
----------------------------------
1 Aardema & Whitelaw
2 Aafedt Forde Gray
3 Whitelaw & Sears-Ewald
using following LINQ query
supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey));
I can return records correctly in the following conditions,
1) If i am using search string as "Whitelaw & Sears-Ewald" it will return 3rd record.
2) If i am using "Whitelaw" or "Sears-Ewald" it will return 3rd record.
But how can i return 3rd record if i am giving search string as "Whitelaw Sears-Ewald". It always returns 0 records.
Can i use ALL to get this result, but i dont know how to use it for this particular need.
What I usually do in this situation is split the words into a collection, then perform the following:
var searchopts = SearchKey.Split(' ').ToList();
supplierListQuery = supplierListQuery
.Where(x => searchopts.Any(y=> x.SupplierName.Contains(y)));
This works for me:
IEnumerable<string> keyWords = SearchKey.Split('');
supplierListQuery = supplierListQuery
.AsParallel()
.Where
(
x => keyWords.All
(
keyword => x.SupplierName.ContainsIgnoreCase(keyword)
)
);
Thank you all for your quick responses. But the one which worked or a easy fix to handle this was timothyclifford's note on this. Like he said i alterd my answer to this
string[] filters = SearchKey.ToLower().Split(new[] { ' ' });
objSuppliersList = (from x in objSuppliersList
where filters.All(f => x.SupplierName.ToLower().Contains(f))
select x).ToList();
Now it returns the result for all my serach conditions.
Because "Whitelaw" appears in both you will get both records. Otherwise there is no dynamic way to determine you only want the last one. If you know you only have these 3 then append .Last() to get the final record.
supplierListQuery = supplierListQuery.Where(x => x.SupplierName.Contains(SearchKey.Split(' ')[0]));
You need to use some sort of string comparer to create your own simple Search Engine and then you can find strings that are most likely to be included in your result :
public static class SearchEngine
{
public static double CompareStrings(string val1, string val2)
{
if ((val1.Length == 0) || (val2.Length == 0)) return 0;
if (val1 == val2) return 100;
double maxLength = Math.Max(val1.Length, val2.Length);
double minLength = Math.Min(val1.Length, val2.Length);
int charIndex = 0;
for (int i = 0; i < minLength; i++) { if (val1.Contains(val2[i])) charIndex++; }
return Math.Round(charIndex / maxLength * 100);
}
public static List<string> Search(this string[] values, string searchKey, double threshold)
{
List<string> result = new List<string>();
for (int i = 0; i < values.Length; i++) if (CompareStrings(values[i], searchKey) > threshold) result.Add(values[i]);
return result;
}
}
Example of usage :
string[] array = { "Aardema & Whitelaw", "Aafedt Forde Gray", "Whitelaw & Sears-Ewald" };
var result = array.Search("WhitelawSears-Ewald", 80);
// Results that matches this string with 80% or more
foreach (var item in result)
{
Console.WriteLine(item);
}
Output: Whitelaw & Sears-Ewald
If you want an easy (not very handy) solution,
var result = supplierListQuery
.Select(x => normalize(x.SupplierName))
.Where(x => x.Contains(normalize(SearchKey)));
string normalize(string inputStr)
{
string retVal = inputStr.Replace("&", "");
while (retVal.IndexOf(" ") >= 0)
{
retVal = retVal.Replace(" ", " ");
}
return retVal;
}

I want substring from set of string after a pattern exist in c#

I have 3 string ---
m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU
m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER
m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT
and I want R0RKE_52_GU, R10KE_52_TCRER,R0HKE_52_NT.
Note: m60_CLDdet2_LOSS2CLF_060520469434 is varying so I want to find substring if R0RKE or R10KE or R0HKE exists
I would suggest using a Regular expression for this, it is much more versatile for pattern matching.
var matches = System.Text.RegularExpressions.Regex.Matches(text, #"(R0RKE|R10KE|R0HKE).*");
I want to find substring if R0RKE or R10KE or R0HKE exists
This LINQ query returns the desired result:
var strings=new[]{"m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU","m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER","m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT"};
string[] starts = { "R0RKE", "R10KE", "R0HKE" };
var result = strings
.Select(str => new { str, match = starts.FirstOrDefault(s => str.IndexOf("_" + s) >= 0)})
.Where(x => x.match != null)
.Select(x => x.str.Substring(x.str.IndexOf(x.match)));
Console.Write(String.Join(",", result)); // R0RKE_52_GU,R10KE_52_TCRER,R0HKE_52_NT
I write it into static method:
private static string TakeIt(string inputString)
{
if (!Regex.IsMatch(inputString, "(R0RKE|R10KE|R0HKE)"))
{
return string.Empty;
}
var regex = new Regex(#"_");
var occurances = regex.Matches(inputString);
var index = occurances[3].Index + 1;
return inputString.Substring(index, inputString.Length - index);
}
void Main()
{
var string1 = "m60_CLDdet2_LOSS2CLF_060520469434_R0RKE_52_GU";
var string2 = "m60_CLDdet2_LOSS2CLF_060520469434_R10KE_52_TCRER";
var string3 = "m60_CLDdet2_LOSS2CLF_060520469434_R0HKE_52_NT";
var string4 = "m60_CLDdet2_LOSS2CLF_060520469434_hhhhh";
Console.WriteLine(TakeIt(string1));
Console.WriteLine(TakeIt(string2));
Console.WriteLine(TakeIt(string3));
Console.WriteLine(TakeIt(string4));
}
Hope this help.
Update: added .Any - it simplifies the code and it's just as same efficient.
If you just need to check for three strings inside string array you can do :
static string[] GetStrings(string[] dirty, string[] lookUpValues)
{
List<string> result = new List<string>();
for (int i = 0; i < dirty.Length; i++) if (lookUpValues.Any(dirty[i].Contains)) result.Add(dirty[i]);
return result.ToArray();
}
Usage: string[] result = GetStrings(dirty, new[] {"R0RKE", "R10KE", "R0HKE"});
Also you can use LINQ query and Regex.Matches as others advised.

How to retrieve a substring based on a first list match

In a string I need to recover a 7 char substring based on the first match from any item in a list. If a match is not made it should return an empty string.
I have the following code:
List<string> myList = new List<string>()
{
"TNCO",
"TNCB",
"TNIT"
};
string sample = "TNSD102, WHRK301, TNIT301, YTRE234";
//doesn't give an index
bool anyfound = myList.Any(w => sample.Contains(w));
//code that needs replacing
string code = sample.Substring(sample.IndexOf("TNC"), 7);
if (code == "")
{
code = sample.Substring(sample.IndexOf("TNIT"), 7);
}
The list is never likely to be more than 35-40 items and the strings < 50 chars.
Anyone able to point me in the right direction?
string val1 = (sample.Split(',').FirstOrDefault(w => myList.Any(m => w.Contains(m))) ?? string.Empty).Trim();
This gives you an IEnumerable of all matches:
var matches = from code in sample.Split(',')
from w in myList
where code.Trim().StartsWith(w)
select code;
To get the first value use FirstOrDefault. Then use the coalesce operator ?? to return an empty string if there was no match.
string firstMatch = (matches.FirstOrDefault() ?? "").Trim();
With data sets this small, you can simply split the string and search for the first match:
// split the sample string into separate entries
var entries = sample.Split(new char[] {',', ' '},
StringSplitOptions.RemoveEmptyEntries);
// find the first entry starting with any allowed prefix
var firstMatch = entries.FirstOrDefault (
e => myList.Any (l => e.StartsWith(l)));
// FirstOrDefault returns null if there are no matches
if (firstMatch == null)
Console.WriteLine("No match!");
else
Console.WriteLine(firstMatch);
Example output (DEMO):
TNIT301
List<string> myList = new List<string> { "TNCO", "TNCB", "TNIT" };
string sample = "TNSD102, WHRK301, TNIT301, YTRE234";
string[] sampleItems = sample.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
var results = myList
.Select(prefix => sampleItems
.FirstOrDefault(item => item.StartsWith(prefix)) ?? "");
Running this code here returns an Index of 2 based on what you are trying to find.
int keyIndex = myList.FindIndex(w => samples.Contains(w));
TNIT301 this is the indexed string value
you could also do the following to return the string value in index position of keyIndex variable value.
var subStrValue = samples.Split(',')[keyIndex];

Change the foreach loop into the LINQ query

I stuck in an easy scenario. I have a List<string> object, all of its items has the body of:
item_1_2_generatedGUID //generatedGUID is Guid.NewGuid()
but there may be much more numbers
item_1_2_3_4_5_generatedGUID etc
now, I'm wondering how to change that loop into the LINQ's query. Any ideas ?
string one = "1"; //an exaplme
string two = "2"; //an exaplme
foreach (var item in myStringsList)
{
string[] splitted = item.Split(new char[] { '_' },
StringSplitOptions.RemoveEmptyEntries);
if(splitted.Length >= 3)
{
if(splitted[1] == one && splitted[2] == two)
{
resultList.Add(item);
}
}
}
var result = from s in lst
let spl = s.Split('_')
where spl.Length >= 3 && spl[1] = one && spl[2] == two
select s;
Try this:
var query = from item in myStringsList
let splitted = item.Split(new[] { '_' }, SSO.RemoveEmptyEntries)
where splitted.Length >= 3
where splitted[1] == one && splitted[2] == two
select item;
var resultList = query.ToList();
This is a different approach:
var items = myStringsList.
Where(x => x.Substring(x.IndexOf("_")).StartsWith(one+"_"+two+"_"));
You probably will need to add a +1 in the IndexOf, but I'm not sure.
What it does is:
Removes the first item (that's the substring for). In your example, it should be "1_2_3_4_5_generatedGUID"
Checks the string starts with what you are expecting. In your example: 1_2_
Edited: Added the pattern for anything at the first "position"
var result = items.Where(i => Regex.IsMatch(i, "^[^_]_1_2_"));

Categories