Best way to extract string from another string based on collection - c#

I have str which is a string and I want to check if the last part of string is equal to other string, below I do it manually but lets say I have an array strin[] keys = {"From", "To", ...}. If its equal I want to extract (remove) it from str and put it inside key. What is the best way to achieve that?
string key;
if(str.Substring(str.Length - 4) == "From");{
key = "From";
//Do something with key
}
else if (str.Substring(str.Length - 2) == "To") {
key = "To";
//Do something with key
}
... //There may be more string to compare with
str = str.Remove(str.Length - key.Length);

You can just use FirstOrDefault and EndsWith. This will either give you the key it ends with or null. You'll have to include the using System.Linq for this to work.
string key = keys.FirstOrDefault(k => str.EndsWith(k));
if(key != null)
{
str = str.Remove(str.Length - key.Length);
}

Use a foreach loop to iterate your keys, then EndsWith() to detect and SucĀ“bString to extract:
foreach(string key in keys)
{
if(str.EndsWith(key))
{
int len = str.Length - key.Length;
result = str.Substring(0, len);
break;
}
}

Related

Searching through keys dictionary

How can i search through a bunch of keys in a Dictionary with a for loop or something like it and see if there is any key with the same first three string values as another string. the following example isnt Code at all but it is basicly the result i whant.
Key1(3932030)
Key2(4201230)
Key3(5209872)
ArrayWithKeys(3930000,4200000,5200000)
Dictionary searchForkeys(ArrayWithKeys[i])
keyFound(3932030)
First, Get substring to search and then use it to find keys inside dictionary object.
string[] keyArray = new string[]{ "3930000", "4200000" , "5200000"};
string substringToSearch ;
foreach(string inputKey in keyArray)
{
substringToSearch = inputKey.Length >= 3 ? inputKey.Substring(0, 3) : inputKey;
if(dictionaryObject.Keys.Any(x => x.StartsWith(substringToSearch)))
{
// below is the key matched with inputKey
dictionaryObject.Where(x => x.Key.StartsWith(substringToSearch)).First().Value;
}
}
EDIT
Using only for loop
string substringToSearch = inputKey.Length >= 3 ? inputKey.Substring(0, 3) : inputKey;
for(int i; i < dictionaryObject.Keys.Count; i++)
{
if( dictionaryObject.ElementAt(i).Key.StartsWith(substringToSearch) )
{
// key matched with inputKey
// below is key
string keyStr = dictionaryObject.ElementAt(i).Key;
}
}

Extract number from string value

