C# encrypt string - c#

I got the following code to encrypt a string.
private void Crypt(int n, int m, int d)
{
n = Convert.ToInt32(n);
m = Convert.ToInt32(m);
d = Convert.ToInt32(d);
// make a block from the string
string invoerstring = invoer.Text;
int stringlength = invoerstring.Length;
var blok = invoer.Text.PadRight(stringlength, ' ').Substring(0, stringlength);
// the letters are shifted d times
char [] buf = invoerstring.ToArray<char>();
foreach (char c in buf)
{
var letter = uitvoer.Text += (char)( c + (char)d);
}
// shift characters inside a block
var shift = String.Concat(invoerstring.Skip(m).Concat(invoerstring.Take(m)));
uitvoer.Text = shift;
}
private void button1_Click(object sender, EventArgs e)
{
Crypt(8,2,1);
}
private void clearbutton_Click(object sender, EventArgs e)
{
invoer.Text = "";
uitvoer.Text = "";
}
}
}
This is the explanation of the exercise:
crypt n m d text
text is padded with spaces until its length is a multiple of n
the characters in text are circulary shifted in the alphabet by the displacement d
example: if d = 1 then 'a' -> 'b' , 'b' -> 'c' .... etc... 'z' -> 'a'
text is divided in blocks of length n characters
inside every block of n the characters are circulary shifted m times to the left
the shifted groups are concatenated
When I run my code the letters aren't shifted d times. For example the string:
"aap noot mies" has to change to "q oppubbjft n" (When Crypt is Crypt(8,2,1)). What do I need to change to get this result?

You have many problems/oddities:
You're Converting a bunch of ints to Int32s, but the former is just syntatic sugar for the latter.
Your PadRight call is going to return the initial string since the length you pass is equal to the length of the string.
Your Substring call is going to return the initial string.
You never use blok.
You never actually split the input into blocks or pad it.
string already implements IEnumerable (a fact you're already implicitly using), so there's no need to convert it to an array just to loop over it.
You never use letter.
(char)( c + (char)d) does not implement the Caeser cipher you're looking for, you'll end up converting some letters into non-letters (except in one degenerate case).
You're concatenating the result of the shift into uitvoer.Text (without clearing it) and then overwriting it later without using it.
You're calling the single parameter static version of Concat (which converts the object it's passed into a string) and passing it a string.
Start by fixing the ones you know how to do and edit the question if you get stuck.

Related

How to skip values in Random.Range? In Unity/C#?

