Ваш код:
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);
}
в зависимости от того, что буквы от U + 0041 до U + 005A просто случается, сортируют буквы алфавитов некоторых языков, таких как английский язык *. (Если бы тест зависел от этого, а не просто проверял, что это письмо, то вы оставите Ñ
без изменений, а не получите ошибку). Существуют и другие языки, алфавит которых смежны и упорядочены в UCS, но большинство языков - нет.
По этой причине вам необходимо определить свой собственный алфавит. Строка - достаточно простой способ сделать это для большинства целей.
string spanishAlphabet = "ABCDEFGHIJKLMNÑOPQRSTUVWXYZ";
string englishAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string irishAlphabet = "ABCDEFGHILMNOPRSTU";
string danishAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅ";
string norwegianAlphabet = danishAlphabet;
Тогда вместо того, чтобы зависеть от совпадения между алфавитом и UCS, вы можете использовать алфавит, вы заботитесь о:
static void VigenereEncrypt(StringBuilder s, string key, string alphabet)
{
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(alphabet.Contains(s[i]))
s[i] = alphabet[(alphabet.IndexOf(s[i]) + alphabet.IndexOf(key[j])) % alphabet.Length];
j = (j + 1) % key.Length;
}
}
static void VigenereDecrypt(StringBuilder s, string key, string alphabet)
{
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(alphabet.Contains(s[i]))
{
s[i] = alphabet[(alphabet.IndexOf(s[i]) - alphabet.IndexOf(key[j]) + alphabet.Length) % alphabet.Length];
j = (j + 1) % key.Length;
}
}
}
(я предполагаю, что ключ всегда состоит только из алфавит в вопросе, более надежное решение не сделало бы этого предположения, но есть несколько разных подходов к тому, что нужно делать в таком случае, поэтому нет ни одного правильного способа справиться с этим, и я проигнорировал проблема).
Я также достал ключевое слово ref
, так как StringBuilder
не изменен для другой ссылки, поскольку эта подпись предлагает, но мутировала на месте. Более идиоматическое подход хотя бы получить строку и вернуть другой:
static string VigenereEncrypt(string s, string key, string alphabet)
{
s = s.ToUpper();
key = key.ToUpper();
int j = 0;
StringBuilder ret = new StringBuilder(s.Length);
for (int i = 0; i < s.Length; i++)
{
if(alphabet.Contains(s[i]))
ret.Append(alphabet[(alphabet.IndexOf(s[i]) + alphabet.IndexOf(key[j])) % alphabet.Length]);
else
ret.Append(s[i]);
j = (j + 1) % key.Length;
}
return ret.ToString();
}
static string VigenereDecrypt(string s, string key, string alphabet)
{
s = s.ToUpper();
key = key.ToUpper();
int j = 0;
StringBuilder ret = new StringBuilder(s.Length);
for (int i = 0; i < s.Length; i++)
{
if(alphabet.Contains(s[i]))
ret.Append(alphabet[(alphabet.IndexOf(s[i]) - alphabet.IndexOf(key[j]) + alphabet.Length) % alphabet.Length]);
else
ret.Append(s[i]);
j = (j + 1) % key.Length;
}
return ret.ToString();
}
Если вы хотите обработать строки, Unicode не считает ни одного символа в виде буквы, например, IJ
на-голландском † это усложняется. Одна из возможностей заключается в использовании символа-маркера для такой последовательности, а затем сначала заменяйте каждый случай последовательности на нее перед шифрованием ‡, а затем заменяйте обратно, если маркер появится на выходе. Нужно быть уверенным, что символ маркера не появился на входе, что сделало бы здесь ненужные символы, такие как U + FFFE.
Диакритические знаки, которые не считаются отдельными частями алфавита (например, , на испанском языке), являются еще одним осложнением. В те времена, когда на самом деле использовались шифры, подобные Vigenère, было обычным делом выписывать диакритические знаки и иметь дело с тем, что на выходе не было бы диакритики, которая должна быть. Самый простой способ сделать это, чтобы использовать метод, как:
public static IEnumerable<char> RemoveDiacriticsEnum(string src, string alphabet)
{
foreach(char c in src.Normalize(NormalizationForm.FormD))
if(alphabet.Contains(c)) // Catch e.g. Ñ in Spanish, considered letter in own right
yield return c;
else
switch(CharUnicodeInfo.GetUnicodeCategory(c))
{
case UnicodeCategory.NonSpacingMark:
case UnicodeCategory.SpacingCombiningMark:
case UnicodeCategory.EnclosingMark:
//do nothing
break;
default:
yield return customFolding(c);
break;
}
}
И затем использовать цикл, который делает foreach(char c in RemoveDiacriticsEnum(s, alphabet))
и использует c
где код выше использует s[i]
. Это не будет охватывать все случаи, см. https://stackoverflow.com/a/3769995/400547 для некоторых возможных осложнений.
В качестве альтернативы можно было бы включать в себя общие комбинации акцента в алфавите:
string spanishAlphabet = "AÁBCDEÉFGHIÍJKLMNÑOÓPQRSTUÚÜVWXYZ";
* Строго говоря, существует целый ряд соглашений о том, где некоторые другие символы, в частности, Ð, Ȝ и Þ должен быть установлен, если используется , поэтому одна версия современного английского алфавита - 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,[Þ]
, то есть, как правило, не будет отображаться список Ð
, но если в ваших данных, которые начинались с него, было слово, то вы должны были бы установить его между D
и E
и так далее. Это неясный случай в современном английском (мы больше не используем эти письма), но может быть более значительным на некоторых других языках; например ирландский алфавит A,B,C,D,E,F,G,H,I,L,M,N,O,P,R,S,T,U
, но V
используется в нескольких одноаспектных словах, а J,K,Q,V,W,X,Y,Z
- в некоторых заимствованных словах, поэтому мы можем перечислить ирландский алфавит как 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]
, не в общем перечисляя буквы в скобках, но позиционируя, например, J
между I
и L
, если слово, начинающееся с J
, находится в наборе данных. Это усложняет вопрос о шифрах, таких как Vigenère, потому что мы должны либо использовать буквы не строго в алфавите в расчете, либо не шифровать V
слова типа vótaí.
† В UCS есть символ IJ
в U + 0132, это совместимо с устаревшими кодировками. Все еще используя IJ
в качестве символа-маркера для IJ
будет аккуратно обрабатывать как IJ
, так и данные, которые использовали IJ
.
‡ Шифрование в довольно свободном смысле, поскольку эта схема шифрования была нарушена к середине 19-го века.
Итак ... в чем проблема? – BradleyDotNET
, когда я ввожу пароль больше, чем письмо с расширением дает мне ошибку –
И эта ошибка есть? Какая линия? Пожалуйста, включите каждую возможную информацию об ошибке. – BradleyDotNET