I'm making a program of Vigenere cipher in c # but I'm having a problem i don't have the "Ñ" I would like to encrypt as happens in Vigenere cipher but With the "Ñ" how add the letter "Ñ" to this code? such that both key and s remain this way: a=0 b=1... n=13 ñ=14... z=26 after the n that a place be flown
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void VigenereEncrypt(ref StringBuilder s, string key)
{
for (int i = 0; i < s.Length; i++) s[i] = Char.ToUpper(s[i]);
key = key.ToUpper();
int j = 0;
for (int i = 0; i < s.Length; i++)
{
if (Char.IsLetter(s[i]))
{
s[i] = (char)(s[i] + key[j] - 'A');
if (s[i] > 'Z') s[i] = (char)(s[i] - 'Z' + 'A' - 1);
}
j = j + 1 == key.Length ? 0 : j + 1;
}
}
static void VigenereDecrypt(ref StringBuilder s, string key)
{
for (int i = 0; i < s.Length; i++) s[i] = Char.ToUpper(s[i]);
key = key.ToUpper();
int j = 0;
for (int i = 0; i < s.Length; i++)
{
if (Char.IsLetter(s[i]))
{
s[i] = s[i] >= key[j] ?
(char)(s[i] - key[j] + 'A') :
(char)('A' + ('Z' - key[j] + s[i] - 'A') + 1);
}
j = j + 1 == key.Length ? 0 : j + 1;
}
}
public static void Main()
{
while (true)
{
StringBuilder s = new StringBuilder(Console.ReadLine());
string key = Console.ReadLine();
VigenereEncrypt(ref s, key);
Console.WriteLine(s);
VigenereDecrypt(ref s, key);
Console.WriteLine(s);
Console.ReadLine();
}
}
}
}
Your code:
Depends on the fact that the letters from U+0041 to U+005A just happen to match a the letters of the alphabets of some languages, such as English*. (If the test had depended on this instead of just checking it was a letter then you would have been leaving
Ñ
unchanged rather than get an error). There are some other languages whose alphabet's are contiguous and in order in the UCS, but most languages are not.For this reason you'll need to define your own alphabet. A string is a simple enough way to do this for most uses.
Then instead of depending on coincidences between an alphabet and the UCS, you can use the alphabet you care about:
(I'm assuming that the key is always composed solely from the alphabet in question, a more robust solution wouldn't make that assumption, but there are a few different approaches as to just what one should do in such a case, so there isn't a single correct way to deal with that and I ignored the issue).
I also took out the
ref
keyword, since theStringBuilder
isn't changed for another reference as that signature suggests, but mutated in-place. A more idiomatic approach though would be to receive a string and return another:If you want to treat strings that Unicode does not consider a single character as a letter, e.g.
IJ
in Dutch† this gets more complicated. One possibility is to use a marker character for such a sequence and then first replace each case of the sequence with it before encrypting‡, and then replace back again should the marker appear in the output. One would have to be sure that the marker character didn't appear in the input, which would make non-characters like U+FFFE useful here.Diacritics that are not considered separate parts of the alphabet (like
Ñ
is in Spanish), are another complication. In the days when cyphers like the Vigenère were actually used it was common to just strip diacritics and deal with the fact that the output would not have diacritics it should have. An easy way to do that is to use a method like:And then use a loop that does
foreach(char c in RemoveDiacriticsEnum(s, alphabet))
and usesc
where the code above usess[i]
. This won't cover all cases, see https://stackoverflow.com/a/3769995/400547 for some of the possible complications.Alternatively, one could include the common accent combinations in the alphabet:
*Strictly speaking there are a variety of conventions about where some other characters, particularly Ð, Ȝ and Þ should be positioned if used, so one version of the modern English alphabet is
A,B,C,D,[Ð],E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,[Ȝ],Z,[Þ]
, that is one would generally not listÐ
, but if there was a word in your data that started with it, you'd position it betweenD
andE
, and so on. This is an obscure case in Modern English (we don't really use those letters any more), but can be more significant in some other languages; e.g. the Irish alphabet isA,B,C,D,E,F,G,H,I,L,M,N,O,P,R,S,T,U
butV
is used in a few onomatopœic words, andJ,K,Q,V,W,X,Y,Z
are each found in some loan words, so we could list the Irish alphabet asA,B,C,D,E,F,G,H,I,[J],[K],L,M,N,O,P,[Q],R,S,T,U,[V],[W],[X],[Y],[Z]
, not generally listing the letters in brackets, but positioning e.g.J
betweenI
andL
if a word beginning withJ
is in a set of data. This complicates the question of cyphers like Vigenère because we have to either use letters not strictly part of the alphabet in the calculation, or else not encrypt theV
of a word like vótaí.†While there is a
IJ
character in the UCS at U+0132, this is for compatibility with legacy encodings. Still usingIJ
as the marker-character forIJ
would neatly handle bothIJ
and data that had usedIJ
.‡Encrypting in a rather loose sense, since this encryption scheme was broken by the middle of the 19th Century.