facing issue with randomising the randomLetter for non latin script. in my script, in the unicode characters table, 4 unicode values are non existent. need to skip those characters while Random.Range() is running. what is the workaround? declare an array? or declare a list? or something else? please help.
Working code for Latin script:
{
private void OnEnable()
{
var i = UnityEngine.Random.Range(0, 26);
_randomLetter = (char) ('a' + i);
GetComponent<TMP_Text>().text = _randomLetter.ToString();
}
Bengali script code:
private void OnEnable()
{
var i = UnityEngine.Random.Range(0, 16); //12 vowels in bengali but here 16 as range including non-existent values
_randomLetter = (char) ('অ' + i);
GetComponent<TMP_Text>().text = _randomLetter.ToString();
}
easiest way is to build a list of all the allowed characters, and generate a random index into this list. Note that a string can be used like a list of characters.
const string allowedCharacters = "abe";
var randomIndex = UnityEngine.Random.Range(0,allowedCharacters.Length);
var randomCharacter = allowedCharacters[randomIndex];
Another easy way is to use rejection sampling

Why wont this loop end? I've looked at it for ages and can't find the problem

Console.Write("Enter a string to encode: ");
string input = Console.ReadLine();
Random r = new Random();
char[] characters = " ~!##$%^&*()_+=-0987654321`{}|\\][\"';:/?.>,<QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".ToCharArray();
string method = "";
bool f = true;
while (method.Length != characters.Length)
{
string cc = "";
while (method.Contains(cc) || f)
{
cc = characters[r.Next(0, characters.Length - 1)].ToString();
f = false;
// Console.WriteLine(method.Length);
// Console.WriteLine(characters.Length);
}
method = method + cc;
}
I'm trying to make method's value a randomized version of the characters array.
I've looked at this for a while and I haven't found the problem.
Compiling the code and printing the length of the two variables shows that method is always 1 less character than characters's length
It might be obvious to some, although I'm absolutely scrambled.
Any help would be appreciated, thanks.
The second parameter of Random.Next is an exclusive upper bound. You need this:
cc = characters[r.Next(0, characters.Length)].ToString();
Now, just as a side-note, to create a string that is a random shuffle of the array characters you can do it this way:
string method = new string(characters.OrderBy(_ => r.Next()).ToArray());
As enigmativity points out the second argument of Random.Next is an exclusive upper bound, meaning the function Random.Next(0, N) will return a value between 0 and N-1.
Therefore, after numerous random samples your code will eventually be set to method to contain all characters except m because m is the char at index characters.length-1.
To accomplish your task:
Change cc = characters[r.Next(0, characters.Length - 1)].ToString(); to cc = characters[r.Next(0, characters.Length)].ToString();
Also, note that as you have fewer and fewer characters left that you have not yet chose, you will be picking many random characters you have already chose which is inefficient. Worse, the algorithm runs an outer loop which requires an array search to see if you have already chosen the character. This repeats until by random chance a character is selected that has not been chosen.
To address the issues in 2), simply keep a list of unused characters. As you randomly select each characters remove it from the list of unused characters. This will allow your algorithm to complete in 0(N) time where N is the length of total characters.
Here is example code:
Console.Write("Enter a string to encode: ");
string input = Console.ReadLine();
Random r = new Random();
char[] characters = " ~!##$%^&*()_+=-0987654321`{}|\\][\"';:/?.>,<QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm".ToCharArray();
string method = "";
bool f = true;
var unused = characters.ToList();
while (method.Length != characters.Length)
{
char cc = unused[r.Next(0, unused.Count)];
method = method + cc;
unused.Remove(cc);
}
https://stackoverflow.com/users/259769/enigmativity

Regular expression to allow a set of characters that are repeated different times

I'm new on regex and for learning purpose, i'm coding a word finding program. It takes a pool of characters and when i press "find" button, it lists all possible words from that character set. Looping in word list, the program compares each word with regex pattern.
Inside that, i wrote a simple pattern to make it work. for example:
^[mase]+$
but it doesn't work properly.
brief explation and what i try to achieve, with one example below :
if the char pool is ahbbhhh then i want to match words which contain a minimum of one a, h, or b AND a maximum of 1 a, 4 h's, and 2 b's. it shouldn't contain any other characters.
I don't think RegEx would support this.
However its a simple test on any programming language.
Here is an example on C#:
private Dictionary<char, int> WordToChars(string word)
{
var result = new Dictionary<char, int>();
foreach (var c in word)
{
if (result.ContainsKey(c))
{
result[c] += result[c] + 1;
}
else
{
result[c] = 1;
}
}
return result;
}
private bool DoesMatchPattern(string patternString, string testString)
{
var pattern = WordToChars(patternString);
var test = WordToChars(testString);
return test.All(x => pattern.TryGetValue(x.Key, out int qty) && qty >= x.Value);
}
In few words: WordToChar() converts any string to characters with repeated quantities.
And DoesMatchPattern() compares that test string has only chars found in pattern string and corresponding repeated qty is less or equal to the pattern.

how to add a sign between each letter in a string in C#?