I have a string that always come into this format:
"TM" + multiple Leading 0 + Number + Non-Number Character + Alphanumeric.
For example: TM000013452S20548, PB000013452S3DVSF.
How do I parse (in C# code) the varchar value to get the "Number" (13452) in this case?
You can use RegualarExpressions:
(?:TM|PB)0{0,}(\d+)
Like this:
string input = "For example: TM000013452S20548, PB000013452S3DVSF.";
var matches = Regex.Matches(input, #"(?:TM|PB)0{0,}(\d+)");
foreach(Match m in matches)
Console.WriteLine(int.Parse(m.Groups[1].Value));
Live Demo
You can use Linq:
var number = new String(
yourString.Skip(2)
.SkipWhile(s => s == '0')
.TakeWhile(s => Char.IsDigit(s))
.ToArray()
);
If all the fields are fixed width, and all you care about is the first integer, then it's pretty easy; just use string.Substring to extract the part you care about and then parse it.
Here's how to do the extract and parse (note that I use int.TryParse - you are parsing a possibly corrupted string):
private bool TryExtractFirstNumber(string input, out int result)
{
var resultString = input.Substring(2, 9);
return int.TryParse(resultString, out result);
}
You can call this like:
var inputs = new[]
{
"TM000013452S20548",
"PB000013452S3DVSF",
};
foreach (var inp in inputs)
{
if (TryExtractFirstNumber(inp, out var result))
{
Debug.WriteLine(result);
}
}
The output from that is:
13452
13452
If the position of the "Non-Number Character" that you describe is not known, go looking for it:
private int FindIndexOfFirstNonNumeric(string toScan, int startIndex = 0)
{
for (var index = startIndex; index < toScan.Length; ++index)
{
if (!char.IsNumber(toScan[index]))
{
return index;
}
}
return toScan.Length;
}
and then modify the TryExtractFirstNumber function to look for it:
private bool TryExtractFirstNumber(string input, out int result)
{
var length = FindIndexOfFirstNonNumeric(input, 2) - 2;
var resultString = input.Substring(2, length);
return int.TryParse(resultString, out result);
}
It gives the same results.

How to replace multiple substrings in a string in C#?

I have to replace multiple substrings from a string (max length 32 of input string). I have a big dictionary which can have millions of items as a key-value pair. I need to check for each word if this word is present in the dictionary and replace with the respective value if present in the dictionary. The input string can have multiple trailing spaces.
This method is being called millions of time, due to this, it's affecting the performance badly.
Is there any scope of optimization in the code or some other better way to do this.
public static string RandomValueCompositeField(object objInput, Dictionary<string, string> g_rawValueRandomValueMapping) {
if (objInput == null)
return null;
string input = objInput.ToString();
if (input == "")
return input;
//List<string> ls = new List<string>();
int count = WhiteSpaceAtEnd(input);
foreach (string data in input.Substring(0, input.Length - count).Split(' ')) {
try {
string value;
gs_dictRawValueRandomValueMapping.TryGetValue(data, out value);
if (value != null) {
//ls.Add(value.TrimEnd());
input = input.Replace(data, value);
}
else {
//ls.Add(data);
}
}
catch(Exception ex) {
}
}
//if (count > 0)
// input = input + new string(' ', count);
//ls.Add(new string(' ', count));
return input;
}
EDIT:
I missed one important thing in the question. substring can occur only once inthe input string. Dictionay key and value have same number of characters.
Here's a method that will take an input string and will build a new string by finding "words" (any consecutive non-whitespace) and then checking if that word is in a dictionary and replacing it with the corresponding value if found. This will fix the issues of Replace doing replacements on "sub-words" (if you have "hello hell" and you want to replace "hell" with "heaven" and you don't want it to give you "heaveno heaven"). It also fixes the issue of swapping. For example if you want to replace "yes" with "no" and "no" with "yes" in "yes no" you don't want it to first turn that into "no no" and then into "yes yes".
public string ReplaceWords(string input, Dictionary<string, string> replacements)
{
var builder = new StringBuilder();
int wordStart = -1;
int wordLength = 0;
for(int i = 0; i < input.Length; i++)
{
// If the current character is white space check if we have a word to replace
if(char.IsWhiteSpace(input[i]))
{
// If wordStart is not -1 then we have hit the end of a word
if(wordStart >= 0)
{
// get the word and look it up in the dictionary
// if found use the replacement, if not keep the word.
var word = input.Substring(wordStart, wordLength);
if(replacements.TryGetValue(word, out var replace))
{
builder.Append(replace);
}
else
{
builder.Append(word);
}
}
// Make sure to reset the start and length
wordStart = -1;
wordLength = 0;
// append whatever whitespace was found.
builder.Append(input[i]);
}
// If this isn't whitespace we set wordStart if it isn't already set
// and just increment the length.
else
{
if(wordStart == -1) wordStart = i;
wordLength++;
}
}
// If wordStart is not -1 then we have a trailing word we need to check.
if(wordStart >= 0)
{
var word = input.Substring(wordStart, wordLength);
if(replacements.TryGetValue(word, out var replace))
{
builder.Append(replace);
}
else
{
builder.Append(word);
}
}
return builder.ToString();
}

How to remove all but the first occurences of a character from a string?

I have a string of text and want to ensure that it contains at most one single occurrence of a specific character (,). Therefore I want to keep the first one, but simply remove all further occurrences of that character.
How could I do this the most elegant way using C#?
This works, but not the most elegant for sure :-)
string a = "12,34,56,789";
int pos = 1 + a.IndexOf(',');
return a.Substring(0, pos) + a.Substring(pos).Replace(",", string.Empty);
You could use a counter variable and a StringBuilder to create the new string efficiently:
var sb = new StringBuilder(text.Length);
int maxCount = 1;
int currentCount = 0;
char specialChar = ',';
foreach(char c in text)
if(c != specialChar || ++currentCount <= maxCount)
sb.Append(c);
text = sb.ToString();
This approach is not the shortest but it's efficient and you can specify the char-count to keep.
Here's a more "elegant" way using LINQ:
int commasFound = 0; int maxCommas = 1;
text = new string(text.Where(c => c != ',' || ++commasFound <= maxCommas).ToArray());
I don't like it because it requires to modify a variable from a query, so it's causing a side-effect.
Regular expressions are elegant, right?
Regex.Replace("Eats, shoots, and leaves.", #"(?<=,.*),", "");
This replaces every comma, as long as there is a comma before it, with nothing.
(Actually, it's probably not elegant - it may only be one line of code, but it may also be O(n^2)...)
If you don't deal with large strings and you reaaaaaaly like Linq oneliners:
public static string KeepFirstOccurence (this string #string, char #char)
{
var index = #string.IndexOf(#char);
return String.Concat(String.Concat(#string.TakeWhile(x => #string.IndexOf(x) < index + 1)), String.Concat(#string.SkipWhile(x=>#string.IndexOf(x) < index)).Replace(#char.ToString(), ""));
}
You could write a function like the following one that would split the string into two sections based on the location of what you were searching (via the String.Split() method) for and it would only remove matches from the second section (using String.Replace()) :
public static string RemoveAllButFirst(string s, string stuffToRemove)
{
// Check if the stuff to replace exists and if not, return the original string
var locationOfStuff = s.IndexOf(stuffToRemove);
if (locationOfStuff < 0)
{
return s;
}
// Calculate where to pull the first string from and then replace the rest of the string
var splitLocation = locationOfStuff + stuffToRemove.Length;
return s.Substring(0, splitLocation) + (s.Substring(splitLocation)).Replace(stuffToRemove,"");
}
You could simply call it by using :
var output = RemoveAllButFirst(input,",");
A prettier approach might actually involve building an extension method that handled this a bit more cleanly :
public static class StringExtensions
{
public static string RemoveAllButFirst(this string s, string stuffToRemove)
{
// Check if the stuff to replace exists and if not, return the
// original string
var locationOfStuff = s.IndexOf(stuffToRemove);
if (locationOfStuff < 0)
{
return s;
}
// Calculate where to pull the first string from and then replace the rest of the string
var splitLocation = locationOfStuff + stuffToRemove.Length;
return s.Substring(0, splitLocation) + (s.Substring(splitLocation)).Replace(stuffToRemove,"");
}
}
which would be called via :
var output = input.RemoveAllButFirst(",");
You can see a working example of it here.
static string KeepFirstOccurance(this string str, char c)
{
int charposition = str.IndexOf(c);
return str.Substring(0, charposition + 1) +
str.Substring(charposition, str.Length - charposition)
.Replace(c, ' ').Trim();
}
Pretty short with Linq; split string into chars, keep distinct set and join back to a string.
text = string.Join("", text.Select(c => c).Distinct());

String to System.Windows.Input.Key

I need a function that takes a String as an argument, and returns a System.Windows.Input.Key. E.G:
var x = StringToKey("enter"); // Returns Key.Enter
var y = StringToKey("a"); // Returns Key.A
Is there any way to do this other than if/else's or switch statements?
Take a look at KeyConverter, it can convert a Key to and from a string.
KeyConverter k = new KeyConverter();
Key mykey = (Key)k.ConvertFromString("Enter");
if (mykey == Key.Enter)
{
Text = "Enter Key Found";
}
Key is an enum, so you can parse it like any enum:
string str = /* name of the key */;
Key key;
if(Enum.TryParse(str, true, out key))
{
// use key
}
else
{
// str is not a valid key
}
Keep in mind that the string has to match exactly (well, almost; it's a case insensitive comparison because of that true parameter) the name of the enumeration value.
var key = Enum.Parse(typeof(Key), "Enter");
Case-insensitive option:
var key = Enum.Parse(typeof(Key), "enter", true);

Categories

Resources