How to call function over - c#

I have made a function which can replace the position of the chars if they are standing in my list
Code:
public string NoSimilarChar(string password)
{
var listOfSimilarCharacters = new Dictionary<string, string>();
listOfSimilarCharacters.Add("l", "i");
listOfSimilarCharacters.Add("1", "i");
listOfSimilarCharacters.Add("O", "0");
// Iterate through each character
for (int i = 0; i < password.Length; i++)
{
var currentCharacter = password[i].ToString();
// check if the current char exists in either the key or the value of the list of similar characters
if (listOfSimilarCharacters.Keys.Contains(currentCharacter) || listOfSimilarCharacters.Values.Contains(currentCharacter))
{
currentCharacter = currentCharacter.Remove(currentCharacter.Length - 1, 1) + ",";
}
}
return password;
}
Now i want to know how to load the function NoSimilarChar over when the characters is remove
i thought something like this:
if (listOfSimilarCharacters.Keys.Contains(currentCharacter) || listOfSimilarCharacters.Values.Contains(currentCharacter))
{
currentCharacter = currentCharacter.Remove(currentCharacter.Length - 1, 1) + ",";
NoSimilarChar(password);
}
but i think this is not good because he then stays in a loop.

///for replacing
foreach (KeyValuePair<string, string> item in listOfSimilarCharacters)
{
password = password.Replace(item.Key, item.Value);
}
///for removing
foreach (KeyValuePair<string, string> item in listOfSimilarCharacters)
{
if (password.IndexOf(item.Key) >= 0)
password = password.Remove(password.IndexOf(item.Key), 1);
}

try this simpler one
var charsThatCannotbeinUserPwd = new[] {'1', 'l', 'O', '0', 'i'};
// Iterate through each character
var builder = new StringBuilder();
for (int i = 0; i < password.Length; i++)
{
var currentCharacter = password[i];
if (!charsThatCannotbeinUserPwd.Any(x => x.Equals(currentCharacter)))
builder.Append(currentCharacter);
}
return builder.ToString();

It looks like you want to remove a set of characters from you password. If that is the case then you don't need to use a Dictionary. A Dictionary would make more sense if you wanted to replace one character with another. Additionally you do not need to use recursion here. I believe all you need is an array of the characters you want to remove and a simple loop to remove them.
public string NoSimilarChar(string password)
{
string[] charsToRemove = new string[] { "l", "i", "1", "0", "O" }
foreach (string charToRemove in charsToRemove)
{
password = password.Replace(charToRemove, "");
}
return password;
}
FYI: I've defined the array of characters as strings because you will want to replace the character with an empty string and there is no empty character.

Related

Extract values from a string based on a pattern

