I need to convert the characters a, e, i, o, u in the user input string to the assigned symbols. Below is what I have so far.
School assignment
First prompt the user for the encrypted text string. Validate that this is not left blank. Send this text string into a custom method you will create that will decipher it. Once it is deciphered, return this text string to the main where you will output both the encrypted and decrypted strings.
To decipher the text string you must perform the following character replacements:
# = a
# = e
^ = i
* = o
+ = u
My current code
public static string Decipher (string code)
{
char[] array = code.ToCharArray();
for (int i = 0; i < code.Length; i++)
{
if (code.Contains("#") && code.Contains("#") && code.Contains("^") &&
code.Contains("*") && code.Contains("+"))
{
}
}
Every time you go through this for loop, it will evaluate true if the string contains #, #, ^, * and + anywhere in the string. So if your string is missing any of these symbols, your if statement will evaluate to false and nothing will happen.
Luckily you can simplify this pretty easily. One way you can do this is to convert your string to a char[] array and break your logic into multiple if-else statements, or a single switch statement, for example:
public static string Decipher (string code)
{
char[] codeArray = code.ToCharArray(); // convert your code string to a char[] array
for (int i = 0; i < codeArray.Length; i++)
{
switch (codeArray[i]) // Get the char at position i in the array
{
case '#': // if the character at i is '#'
codeArray[i] = 'a'; // Change the character at i to 'a'
break; // break out of the switch statement - we don't need to evaluate anything else
case '#': // if the character at i is '#'
codeArray[i] = 'e'; // Change the character at i to 'e'
break; // break out of the switch statement - we don't need to evaluate anything else
// repeat for everything else you need to replace!
}
}
return new String(codeArray); // Once you're all done, create a string from your deciphered array and return it
}
There are a bunch of different ways of doing it. Doing string concatenation in a loop (as shown by #Acex) is generally frowned upon; it spins out a lot of "garbage" and can slow things down. The Stringbuilder class is generally a better option. My code uses Stringbuilders (well, the same one over and over - I clear it in between).
Here are several ways of doing the same thing:
const string encoded = "H#ll*, H*w #r# y*+?";
//good old fashioned C-style/brute force:
var buf = new StringBuilder();
foreach (var c in encoded){
switch(c){
case '#':
buf.Append('a');
break;
case '#':
buf.Append('e');
break;
case '^':
buf.Append('i');
break;
case '*':
buf.Append('o');
break;
case '+':
buf.Append('u');
break;
default:
buf.Append(c);
break;
}
}
var result = buf.ToString();
//using a lookup table (easily extensible)
buf.Clear();
var decodeDict = new Dictionary<char, char>{
{'#', 'a'},
{'#', 'e'},
{'^', 'i'},
{'*', 'o'},
{'+', 'u'},
};
foreach (var c in encoded){
if (decodeDict.Keys.Contains(c)){
buf.Append(decodeDict[c]);
} else {
buf.Append(c);
}
}
result = buf.ToString();
//something completely different
//instead of iterating through the string, iterate through the decoding dictionary
buf.Clear();
var working = new StringBuilder(encoded.Length);
working.Append(encoded);
foreach (var pair in decodeDict){
working.Replace(pair.Key, pair.Value);
}
result = working.ToString();
In each case, result holds, well, the result. Put a breakpoint right after each result assignment and see what's happened.
I'm not providing a lot of comments, step through the code, look up the classes and figure out what I'm doing (you are the student, after all).
It's really as simple as doing this:
public static string Decipher(string code)
{
var map = new Dictionary<char, char>()
{
{ '#', 'a' },
{ '#', 'e' },
{ '^', 'i' },
{ '*', 'o' },
{ '+', 'u' },
};
char[] array = code.ToCharArray();
array = array.Select(x => map.ContainsKey(x) ? map[x] : x).ToArray();
return new string(array);
}
Now you can do this:
string cipher = "*+tp+t";
string plain = Decipher(cipher);
Console.WriteLine(cipher);
Console.WriteLine(plain);
This outputs:
*+tp+t
output
For the sake of alternative
And when you will be allowed to use existing methods.
you can write something like this:
private Dictionary<char, char> mapping = new Dictionary<char, char>()
{
{ '#', 'a' },
{ '#', 'e' },
{ '^', 'i' },
{ '*', 'o' },
{ '+', 'u' },
};
private string Decrypt(string encryptedString) =>
string.Concat(encryptedString.Select(s => mapping.ContainsKey(s) ? mapping[s] : s));
And usage:
string result = Decrypt(encryptedString);
References: DotNetFiddle Example
Related
Whilst working on a simple project I was trying to come up with a very basic cryptographic system which will allow me to switch letters in a message to another pre-chosen letter. So far I have tried a few ways but have so far been unsuccessful in my attempts. (*NOTE: This is not for anything other then learning the basics of c# so randomness and security is not important in this case, I simply want to turn one letter into another for the sake of learning how to do it)
so first I started by defining some strings such as this
string a = "a";
string b = "b";
string c = "d";
..... //continues to string z = "z"
next I tried to create a new string based on the values that have been input in to a textbox called PlainTextBox and place them inside a separate textbox called ChangedTextBox. this code is triggered with a button click event.
string str = PlainTextBox.Text;
char[] array = str.ToCharArray();
array[int.Parse(a)] = 'x';
array[int.Parse(b)] = 'y';
array[int.Parse(c)] = 'z';
.......// continues to (z)
str = new string(array);
ChangedTextBox.Text = str;
but this code throws an exception because the input is not a valid integer. the basic Idea is that if the user types "abc" in the PlainTextBox and pushes a button, the ChangedTextBox should show "xyz" but should be inclusive of the whole text in PlainTextBox, switching every letter in the message to its chosen counterpart.
Besides the error I receive, this code seems very cumbersome and inefficient.
Is there a faster way to achieve this result?
Just for completeness I will also include information, that what you are doing is called Caesar cipher
You could define yourself a proper Dictionary
var mapping = new Dictionary<char, char>()
{
{ 'a', 'x' },
{ 'b', 'y' },
{ 'c', 'z' }
// other letters
}
in which you would assign every original letter the letter it should be converted to. Then you could use this dictionary
ChangedTextBox.Text = new string(PlainTextBox.Text.Select(letter => mapping[letter].ToArray());
You've chosen wrong collection type (array) for mapping; dictionary is much more convenient
private static Dictionary<char, char> m_Mapping = new Dictionary<char, char>() {
{'a', 'x'}, // a -> x
{'b', 'y'}, // b -> y
...
};
Then implement the encoding
// I'd rather used Linq
private static String Encode(String value) {
// Simplest: we don't check if the actual character can be mapped
return String.Concat(value.Select(c => m_Mapping[c]));
}
But your (amended) implementation is good enough:
private static String Encode(string str) {
char[] array = str.ToCharArray();
for (int i = 0; i < array.Length; ++i) {
// Simplest: we don't check if the actual character can be mapped
array[i] = m_Mapping[array[i]];
}
return new string(array);
}
Finally, add up UI:
ChangedTextBox.Text = Encode(PlainTextBox.Text);
Edit: in general case, when m_Mapping doesn't contain records for some characters (e.g. for new line \n) and so we want to preserve these characters intact we can't use direct m_Mapping[...] but should implement, say, EncodeChar.
private static char EncodeChar(char value) {
char result;
if (m_Mapping.TryGetValue(value, out result))
return result;
else
return value;
}
And put EncodeChar(...) instead of m_Mapping[...]
private static String Encode(String value) {
return String.Concat(value.Select(EncodeChar(c)));
}
Your version
private static String Encode(string str) {
char[] array = str.ToCharArray();
for (int i = 0; i < array.Length; ++i) {
array[i] = EncodeChar(array[i]);
return new string(array);
}
Probably the best solution is using a Dictionary, as other answers had said. But if I understand what you want, you want to just change one letter by that letter plus an offset in a kind of "circular" way. This solution would do something like that (with "abcd" as input it would return "xyza"):
string input = "abcd";
char startChar = 'x';
char lastChar = 'z';
char firstChar = 'a';
byte[] asciiBytes=Encoding.ASCII.GetBytes(input);
byte[] encriptedByteArray = new byte[asciiBytes.Length];
int val = (int)startChar-(int)firstChar;
int i = 0;
foreach(byte b in asciiBytes)
{
var a=b + val;
if (a>(int)lastChar)
{
a = firstChar+(a-lastChar)-1;
}
encriptedByteArray[i] = (byte)a;
i++;
}
string encriptedArray = System.Text.Encoding.UTF8.GetString(encriptedByteArray);
With this solution you can change the offsety easily (changing startChar). It has room for improvement though, for example it only works on lower letters from a-z, it could be changed to be more extensive.
int.Parse(a)
will of course throw InvalidCastException because a is a string as you've defined it
string a = "a";
I have a string function in which i have to check multiple characters. My code is
if(str.Contains("R") || str.Contains("f") || str.Contains("W") )
{
string letter= "";
}
My question is if string contains R then it has to be stored in letter variable, if f contains it has to be stored. How can I achieve it by not using multiple if conditions??
You could use string.IndexOfAny to find the position of one of the letters
int pos = str.IndexOfAny(new char[] {'R','f','W'});
if(pos >= 0)
{
string letter = str[pos].ToString();
....
}
Perhaps you want something like this?
string str = "abcRefg";
var letters = new[] { "R", "f", "W" };
string foundLetter = null;
foreach (var letter in letters)
{
if (str.Contains(letter))
{
foundLetter = letter;
break;
}
}
Since you need to know which characters str contains, you can use the Enumerable.Intersect extension method.
char[] characters = {'R', 'f', 'W'};
var common = str.Intersect(characters).ToList();
foreach(char c in common)
{
}
I want to make a program which takes a string you entered and turn it to different string, so if for example I input "Hello World" every char will turn into a string and the console will output something like "Alpha Beta Gamma Gamma Zeta Foxtrot Dona Rama Lana Zema" - making every char a word.
I tried doing it like this :
static string WordMap(string value)
{
char[] buffer = value.ToCharArray();
for (int i = 0; i < buffer.Length; i++)
{
if (letter = "a")
{
letter = ("Alpha");
}
//and so on
buffer[i] = letter;
}
return new string(buffer);
}
but I just can't get it to work.
can anyone give me a tip or point me at the right direction?
What you need is a Dictionary<char,string>
var words = new Dictionary<char, string>();
words.Add('a', "Alpha");
words.Add('b',"Beta");
...
string input = Console.ReadLine();
string[] contents = new string[input.Length];
for (int i = 0; i < input.Length; i++)
{
if (words.ContainsKey(input[i]))
{
contents[i] = words[input[i]];
}
}
string result = string.Join(" ", contents);
Or LINQ way:
var result = string.Join(" ", input.Where(words.ContainsKey).Select(c => words[c]));
First off, the buffer is a char array. Arrays have a fixed size and to expand them you need to create a new one. To overcome this cumbersome work, there is a StringBuilder class that does this automatically.
Secondly, if you keep these 'Alpha', 'Beta', ... strings in if statements you will have a very long piece of code. You can replace this by using a dictionary, or create it from a single string or text file.
To put this into practice:
class MyClass
{
static Dictionary<char, string> _map = new Dictionary<char, string>();
static MyClass()
{
_map.Add('a', "Alpha");
_map.Add('b', "Beta");
// etc
}
static string WordMap(string data)
{
var output = new StringBuilder();
foreach (char c in data)
{
if (_map.ContainsKey(c))
{
output.Append(_map[c]);
output.Append(' ');
}
}
return output.ToString();
}
}
Solution without a dictionary:
static string WordMap(string data)
{
const string words = "Alpha Beta Gamma Delta ...";
string[] wordMap = words.Split(' ');
var output = new StringBuilder();
foreach (char c in data)
{
int index = c - 'a';
if (index >= 0 && index < wordMap.Length)
{
output.Append(wordMap[index]);
output.Append(' ');
}
}
return output.ToString();
}
With LINQ and String.Join it's short and readable. Since you want to have a new word for special chards you need a word-map. I would use a Dictionary<char, string>:
static Dictionary<char, string> wordMap = new Dictionary<char, string>()
{
{'a', "Alpha"}, {'b', "Beta"},{'c', "Gamma"}, {'d', "Delta"}
};
static string WordMap(string value)
{
var strings = value
.Select(c =>
{
string word;
if(!wordMap.TryGetValue(c, out word))
word = c.ToString();
return word;
});
return string.Join("", strings);
}
Test:
string newString = WordMap("abcdeghj"); // AlphaBetaGammaDeltaeghj
Tips:
You don't have to create character array from string, you can easily access single characters in string by indexer:
char some = "123"[2];
When you use "" then you create string not char therefore you should use '' to create character for comparison:
if (some == 'a') Console.WriteLine("character is a, see how you compare chars!!!");
A good solution ...
string[] words = { "Alpha", "Beta", "C_word", "D_Word" }; // ....
string myPhrase = "aBC";
myPhrase.Replace(" ", string.Empty).ToList().ForEach(a =>
{
int asciiCode = (int)a;
/// ToUpper()
int index = asciiCode >= 97 ? asciiCode - 32 : asciiCode;
Console.WriteLine(words[index - 65]); // ascii --> 65-a , 66-b ...
});
One more variation of answer which contains not found option.
static Dictionary<char, string> Mapping =
new Dictionary<char, string>()
{ { 'a', "alpha" }, { 'b', "beta" }, { 'c', "gamma" }, { 'd', "zeta" } };
static void Main(string[] args)
{
string test = "abcx";
Console.WriteLine(string.Join(" ", test.Select(t => GetMapping(t))));
//output alpha beta gamma not found
Console.ReadKey();
}
static string GetMapping(char key)
{
if (Mapping.ContainsKey(key))
return Mapping.First(a => a.Key == key).Value;
else
return "not found";
}
Just declare a second variable where you build up your result.
And I think you have some syntax problems, you need to have "==" in a
condition, otherwise it's an assignment.
static string WordMap(string value)
{
string result = string.Empty;
char[] buffer = value.ToCharArray();
for (int i = 0; i < buffer.Length; i++)
{
if (letter == "a")
{
result += ("Alpha");
}
//and so on
}
return result;
}
But I would only do this that way, if this is "just for fun" code,
as it will not be very fast.
Building up the result like I did is slow, a better way would be
result = string.Concat(result, "(Alpha)");
And an even faster way is using a StringBuilder (s. documentation for that),
which offers you fast and convenient methods to deal with bigger strings.
Only downfall here is, that you need to know a little bit, how big the result
will be in characters, as you need to provide a starting dimension.
And here you should not start with simply 1, or 100. Each time, when the StringBuilder
is full, it creates a new bigger instance and copies the values, so multiple instances
of that will fill your memory, which can cause an out of memory exception,
when dealing with some ten thousands of characters.
But as said, for just for fun code, all of that does not matter...
And of course, you need to be aware, that if you do it like that, your result will
be in one straight line, no breaks. If you want line breaks add "\n" at the end of
the strings. Or add anything elese you need.
Regards,
Markus
I have a app and in this app it is possible with a function to replace some characters in a word with a other character
var newCharacter = "H";
if (/*something happens here and than the currentCharacter will be replaced*/)
{
// Replace the currentCharacter in the word with a random newCharacter.
wordString = wordString.Replace(currentCharacter, newCharacter);
}
now all the characters will be replaced with the code above with the "H". But i want more letters so by example the H, E, A, S
what is the best way to do this?
When i do this:
var newCharacter = "H" + "L" + "S";
it replaced the currentCharacter with H AND L AND S but i just want it to replace with H OR L OR S not all three
so if you have a word with HELLO and you want to replace the O with the newCharacter my output now is HELLHLS
O -> HLS
but O needs to be -> H or L or S
Here is a way to do using LINQ.You can add the characters you want to remove in the array excpChar
char[] excpChar= new[] { 'O','N' };
string word = "LONDON";
var result = excpChar.Select(ch => word = word.Replace(ch.ToString(), ""));
Console.WriteLine(result.Last());
The Replace function replaces all the occurences at once, this is not what we want. Let's do a ReplaceFirst function, only replacing the first occurence (one could make an extension method out of this):
static string ReplaceFirst(string word, char find, char replacement)
{
int location = word.IndexOf(find);
if (location > -1)
return word.Substring(0, location) + replacement + word.Substring(location + 1);
else
return word;
}
Then we can use a random generator to replace the target letter with different letters through successive calls of ReplaceFirst:
string word = "TpqsdfTsqfdTomTmeT";
char find = 'T';
char[] replacements = { 'H', 'E', 'A', 'S' };
Random random = new Random();
while (word.Contains(find))
word = ReplaceFirst(word, find, replacements[random.Next(replacements.Length)]);
word now may be EpqsdfSsqfdEomHmeS or SpqsdfSsqfdHomHmeE or ...
You can do like following :
string test = "abcde";
var result = ChangeFor(test, new char[] {'b', 'c'}, 'z');
// result = "azzde"
with ChangeFor :
private string ChangeFor(string input, IEnumerable<char> before, char after)
{
string result = input;
foreach (char c in before)
{
result = result.Replace(c, after);
}
return result;
}
I'm using asp.net 4 and c#.
I have a string that can contains:
Special Characters, like: !"£$%&/()/#
Accented letters, like: àòèù
Empty spaces, like: " "(1 consecutive or more),
Example string:
#Hi this is rèally/ special strìng!!!
I would like to:
a) Remove all Special Characters, like:
Hi this is rèally special strìng
b) Convert all Accented letters to NON Accented letters, like:
Hi this is really special string
c) Remove all Empty spaces and replace theme with a dash (-), like:
Hi-this-is-really-special-string
My aim is to creating a string suitable for URL path for better SEO.
Any idea how to do it with Regular Expression or another techniques?
Thanks for your help on this!
Similar to mathieu's answer, but more custom made for you requirements. This solution first strips special characters and diacritics from the input string, and then replaces whitespace with dashes:
string s = "#Hi this is rèally/ special strìng!!!";
string normalized = s.Normalize(NormalizationForm.FormD);
StringBuilder resultBuilder = new StringBuilder();
foreach (var character in normalized)
{
UnicodeCategory category = CharUnicodeInfo.GetUnicodeCategory(character);
if (category == UnicodeCategory.LowercaseLetter
|| category == UnicodeCategory.UppercaseLetter
|| category == UnicodeCategory.SpaceSeparator)
resultBuilder.Append(character);
}
string result = Regex.Replace(resultBuilder.ToString(), #"\s+", "-");
See it in action at ideone.com.
You should have a look a this answer : Ignoring accented letters in string comparison
Code here :
static string RemoveDiacritics(string sIn)
{
string sFormD = sIn.Normalize(NormalizationForm.FormD);
StringBuilder sb = new StringBuilder();
foreach (char ch in sFormD)
{
UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch);
if (uc != UnicodeCategory.NonSpacingMark)
{
sb.Append(ch);
}
}
return (sb.ToString().Normalize(NormalizationForm.FormC));
}
I am not an expert when it comes to RegularExpressions but I doubt it would be useful for this sort of computation.
To me, a simple iteration over the characters of the input is enough:
List<char> specialChars =
new List<char>() { '!', '"', '£', '$', '%', '&', '/', '(', ')', '/', '#' };
string specialString = "#Hi this is rèally/ special strìng!!!";
System.Text.StringBuilder builder =
new System.Text.StringBuilder(specialString.Length);
bool encounteredWhiteSpace = false;
foreach (char ch in specialString)
{
char val = ch;
if (specialChars.Contains(val))
continue;
switch (val)
{
case 'è':
val = 'e'; break;
case 'à':
val = 'a'; break;
case 'ò':
val = 'o'; break;
case 'ù':
case 'ü':
val = 'u'; break;
case 'ı':
case 'ì':
val = 'i'; break;
}
if (val == ' ' || val == '\t')
{
encounteredWhiteSpace = true;
continue;
}
if (encounteredWhiteSpace)
{
builder.Append('-');
encounteredWhiteSpace = false;
}
builder.Append(val);
}
string result = builder.ToString();