首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >阿塔什密码

阿塔什密码
EN

Code Review用户
提问于 2017-06-28 03:18:15
回答 3查看 775关注 0票数 6

我正在用C#做一些练习,我刚刚完成了我自己的atbash密码实现,下面是代码:

代码语言:javascript
复制
public class AtbashCipher
{
    private string _plain = "abcdefghijklmnopqrstuvwxyz";
    private string _cipher = "zyxwvutsrqponmlkjihgfedcba";
    private readonly string _input;
    private readonly List<int> _indices = new List<int>();

    public AtbashCipher(string input)
    {
        _input = input;
    }

    public string Encode()
    {
        Splitter(_input).ForEach(x => _indices.Add(_plain.IndexOf(x)));
        return _indices.Aggregate("", (current, index) => current + _cipher[index]);
    }

    public string Decode()
    {
        Splitter(_input).ForEach(x => _indices.Add(_cipher.IndexOf(x)));
        return _indices.Aggregate("", (current, index) => current + _plain[index]);
    }

    private List<char> Splitter(string input)
    {
        return input.ToCharArray().ToList();
    }
}

有时感觉有点重复,我班上所有的变量看起来都很混乱。有什么更优雅的方法吗?

EN

回答 3

Code Review用户

发布于 2017-06-28 03:59:10

好吧,如果你真的不想重复,你可以这样做

代码语言:javascript
复制
public static class AtbashCipher
{
    private static string Rotate(string input, bool direction)
    {
        char min = direction ? 'z' : 'a';
        char max = direction ? 'a' : 'z';

        return input.ToList().Aggregate("", (current, character) => current + (char)(min - (character - max)));
    }

    public static string Encode(string plaintext)
    {
        return Rotate(plaintext, true);
    }

    public static string Decode(string cyphertext)
    {
        return Rotate(cyphertext, false);
    }
}

如果您期望获得很大的输入,那么使用StringBuilder和foreach循环可能更有性能,而不是使用聚合()调用。

票数 5
EN

Code Review用户

发布于 2017-06-28 18:32:52

因为AtBash密码是一个简单的反向,所以您不需要_plain_cipher_indices没有理由处于类级别;相反,它应该在EncodeDecode中本地定义。

您甚至可以考虑取消拥有类实例,而使类及其方法成为静态的。如果将Decode保持为类实例,则可以简化为简单地返回_input

您应该确保将输入字符串设置为小写,以防有人输入"Hello“。类似于:

代码语言:javascript
复制
_input = input.ToLowerInvariant();

除了你应该尽量避免土耳其的“将”问题,代孕对被视为单一字符。避免的方法是使用大写。

另外,拆分器应该只使用char[],而不是转换ToList()。再说一次,你不需要真正的拆分器。

这些都是要考虑的事情。以下是我的看法:

代码语言:javascript
复制
public static class AtbashCipher
{
    private const string DefaultAlphabet = "abcdefghijklmnopqrstuvwxyz";

    public static string Encode(string input, string alphabet = DefaultAlphabet)
    {
        var plain = alphabet.ToUpperInvariant();
        var letters = new List<char>(input.Length);
        foreach (var c in input.ToUpperInvariant())
        {
            if (char.IsLetter(c))
            {
                // Get index of plain alphabet, but subtract from end
                var index = plain.Length - plain.IndexOf(c) - 1;
                letters.Add(plain[index]);
            }
        }
        return new string(letters.ToArray());
    }

    public static string Decode(string input, string alphabet = DefaultAlphabet)
    {
        // reverse alphabet to get cipher
        string cipher = new string(alphabet.ToUpperInvariant().Reverse().ToArray());

        var letters = new List<char>(input.Length);
        foreach (var c in input.ToUpperInvariant())
        {
            if (char.IsLetter(c))
            {
                var index = cipher.Length - cipher.IndexOf(c) - 1;
                letters.Add(cipher[index]);
            }
        }
        return new string(letters.ToArray());
    }
}

您可能会注意到,编码和解码看起来非常相似,除了选择普通或密码。以DRY的名义(不要重复),这可以简化为:

代码语言:javascript
复制
public static class AtbashCipher
{
    private const string DefaultAlphabet = "abcdefghijklmnopqrstuvwxyz";

    public static string Encode(string input, string alphabet = DefaultAlphabet)
    {
        var plain = alphabet.ToUpperInvariant();
        return Transform(input, plain);
    }

    public static string Decode(string input, string alphabet = DefaultAlphabet)
    {
        var cipher = new string(alphabet.ToUpperInvariant().Reverse().ToArray());
        return Transform(input, cipher);
    }

    private static string Transform(string input, string code)
    {
        var letters = new List<char>(input.Length);
        foreach (var c in input.ToUpperInvariant())
        {
            if (char.IsLetter(c))
            {
                var index = code.Length - code.IndexOf(c) - 1;
                letters.Add(code[index]);
            }
        }
        return new string(letters.ToArray());
    }
}
票数 5
EN

Code Review用户

发布于 2017-06-29 15:37:19

Atbash是它自己的逆方法,因此不需要单独的Encode()Decode()方法:例如,Atbash(b) = y;Atbash(y) =b。只需一个Transform()方法即可。

您也不需要_plain_cipher数组,您可以使用内置的字符排序。字符c是字母表中“a”前面的(c - 'a')位置,因此它的Atbash编码与“z”:('z' - (c - 'a'))之前的位置相同。这可以通过收集常量部分:(('z' + 'a') - c)来简化。

我的C#非常生疏,过时了,所以这是伪代码:

代码语言:javascript
复制
constant zANDa <- ascVal('z') + ascVal('a')

method Transform(inText) returns String
  inText <- toLowercase(inText)
  outText <- ""
  foreach character c in inText
    if (IsAlphabetic(c))
      outText.append(char(zANDa - ascVal(c)))
    else
      // Non-alphabetic characters.
      outText.append(c)
    end if
  end foreach
  return outText
end Transform

对于大写字母,请使用constant ZandA <- ascVal('Z') + ascVal('A')

票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/166822

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档