I have a task, in which i have to write a function called accum, which transforms given string into something like this:
Accumul.Accum("abcd"); // "A-Bb-Ccc-Dddd"
Accumul.Accum("RqaEzty"); // "R-Qq-Aaa-Eeee-Zzzzz-Tttttt-Yyyyyyy"
Accumul.Accum("cwAt"); // "C-Ww-Aaa-Tttt"
So far I only converted each letter to uppercase and... Now that I am writing about it, I think it could be easier for me to - firstly multiply the number of each letter and then add a dash there... Okay, well let's say I already multiplied the number of them(I will deal with it later) and now I need to add the dash. I tried several manners to solve this, including: for and foreach(and now that I think of it, I can't use foreach if I want to add a dash after multiplying the letters) with String.Join, String.Insert or something called StringBuilder with Append(which I don't exactly understand) and it does nothing to the string.
One of those loops that I tried was:
for (int letter = 0; letter < s.Length-1; letter += 2) {
if (letter % 2 == 0) s.Replace("", "-");
}
and
for (int letter = 0; letter < s.Length; letter++) {
return String.Join(s, "-");
}
The second one returns "unreachable code" error. What am I doing wrong here, that it does nothing to the string(after uppercase convertion)? Also, is there any method to copy each letter, in order to increase the number of them?
As you say string.join can be used as long as an enumerable is created instead of a foreach. Since the string itself is enumerable, you can use the Linq select overload which includes an index:
var input = "abcd";
var res = string.Join("-", input.Select((c,i) => Char.ToUpper(c) + new string(Char.ToLower(c),i)));
(Assuming each char is unique or can be used. e.g. "aab" would become "A-Aa-Bbb")
Explanation:
The Select extension method takes a lambda function as parameter with c being a char and i the index. The lambda returns an uppercase version of the char (c) folowed by a string of the lowercase char of the index length (new string(char,length)), (which is an empty string for the first index). Finally the string.join concatenates the resulting enumeration with a - between each element.
Use this code.
string result = String.Empty;
for (int i = 0; i < s.Length; i++)
{
char c = s[i];
result += char.ToUpper(c);
result += new String(char.ToLower(c), i);
if (i < s.Length - 1)
{
result += "-";
}
}
It will be better to use StringBuilder instead of strings concatenation, but this code can be a bit more clear.
Strings are immutable, which means that you cannot modify them once you created them. It means that Replace function return a new string that you need to capture somehow:
s = s.Replace("x", "-");
you currently are not assigning the result of the Replace method anywhere, that's why you don't see any results
For the future, the best way to approach problems like this one is not to search for the code snippet, but write down step by step algorithm of how you can achieve the expected result in plain English or some other pseudo code, e.g.
Given I have input string 'abcd' which should turn into output string 'A-Bb-Ccc-Dddd'.
Copy first character 'a' from the input to Buffer.
Store the index of the character to Index.
If Buffer has only one character make it Upper Case.
If Index is greater then 1 trail Buffer with Index-1 lower case characters.
Append dash '-' to the Buffer.
Copy Buffer content to Output and clear Buffer.
Copy second character 'b' from the input to Buffer.
...
etc.
Aha moment often happens on the third iteration. Hope it helps! :)

Calculate variations on a string

I have a series of incorrectly encoded base36 values - these were encoded from integers using a string of letters, missing the "i" and "o". They now need to be converted back to integers using C#.
There are multiple permutations because of the rollover effect.
"0" can either equal 0 or 34;
"1" can either equal 1 or 35.
So, for instance, if I have a string "a110", it has six possible values.
I'm having a hard time trying to figure how to code for this.
All the examples I've looked at compute variations for a set of elements, for example
char[] = { a, b, c }
int[] = { 1, 2, 3 }
However, in my case, there are conditionals involved too, and it's making my head hurt. Can anyone help?
You can compute the list of all possible input strings. First, read the input into a list of ints. Now, you know that each of those (if it's a sufficiently low value) could be one of two things. So then you can create an enumerator that returns all of the possible inputs, via a recursive descent.
I managed to do it with the following code. It was actually a little simpler than I expected, since I only had two conditions, and two options. It uses recursion and steps through each character in the string. If that character is a 0 or 1, it then diverges, and continues building the string.
It actually generates a few duplicates, so I had to add a condition to only add it to the string list if it doesn't already exist. If someone else can point me to slightly better logic I'd appreciate it
public string st = "101"; // hardcoded for now
public char[] cs;
public List<string> variations;
static void Main()
{
cs = st.ToCharArray();
variations = new List<string>();
vary("",0);
}
static void vary(string m, int n)
{
for (int i = n; i < cs.Count(); i++)
{
if (cs[i] == '0' || cs[i] == '1')
{
// recurse
combo(m + (cs[i] == '0' ? "0" : "1"), i + 1);
combo(m + (cs[i] == '0' ? "Y" : "Z"), i + 1);
}
m += cs[i];
}
if(!variations.Contains(m))
variations.Add(m);
}
for the string "101" I get the following combinations
101
10Z
1Y1
1YZ
Z01
Z0Z
ZY1
ZYZ

Categories

Resources