I need to pull a bunch of key value pairs based on a predefined pattern from a string. An example of what I would need is this:
Pattern: {value1}-{value2}
String: Example-String
Result KVP:
{ Key: value1, value: Example },
{ Key: value2, value: String }
The catch is that the pattern could be pretty much anything (although the values I'd need to extract would always be surrounded in curly brackets), ie:
Pattern: {test1}\{test2}={value}
String: Example\Value=Result
Result KVP:
{ Key: test1, value: Example },
{ Key: test2, value: Value },
{ Key: value, value: Result }
What I have done so far isn't quite working and I'm quite certain that there has to be a more elegant way of doing this as opposed to my solution anyway so I thought I'd see if anyone here would have a good idea.
EDIT:
Here is essentially what I have so far (it's working, but IMO it's really ugly):
public List<KeyValuePair<string, string>> Example(string pattern, string input)
{
var values = new List<KeyValuePair<string, string>>();
var r1 = Regex.Matches(input, #"(\{[A-Z,a-z]*\})");
string newregex = string.Empty;
foreach (Match item in r1)
{
newregex = newregex.Replace(item.Value, "(.*?)"); //updates regex so that it adds this as a group for use later, ie: "{item1}-{item2}" will become "(.*?)-{item2}"
string field = item.Value.Substring(1, item.Value.Length - 2); // {test1} will return "test1"
values.Add(new KeyValuePair<string, string>(field, string.Empty));
}
newregex = $"{newregex}\\z"; // ensures that it matches to end of input
var r2 = Regex.Match(input, newregex);
// KVP index (used below)
int val = 0;
foreach (Group g in r2.Groups)
{
if (g.Value == input)
continue; // first group will be equal to input, ignore
values[val] = new KeyValuePair<string, string>(values[val].Key, g.Value); // update KVP at index with new KVP with the value
val++;
}
return values;
}
Unfortunately I don't know regular expressions very well, but one way to solve this is to walk through each character of the pattern string and create a list of keys and delimeters, after which we can walk through the search string, and find the index of each delimeter to get the current value, and then add a new KeyValuePair to a list.
Here's a rough sample that assumes good input:
public static List<KeyValuePair<string, string>> GetKVPs(string pattern, string search)
{
var results = new List<KeyValuePair<string, string>>();
var keys = new List<string>();
var delimeters = new List<string>();
var currentKey = string.Empty;
var currentDelimeter = string.Empty;
var processingKey = false;
// Populate our lists of Keys and Delimeters
foreach (var chr in pattern)
{
switch (chr)
{
case '}':
{
if (currentKey.Length > 0)
{
keys.Add(currentKey);
currentKey = string.Empty;
}
processingKey = false;
break;
}
case '{':
{
if (currentDelimeter.Length > 0)
{
delimeters.Add(currentDelimeter);
currentDelimeter = string.Empty;
}
processingKey = true;
break;
}
default:
{
if (processingKey)
{
currentKey += chr;
}
else
{
currentDelimeter += chr;
}
break;
}
}
}
if (currentDelimeter.Length > 0) delimeters.Add(currentDelimeter);
var lastDelim = -1;
// Find our Values based on the delimeter positions in the search string
for (int i = 0; i < delimeters.Count; i++)
{
var delimIndex = search.IndexOf(delimeters[i], lastDelim + 1);
if (delimIndex > -1)
{
var value = search.Substring(lastDelim + 1, delimIndex - lastDelim - 1);
results.Add(new KeyValuePair<string, string>(keys[i], value));
lastDelim = delimIndex + delimeters[i].Length - 1;
}
}
// Add the item after the final delimeter if it exists:
if (lastDelim > -1 && lastDelim < search.Length - 1)
{
results.Add(new KeyValuePair<string, string>(keys.Last(),
search.Substring(lastDelim + 1)));
}
return results;
}
And an example of it in action:
public static void Main(string[] args)
{
var results = GetKVPs(
"{greeting}, {recipient}, this is {sender}.",
"Hello, Dolly, this is Louis.");
foreach (var kvp in results)
{
Console.WriteLine($"{kvp.Key} = {kvp.Value}");
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output

Replace string if starts with string in List

I have a string that looks like this
s = "<Hello it´s me, <Hi how are you <hay"
and a List
List<string> ValidList= {Hello, hay} I need the result string to be like
string result = "<Hello it´s me, ?Hi how are you <hay"
So the result string will if it starts with an < and the rest bellogs to the list, keep it, otherwise if starts with < but doesn´t bellong to list replaces the H by ?
I tried using the IndexOf to find the position of the < and the if the string after starsWith any of the strings in the List leave it.
foreach (var vl in ValidList)
{
int nextLt = 0;
while ((nextLt = strAux.IndexOf('<', nextLt)) != -1)
{
//is element, leave it
if (!(strAux.Substring(nextLt + 1).StartsWith(vl)))
{
//its not, replace
strAux = string.Format(#"{0}?{1}", strAux.Substring(0, nextLt), strAux.Substring(nextLt + 1, strAux.Length - (nextLt + 1)));
}
nextLt++;
}
}
To give the solution I gave as a comment its proper answer:
Regex.Replace(s, string.Format("<(?!{0})", string.Join("|", ValidList)), "?")
This (obviously) uses regular expressions to replace the unwanted < characters by ?. In order to recognize those characters, we use a negative lookahead expression. For the example word list, this would look like this: (?!Hallo|hay). This will essentially match only if what we are matching is not followed by Hallo or hay. In this case, we are matching < so the full expression becomes <(?!Hallo|hay).
Now we just need to account for the dynamic ValidList by creating the regular expression on the fly. We use string.Format and string.Join there.
Something like this without using RegEx or LINQ
string s = "<Hello it´s me, <Hi how are you <hay";
List<string> ValidList = new List<string>() { "Hello", "hay" };
var arr = s.Split(new[] { '<' }, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < arr.Length; i++)
{
bool flag = false;
foreach (var item in ValidList)
{
if (arr[i].Contains(item))
{
flag = false;
break;
}
else
{
flag = (flag) ? flag : !flag;
}
}
if (flag)
arr[i] = "?" + arr[i];
else
arr[i] = "<" + arr[i];
}
Console.WriteLine(string.Concat(arr));
A possible solution using LINQ.It splits the string using < and checks if the "word" (text until a blank space found) following is in the Valid List,adding < or ? accordingly. Finally,it joins it all:
List<string> ValidList = new List<string>{ "Hello", "hay" };
string str = "<Hello it´s me, <Hi how are you <hay";
var res = String.Join("",str.Split(new char[] { '<' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => ValidList.Contains(x.Split(' ').First()) ? "<" + x : "?"+x));

check if string contains dictionary Key -> remove key and add value

I am stuck at a function which checks a string ('14534000000875e') if it contains a letter.
If it contains a letter (a-z), remove the letter and add a string to the end.
To realize this, I have created a Dictionary<char, string> Pairs which has mapped a to 09001, b to 09002 [...] and z to 09026
This is my code so far:
public static string AlterSerial(string source)
{
Dictionary<char, string> pairs = new Dictionary<char, string>();
pairs.Add('a', "09001");
...
int index = source.IndexOf(x);
if (index != -1)
{
return source.Remove(index, 1);
}
return source;
}
How can I check if the source string contains one of the 26 keys, delete this key and add the corresponding string to the end of the source-string?
Note: the letter is not always at the end of the source.
Kind regards
Try this:
Dictionary<char, string> pairs = new Dictionary<char, string>();
pairs.Add('a', "09001");
...
foreach(KeyValuePair<string, string> entry in pairs)
{
if (source.Contains(entry.Key)) // .Key must be capitalized
{
source = source.Replace(entry.Key, "") + entry.Value;
break;
}
}
return source;
....
So this is the solution where you have only one letter within your string. You need to find the letter that is within the string, if it exists, and find its index. Then you have to insert the respective value instead of the letter, obtained from the dictionary.
String mystring = "1453400e0000875";
Dictionary<char, string> pairs = new Dictionary<char, string>();
pairs.Add('a', "09001");
pairs.Add('b', "09002");
pairs.Add('c', "09003");
pairs.Add('d', "09004");
pairs.Add('e', "09005");
//...
char letter = mystring.FirstOrDefault(a => Char.IsLetter(a));
if (letter != '\0')
{
int index = mystring.IndexOf(letter);
string substitute;
pairs.TryGetValue(mystring[index], out substitute);
mystring = mystring.Substring(0, index) + substitute + mystring.Substring(index + 1);
}
EDIT:
Using Replace method of the string, the if part can be altered like this:
char letter = mystring.FirstOrDefault(a => Char.IsLetter(a));
if (letter != '\0')
{
string substitute;
pairs.TryGetValue(letter, out substitute);
mystring = mystring.Replace(letter.ToString(), substitute);
}
EDIT2:And if I didn't understand the OP correctly so that he wants to remove the letter and add the replacement string to the end of the source string, the if statement should be like this:
if (letter != '\0')
{
string substitute;
pairs.TryGetValue(letter, out substitute);
mystring = mystring.Replace(letter.ToString(), "");
mystring += substitute;
}
and this is the generalisation when you have more letters within the string. It is the similar solution but requires to iterate over all the letters within the string.
String mystring = "1453a400e0000b875";
Dictionary<char, string> pairs = new Dictionary<char, string>();
pairs.Add('a', "09001");
pairs.Add('b', "09002");
pairs.Add('c', "09003");
pairs.Add('d', "09004");
pairs.Add('e', "09005");
//...
var lettersList = mystring.Where(a => Char.IsLetter(a));
foreach (char letter in lettersList)
{
int index = mystring.IndexOf(letter);
string substitute;
pairs.TryGetValue(mystring[index], out substitute);
mystring = mystring.Substring(0, index) + substitute + mystring.Substring(index + 1);
}
Checked and it works!
Nikola's answer is good and if you like it you should mark it as the answer. However I like this simple method (slightly borrowed a few things :p).
var Alphabet = "abcdefghijklmnopqrstuvwxyz".ToArray();
var Pairs = new Dictionary<char, string>();
for(var i = 1; i < Alphabet.Count() +1; i++)
Pairs.Add(Alphabet[i-1], "090" + (i < 10 ? "0" + i.ToString() : i.ToString()));
var Source = "14534000000875e";
var Chars = Source.Where(x => Char.IsLetter(x));
var Output = string.Empty();
foreach(var Char in Chars)
Output = Source.Replace(Char.ToString(), Pairs[Char]);
or if you want the replacement at the end and only once for repeated chars?
foreach(var Char in Chars)
Output = Source.Replace(Char.ToString(),"") + (Pairs[Char]);

Dictionary with multiple keys isn't working as expected

I'm making a console program where I've got multiple values mapped to dictionary keyLookup. I'm using if commands that use the key to output some console.writeline = ("stuff"); but it only works if I have the value and the key the same (in the dictionary). I don't know why this is. I've been mucking about with list and foreach and some variables trying to figure out what I've done wrong but even though it continues to work how it works now it still doesn't work how I want.
Also if I have a word in my console.readline(); that isn't in my dictionary the whole thing crashes. Which I don't want, and I'm not sure of why its doing that either as at some point it didn't. Also my mathFunction dictionary works just how I want my keyLookup dictionary to work. Though I think the difference is in how I'm using a list to cross reference through keyLookup.
class MainClass
{
public static string Line;
static string foundKey;
public static void Main (string[] args)
{
while (true)
{
if (Line == null)
{Console.WriteLine ("Enter Input"); }
WordChecker ();
}
}
public static void WordChecker()
{
string inputString = Console.ReadLine ();
inputString = inputString.ToLower();
string[] stripChars = { ";", ",", ".", "-", "_", "^", "(", ")", "[", "]",
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "\n", "\t", "\r" };
foreach (string character in stripChars)
{
inputString = inputString.Replace(character, "");
}
// Split on spaces into a List of strings
List<string> wordList = inputString.Split(' ').ToList();
// Define and remove stopwords
string[] stopwords = new string[] { "and", "the", "she", "for", "this", "you", "but" };
foreach (string word in stopwords)
{
// While there's still an instance of a stopword in the wordList, remove it.
// If we don't use a while loop on this each call to Remove simply removes a single
// instance of the stopword from our wordList, and we can't call Replace on the
// entire string (as opposed to the individual words in the string) as it's
// too indiscriminate (i.e. removing 'and' will turn words like 'bandage' into 'bdage'!)
while ( wordList.Contains(word) )
{
wordList.Remove(word);
}
}
// Create a new Dictionary object
Dictionary<string, int> dictionary = new Dictionary<string, int>();
// Loop over all over the words in our wordList...
foreach (string word in wordList)
{
// If the length of the word is at least three letters...
if (word.Length >= 3)
{
// ...check if the dictionary already has the word.
if ( dictionary.ContainsKey(word) )
{
// If we already have the word in the dictionary, increment the count of how many times it appears
dictionary[word]++;
}
else
{
// Otherwise, if it's a new word then add it to the dictionary with an initial count of 1
dictionary[word] = 1;
}
}
List<string> dicList = new List<string>();
dicList = dictionary.Keys.ToList ();
Dictionary<string, string> keyLookup = new Dictionary<string, string>();
keyLookup["hey"] = "greeting";
keyLookup["hi"] = "greeting";
keyLookup["greeting"] = "greeting";
keyLookup["math"] = "math";
keyLookup["calculate"] = "math";
keyLookup["equation"] = "math";
foundKey = keyLookup[word];
List<string> keyList = new List<string>();
foreach (string keyWord in dicList)
{
if(keyWord == foundKey)
{keyList.Add (keyWord); }
}
foreach (string mKey in keyList)
{
if(mKey == "greeting")
{Greetings ();}
if (mKey == "math")
{Math ();}
}
}
}
public static void Math()
{
Console.WriteLine ("What do you want me to math?");
Console.WriteLine ("input a number");
string input = Console.ReadLine ();
decimal a = Convert.ToDecimal (input);
Console.WriteLine("Tell me math function");
string mFunction = Console.ReadLine();
Console.WriteLine ("tell me another number");
string inputB = Console.ReadLine();
decimal b = Convert.ToDecimal (inputB);
Dictionary<string, string> mathFunction = new Dictionary<string, string>();
mathFunction["multiply"] = "multiply";
mathFunction["times"] = "multiply";
mathFunction["x"] = "multiply";
mathFunction["*"] = "multiply";
mathFunction["divide"] = "divide";
mathFunction["/"] = "divide";
mathFunction["subtract"] = "subtract";
mathFunction["minus"] = "subtract";
mathFunction["-"] = "subtract";
mathFunction["add"] = "add";
mathFunction["+"] = "add";
mathFunction["plus"] = "add";
string foundKey = mathFunction[mFunction];
if (foundKey == "add")
{
Console.WriteLine (a + b);
}
else if (foundKey == "subtract")
{
Console.WriteLine (a - b);
}
else if (foundKey == "multiply")
{
Console.WriteLine (a * b);
}
else if (foundKey == "divide")
{
Console.WriteLine (a / b);
}
else
{
Console.WriteLine ("not a math");
}
}
public static void Greetings()
{
Console.WriteLine("You said hello");
}
}'
You should iterate through the dictionary differently (Dont use ToList-Function).
Try this instead:
foreach (KeyValuePair kvp (Of String, String) In testDictionary)
{
Debug.WriteLine("Key:" + kvp.Key + " Value:" + kvp.Value);
}
And your application is crashing if the word doesn't match, because of this code (You're not creating a new entry that way):
// Otherwise, if it's a new word then add it to the dictionary with an initial count of 1
dictionary[word] = 1;
EDIT: I was wrong about that dictionary[word] = 1 would not create a new element. It's perfectly fine like this.
foundKey = keyLookup[word];
If word doesn't exist in keyLookup then it will crash.
string foundKey = mathFunction[mFunction];
if mFunction doesn't exist in mathFunction then it will crash.
If you're trying to make this a "conversational" program, then the word look-up is the most important part. You don't use predicates or LINQ, both can make string functions extremely easy. Currently you use a Dictionary. Why not use Lists for each keyword?
List<string> GreetingKeywords;
GreetingKeywords.Add("hello"); // ...
List<string> MathKeywords;
MathKeywords.Add("math"); // ...
foreach (var word in dicList)
{
if (GreetingKeywords.Contains(word))
{ Greetings(); }
if (MathKeywords.Contains(word))
{ Maths(); }
}
I'd suggest you read up on predicate and List/Dictionary functions such as Find, IndexOf, etc. etc. That knowledge is invaluable to C#.

Splitting a string array

I have a string array string[] arr, which contains values like N36102W114383, N36102W114382 etc...
I want to split the each and every string such that the value comes like this N36082 and W115080.
What is the best way to do this?
This should work for you.
Regex regexObj = new Regex(#"\w\d+"); # matches a character followed by a sequence of digits
Match matchResults = regexObj.Match(subjectString);
while (matchResults.Success) {
matchResults = matchResults.NextMatch(); #two mathches N36102 and W114383
}
If you have the fixed format every time you can just do this:
string[] split_data = data_string.Insert(data_string.IndexOf("W"), ",")
.Split(",", StringSplitOptions.None);
Here you insert a recognizable delimiter into your string and then split it by this delimiter.
Forgive me if this doesn't quite compile, but I'd just break down and write the string processing function by hand:
public static IEnumerable<string> Split(string str)
{
char [] chars = str.ToCharArray();
int last = 0;
for(int i = 1; i < chars.Length; i++) {
if(char.IsLetter(chars[i])) {
yield return new string(chars, last, i - last);
last = i;
}
}
yield return new string(chars, last, chars.Length - last);
}
If you use C#, please try:
String[] code = new Regex("(?:([A-Z][0-9]+))").Split(text).Where(e => e.Length > 0 && e != ",").ToArray();
in case you're only looking for the format NxxxxxWxxxxx, this will do just fine :
Regex r = new Regex(#"(N[0-9]+)(W[0-9]+)");
Match mc = r.Match(arr[i]);
string N = mc.Groups[1];
string W = mc.Groups[2];
Using the 'Split' and 'IsLetter' string functions, this is relatively easy in c#.
Don't forget to write unit tests - the following may have some corner case errors!
// input has form "N36102W114383, N36102W114382"
// output: "N36102", "W114383", "N36102", "W114382", ...
string[] ParseSequenceString(string input)
{
string[] inputStrings = string.Split(',');
List<string> outputStrings = new List<string>();
foreach (string value in inputstrings) {
List<string> valuesInString = ParseValuesInString(value);
outputStrings.Add(valuesInString);
}
return outputStrings.ToArray();
}
// input has form "N36102W114383"
// output: "N36102", "W114383"
List<string> ParseValuesInString(string inputString)
{
List<string> outputValues = new List<string>();
string currentValue = string.Empty;
foreach (char c in inputString)
{
if (char.IsLetter(c))
{
if (currentValue .Length == 0)
{
currentValue += c;
} else
{
outputValues.Add(currentValue);
currentValue = string.Empty;
}
}
currentValue += c;
}
outputValues.Add(currentValue);
return outputValues;
}

Categories