I'm trying to make a Caesar cipher program, however I am unable to remove the spaces from the final encrypted output. I used:
if (letter == ' ')
continue;
However this seems to not be working and I can't identify what is causing the issue. I haven't been working with C# very long so it may potentially be a stupid error.
If I was to input the phrase with a shift of 7: "I need help" the following output would be pAullkAolsw with all spaces becoming uppercase A. The output I wish to have should be in the example: p ullk olsw.
Below is my full code:
using System;
class Program
{
static string Caesar(string value, int shift)
{
char[] buffer = value.ToCharArray();
for (int i = 0; i < buffer.Length; i++)
{
char letter = buffer[i];
letter = (char)(letter + shift);
if (letter == ' ')
continue;
if (letter > 'z')
{
letter = (char)(letter - 26);
}
else if (letter < 'a')
{
letter = (char)(letter + 26);
}
buffer[i] = letter;
}
return new string(buffer);
}
static void Main()
{
Console.WriteLine("Enter text to encrypt: ");
string buffer = Console.ReadLine();
Console.WriteLine("Enter value of shift: ");
int shift = int.Parse(Console.ReadLine());
string final = Caesar(buffer, shift);
Console.WriteLine(final);
}
}
If you want to skip spaces you just have to check before you transform the letter variable:
char letter = buffer[i];
if (letter == ' ')
continue;
letter = (char)(letter + shift);
// ...
You should encrypt if and only if you know how to do it (i.e. if you have a a..z or A..Z character); in case you have different character (space, minus sign, quotation mark, whatever), just leave it intact:
using System.Linq;
...
static string Caesar(string value, int shift) {
//DONE: do not forget about validation
if (null == value)
return value; // or throw exception (ArgumentNullValue)
int n = 'z' - 'a' + 1;
// For each character in the value we have three cases:
// a..z letters - encrypt
// A..Z letters - encrypt
// other letters - leave intact
// "n + shift % n) % n" - let's support arbitrary shifts, e.g. 2017, -12345 etc.
return string.Concat(value
.Select(c =>
c >= 'a' && c <= 'z' ? (char) ('a' + (c - 'a' + n + shift % n) % n)
: c >= 'A' && c <= 'Z' ? (char) ('A' + (c - 'A' + n + shift % n) % n)
: c));
}
Test:
Console.Write(Caesar("Hello! It's a test for so called 'Caesar cipher'.", -2));
Outcome (please, notice that spaces, apostrophes, exclamation mark are left as they were):
Fcjjm! Gr'q y rcqr dmp qm ayjjcb 'Aycqyp agnfcp'.
Related
I am trying to solve a problem in C#.
Here is the task:
If a word begins with a vowel (a, e, i, o, u or A, E, I, O, U), remove
the first letter and append it to the end, then add "che". If you have
the word “orange” It translates to “rangeoche”
If a word begins with a consonant (i.e. not a vowel), append "che" to the end of the word. For example, the word "chicken" becomes
"chickenche".
If the word has even number of letters append one more "e" to the end of it.
Print the translated sentence.
Example:
Hello there Amy
Output:
Helloche thereche myAche
Here is what I have done so far :
string Sentence = Console.ReadLine();
string[] output = Sentence.Split(' ');
char letter;
string che = "che";
StringBuilder sb = new StringBuilder(Sentence);
foreach (string s in output)
{
letter = s[0];
if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i'
|| letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
{
// Console.WriteLine("first char of the word is a vowel");
}
else
{
sb.Insert(s.Length,che);
// Console.WriteLine("first char of a word is a consonant");
}
if (s.Length % 2 == 0)
{
// Console.WriteLine("the word has even numbers of letters");
}
//Console.WriteLine(firstchar);
int currentWordLength = s.Length;
}
Console.WriteLine(sb);
The problem is I cannot add "che" or remove vowels of words because the index is moving due to those changes. I can only change the first word. My ifs are correct because if I uncomment the Console.Writelines they scan through each word.
I am just struggling with the adding/removing of each word. Can you please point me to the right direction?
I would suggest you to create StringBuilder object and append appropriate string into the IF condition. Try with the below code:
string Sentence = Console.ReadLine();
string[] output = Sentence.Split(' ');
char letter;
string che = "che";
StringBuilder sb = null;
Console.WriteLine("\n");
string strFinal = "";
foreach (string s in output)
{
letter = s[0];
sb = new StringBuilder(s);
if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i'
|| letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
{
// Console.WriteLine("first char of the word is a vowel");
string s1 = sb.Remove(0, 1).ToString();
sb.Insert(s1.Length, letter);
sb.Insert(sb.Length, che);
}
else
{
// Console.WriteLine("first char of a word is a consonant");
sb.Insert(s.Length, che);
}
if (s.Length % 2 == 0)
{
// Console.WriteLine("the word has even numbers of letters");
// sb.Insert(s.Length, "e");
sb.Insert(sb.Length, "e");
}
//Console.WriteLine(firstchar);
int currentWordLength = s.Length;
strFinal += sb + " ";
}
Console.WriteLine(strFinal);
Console.ReadKey();
First, I'd recommend changing your translation code to have a function that acts on words, instead of the whole sentence. So the code in foreach (string s in output) should be moved to another function that just acts on that string. And don't try to manipulate the string passed it, create a new one based on the logic you've listed. Once you've created the translated string, return it to the caller. The caller would then reconstruct the sentence from each returned translation.
Using the obvious extension methods:
public static class ExtensionMethods {
// ***
// *** int Extensions
// ***
public static bool IsEven(this int n) => n % 2 == 0;
// ***
// *** String Extensions
// ***
public static bool StartsWithOneOf(this string s, HashSet<char> starts) => starts.Contains(s[0]);
public static string Join(this IEnumerable<string> strings, string sep) => String.Join(sep, strings);
}
You can use LINQ to process the rules:
var vowels = "aeiouAEIOU".ToHashSet();
var ans = src.Split(' ')
.Select(w => (w.StartsWithOneOf(vowels) ? w.Substring(1)+w[0] : w)+"che"+(w.Length.IsEven() ? "e" : ""))
.Join(" ");
Let's start from splitting the initial problem into smaller ones, with a help of extract methods:
using using System.Text.RegularExpressions;
...
private static String ConvertWord(string word) {
//TODO: Solution here
return word; // <- Stub
}
private static String ConvertPhrase(string phrase) {
// Regex (not Split) to preserve punctuation:
// we convert each word (continued sequence of letter A..Z a..z or ')
// within the original phrase
return Regex.Replace(phrase, #"[A-Za-z']+", match => ConvertWord(match.Value));
// Or if there's guarantee, that space is the only separator:
// return string.Join(" ", phrase
// .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
// .Select(item => ConvertWord(item)));
}
Now it's time to implement ConvertWord:
private static String ConvertWord(string word) {
// Do not forget of special cases - e.g. empty string
if (string.IsNullOrEmpty(word))
return "chee";
// If the word has even number of letters append one more "e" to the end of it.
string suffix = word.Length % 2 == 0 ? "chee" : "che";
// To cases: starting from vowel / consonant
char letter = char.ToUpper(word[0]);
if (letter == 'A' || letter == 'E' || letter == 'I' || letter == 'O' || letter == 'U')
return word.Substring(1) + word.Substring(0, 1) + suffix;
else
return word + suffix;
}
Finally
string Sentence = Console.ReadLine();
Console.Write(ConvertPhrase(Sentence));
For test input
"It's just a simple test (demo only): nothing more!"
Will get
t'sIchee justchee ache simplechee testchee (demochee nlyochee): nothingche morechee!
You mustn't change your word before the end of ifs. you need to test all of the conditions and save the result in another values, finally do changes on the word:
foreach (string s in output)
{
letter = char.ToLower(s[0]);
bool isVowel = false;
bool isEven = false;
if (letter == 'a' || letter == 'e' || letter == 'i'
|| letter == 'o' || letter == 'u')
{
isVowel = true;
}
if (s.Length % 2 == 0)
{
isEven = true;
}
//Now you can change the word
if (isVowel)
{
//Do What you want
}
if (isEven)
{
//Do What you want
}
//Console.WriteLine(firstchar);
int currentWordLength = s.Length;
}
I would say break the logic into specific units so you can write tests,
static void Main(string[] args)
{
var input = Console.ReadLine();
var inputs = input.Split(' ');
var sentence = string.Join(" ", inputs.Select(ConvertWord));
Console.Write(sentence);
Console.Read();
}
internal static string ConvertWord(string input)
{
const string che = "che";
var vowels = new List<string>
{
"a","A", "e", "E", "i", "I", "o", "O", "u", "U"
};
var firstChar = input.First();
var startsWithVowel = vowels.SingleOrDefault(a => a.Equals(firstChar));
string rule2String, output;
if (string.IsNullOrEmpty(startsWithVowel))
{
output = input + che;
}
else
{
output = input.Substring(1) + startsWithVowel + che;
}
rule2String = IsLengthEven(input)
? output + "e"
: output
;
return rule2String;
}
internal static bool IsLengthEven(string input)
{
return input.Length % 2 == 0;
}
Hope this Helps!
PS: I have not covered the edge cases
I would recommend to use String.Join using Linq with String.Format. Then the solution is quite easy:
private String convertSentence() {
var sentence = "Hello there Amy";
var vowels = "aeiou";
var che = "che";
return String.Join(" ", (
from s in sentence.Split(' ')
let moveFirstToEnd = vowels.Contains(s.ToLower()[0]) && s.Length > 1
select String.Format("{0}{1}{2}{3}"
, moveFirstToEnd ? s.Substring(1) : s
, moveFirstToEnd ? s.Substring(0, 1) : String.Empty
, che
, s.Length % 2 == 0 ? "e" : String.Empty
)
)
);
}
This is my code. How can I edit it to show every word which is at the odd position ONLY to be reversed?
for (int i = input.Length - 1; i >= 0; i--)
{
if (input[i] == ' ')
{
result = tmp + " " + result;
tmp = "";
}
else
tmp += input[i];
}
result = tmp + " " + result;
Console.WriteLine(result);
Example input:
"How are you today"
to output:
"How era you yadot"
Based on the position of a word ['How' -> 0] do not reverse; [are -> 1 odd index] Reverse
You can achieve it with the help of LINQ:
var input = "hello this is a test message";
var inputWords = input.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var result = string.Join(" ",
inputWords.Select((w, i) =>
i % 2 == 0
? w
: new string(w.Reverse().ToArray())
));
Where w in the select is the word, and i is the index, starting at 0 for the first word. % is the modulus operator and gets the remainder. If i % 2 == 0 (i.e. i can be divided by 2 with no remainder), then the original is returned. If there is a remainder (odd) then the reversed word is returned. Finally, it's all wrapped up in a string.Join(" ", items); which turns it back into a normal string rather than an array of items.
Try it online
So far you have a string, like this:
string input = "I want to reverse all odd words (odd words only!).";
And you, naturally, want to perform the task. Now it's the main question what's an odd word?
If you mean word's position (I at position 0, want at 1 - should be reversed etc.)
then you can use regular expressions to match words and Linq to process them:
using System.Linq; // To reverse single word
using System.Text.RegularExpressions; // To match the words within the text
...
// Let's elaborate the test example: add
// 1. some punctuation - ()!. - to preserve it
// 2. different white spaces (spaces and tabulation - \t)
// to add difficulties for naive algorithms
// 3. double spaces (after "to") to mislead split based algorithms
string input = "I want to reverse all\todd words (odd words only!).";
int index = 0; // words' indexes start from zero
string result = Regex.Replace(
input,
"[A-Za-z']+", // word is letters and apostrophes
match => index++ % 2 == 0
? match.Value // Even words intact
: string.Concat(match.Value.Reverse())); // Odd words reversed
Console.WriteLine(result);
If you want to reverse the words with odd Length, i.e. I, all, odd then all you have to do is to change the condition to
match => match.Value % 2 == 0
Outcome:
I tnaw to esrever all ddo words (ddo words ylno!).
Please, notice, that the punctuation has been preserved (only words are reversed).
OP: Based on the position of a word ['How' -> 0] do not reverse; [are -> 1 odd index] Reverse
public static void Main()
{
string input = "How are you today Laken-C";
//As pointed out by #Dmitry Bychenko string input = "How are you today";
//(double space after How) leads to How are uoy today outcome
input = Regex.Replace(input, #"\s+", " ");
var inp = input.Split(' ').ToList();
for (int j = 0; j < inp.Count(); j++)
{
if(j % 2 == 1)
{
Console.Write(inp[j].Reverse().ToArray());
Console.Write(" ");
}
else
Console.Write(inp[j] + " ");
}
}
OUTPUT:
DEMO:
dotNetFiddle
try this is perfect working code..
static void Main(string[] args)
{
string orgstr = "my name is sagar";
string revstr = "";
foreach (var word in orgstr.Split(' '))
{
string temp = "";
foreach (var ch in word.ToCharArray())
{
temp = ch + temp;
}
revstr = revstr + temp + " ";
}
Console.Write(revstr);
Console.ReadKey();
}
Output: ym eman si ragas
My project: Basically, I've written a small encrypting program in the workshop which takes user input and checks whether the character position in the loop is even, if so it will at the front of the string, else at the end. It looks something like this;
string userInput = "", encodedInput = "", evenChar = "", oddChar = "";
int charCount = 0;
Console.WriteLine("Input your text: ");
userInput = Console.ReadLine();
foreach(char character in userInput)
{
charCount++;
if ((charCount % 2) == 0)
{
evenChar = evenChar + character;
}
else
{
oddChar = character + oddChar;
}
encodedInput = evenChar + oddChar;
}
Console.WriteLine(encodedInput);
Now this works fine, when i type in "hi my name is jeff!" I get "im aei ef!fjs mny h".
Now I'm trying to write a deciphering loop. The method I chose for deciphering is basically taking the last character from the string adding it to a new empty string and then taking the first character from the string and also adding it to the same empty string and then simply decrements the overall length of the encrypted string and increments the position of the first character.
char lastChar = ' ';
char firstChar = ' ';
StringBuilder decodedInput = new StringBuilder();
int len = encodedInput.Length;
int len2 = 0;
foreach(char character in encodedInput)
{
lastChar = encodedInput[len - 1];
decodedInput.Append(lastChar.ToString());
len--;
firstChar = encodedInput[len2];
len2++;
decodedInput.Append(firstChar.ToString());
}
Console.WriteLine(decodedInput.ToString());
Now this works fine for the most part. It takes the same "im aei ef!fjs mny h" and outputs "hi my name is jeff!!ffej si eman ym ih". It mirrors the string because for each loop i produce to characters so "hi my name is jeff" turns into 36 characters. I've tried halving the loop, but you still get some mirroring.
I'm well aware that there are better or easier methods for deciphering this, but I want to do it this way for the educational purposes.
Kind regards,
Vocaloidas.
Don't loop over each character of the encoded input as you will end up processing each character twice. You are already counting up and down the string with the len and len2 variables so if you replace the foreach with:
while (len > len2)
this will only process each character of the string once
You will have to do some special casing when the string is an odd number of characters to deal with the middle character - i.e. when len and len2 are equal. To this end add the following:
if (len == len2)
break;
in middle of the loop so that it becomes:
while (len > len2)
{
lastChar = encodedInput[len - 1];
decodedInput.Append(lastChar.ToString());
len--;
if (len == len2)
break;
firstChar = encodedInput[len2];
len2++;
decodedInput.Append(firstChar.ToString());
}
This question already has answers here:
Get Index of First non-Whitespace Character in C# String
(12 answers)
Closed 9 years ago.
How would I count the amount of spaces at the start of a string in C#?
example:
" this is a string"
and the result would be 4. Not sure how to do this correctly.
Thanks.
Use Enumerable.TakeWhile, Char.IsWhiteSpace and Enumerable.Count
int count = str.TakeWhile(Char.IsWhiteSpace).Count();
Note that not only " " is a white-space but:
White space characters are the following Unicode characters:
Members of the SpaceSeparator category, which includes the characters SPACE (U+0020), OGHAM SPACE MARK (U+1680), MONGOLIAN VOWEL SEPARATOR (U+180E), EN QUAD (U+2000), EM QUAD (U+2001), EN SPACE (U+2002), EM SPACE (U+2003), THREE-PER-EM SPACE (U+2004), FOUR-PER-EM SPACE (U+2005), SIX-PER-EM SPACE (U+2006), FIGURE SPACE (U+2007), PUNCTUATION SPACE (U+2008), THIN SPACE (U+2009), HAIR SPACE (U+200A), NARROW NO-BREAK SPACE (U+202F), MEDIUM MATHEMATICAL SPACE (U+205F), and IDEOGRAPHIC SPACE (U+3000).
Members of the LineSeparator category, which consists solely of the LINE SEPARATOR character (U+2028).
Members of the ParagraphSeparator category, which consists solely of the PARAGRAPH SEPARATOR character (U+2029). The characters CHARACTER TABULATION (U+0009), LINE FEED (U+000A), LINE TABULATION (U+000B), FORM FEED (U+000C), CARRIAGE RETURN (U+000D), NEXT LINE (U+0085), and NO-BREAK SPACE (U+00A0).
.... so basically spaces, new-lines- and tabs
You can use LINQ, because string implements IEnumerable<char>:
var numberOfSpaces = input.TakeWhile(c => c == ' ').Count();
input.TakeWhile(c => c == ' ').Count()
Or
input.Length - input.TrimStart(' ').Length
Try this:
static void Main(string[] args)
{
string s = " this is a string";
Console.WriteLine(count(s));
}
static int count(string s)
{
int total = 0;
for (int i = 0; i < s.Length; i++)
{
if (s[i] == ' ')
total++;
else
break;
}
return total;
}
While I like the Linq based answers here's a boring unsafe method that should be pretty fast
private static unsafe int HowManyLeadingSpaces(string input)
{
if (input == null)
return 0;
if (input.Length == 0)
return 0;
if (string.IsNullOrWhiteSpace(input))
return input.Length;
int count = 0;
fixed (char* unsafeChar = input)
{
for (int i = 0; i < input.Length; i++)
{
if (char.IsWhiteSpace((char)(*(unsafeChar + i))))
count++;
else
break;
}
}
return count;
}
int count = 0, index = 0, lastIndex = 0;
string s = " this is a string";
index = s.IndexOf(" ");
while (index > -1)
{
count++;
index = s.IndexOf(" ", index + 1);
if ((index - lastIndex) > 1)
break;
lastIndex = index;
}
Console.WriteLine(count);
How we can find out the next character of the entered one. For example, if I entered the character "b" then how do I get the answer "c"?
Try this:
char letter = 'c';
if (letter == 'z')
nextChar = 'a';
else if (letter == 'Z')
nextChar = 'A';
else
nextChar = (char)(((int)letter) + 1);
This way you have no trouble when the char is the last of the alphabet.
How about:
char first = 'c';
char nextChar = (char)((int) first + 1);
Note that a char will implicitly cast to an int. Here's a simplified solution:
char incrementCharacter(char input)
{
return (input == 'z'? 'a': (char)(input + 1));
}
Perhaps the simplest way is a little function and an array of the 26 chars. Then you can decide what you want to return for 'z'.
Convert the character to a number, increment the number and then convert back.
But consider what will happen for "z" or "á" (Latin Small Leter A with Acute).
This Change value useful for Excel application to find previous column
public static string PrevExecelColumn( string s)
{
s = s.ToUpper();
char[] ac = s.ToCharArray();
int ln = ac.Length;
for (int i = ln - 1; i > -1; i--)
{
char c = ac[i];
if (c == 'A')
{
ac[i] = 'Z';
continue;
}
ac[i] = (char)(((int)ac[i]) - 1);
break;
}
s = new string(ac);
return s;
}
Try this :
public string GetNextAlphabetLetter(int indice) {
return ((char)('A' + indice)).ToString();
}
need to just add 1 in character you get next character.
It works on ASCII values.