Кодирование числа, реализация С# для z-base-32 или что-то еще?

Мне нужно кодировать/декодировать целое число длиной до 9 цифр, но чаще всего 7 цифр. Я хотел бы, чтобы было проще общаться/запоминать - он будет передаваться по телефону, копироваться и вставляться, вставляться с карты/памяти/ярлыка, написанной на лейблах и обычно злоупотребляемым!

Я хочу уменьшить количество цифр (при добавлении контрольной суммы), используя схему base 32. Я больше всего сторонник z-base-32 (над RFC4648) из-за некоторых целей дизайна (например, рукописного ввода) и выбора алфавита (в нижнем регистре, переделаны в пользу символов, которые легче читать, писать, говорить и запоминать). Однако я не могу найти реализацию С#, и я заинтересован в переносе из существующей реализации Python.

Кто-нибудь имеет реализацию С#? В качестве альтернативы, есть ли у кого-нибудь набор тестовых примеров (кроме примеров в спецификации), которые я могу использовать для проверки порта?

Я открыт для предложений об альтернативных схемах кодирования.

Ответ 1

Я начал с кода, предоставленного Dead, и внес некоторые изменения, основанные на моих тестах. Надеюсь, это полезно.

/// <summary>
/// Author: Ben Maddox
/// </summary>
public class ZBase32Encoder
{
    /*
     * Accepted characters based on code from: 
     * http://www.codeproject.com/KB/recipes/Base32Encoding.aspx?display=Print
     */
    public const string AcceptedCharacters = "ybndrfg8ejkmcpqxot1uwisza345h769";

    public static string Encode(int input)
    {
        string result = "";

        if (input == 0)
        {
            result += AcceptedCharacters[0];
        }
        else
        {
            while (input > 0)
            {
                //Must make sure result is in the correct order
                result = AcceptedCharacters[input%AcceptedCharacters.Length] + result;
                input /= AcceptedCharacters.Length;
            }
        }

        return result;
    }

    public static int Decode(string input)
    {
        var inputString = input.ToLower();

        int result = 0;
        for (int i = 0; i < inputString.Length; i++)
        {
            result *= AcceptedCharacters.Length;
            var character = inputString[i];
            result += AcceptedCharacters.IndexOf(character);
        }
        return result;
    }

    public static int Decode(char data)
    {
        return Decode(data.ToString());
    }
}

И вот тесты, которые я использовал. MS Test с библиотекой утверждений If.

[TestClass]
public class ZBase32EncoderTests
{

    [TestMethod]
    public void Encoding_0_ReturnsFirstCharacter()
    {
        var result = ZBase32Encoder.Encode(0);
        result.ShouldEqual(ZBase32Encoder.AcceptedCharacters[0].ToString());
    }

    [TestMethod]
    public void Encoding_1_ReturnsSecondCharacter()
    {
        var result = ZBase32Encoder.Encode(1);
        result.ShouldEqual(ZBase32Encoder.AcceptedCharacters[1].ToString());
    }

    [TestMethod]
    public void Encoding_32_ReturnsSecondAndFirstValues()
    {
        var result = ZBase32Encoder.Encode(32);
        result.ShouldEqual(ZBase32Encoder.AcceptedCharacters[1].ToString() + ZBase32Encoder.AcceptedCharacters[0].ToString());
    }

    [TestMethod]
    public void Encoding_64_ReturnsThirdAndFirstValues()
    {
        var result = ZBase32Encoder.Encode(64);
        result.ShouldEqual(ZBase32Encoder.AcceptedCharacters[2].ToString() + ZBase32Encoder.AcceptedCharacters[0].ToString());
    }

    [TestMethod]
    public void Encoding_65_ReturnsThirdAndSecondValues()
    {
        var result = ZBase32Encoder.Encode(65);
        result.ShouldEqual(ZBase32Encoder.AcceptedCharacters[2].ToString() + ZBase32Encoder.AcceptedCharacters[1].ToString());
    }



    [TestMethod]
    public void Decoding_FirstCharacter_Returns_0()
    {
        var inputCharacter = ZBase32Encoder.AcceptedCharacters[0];
        var result = ZBase32Encoder.Decode(inputCharacter);
        result.ShouldEqual(0);
    }

    [TestMethod]
    public void Decoding_SecondCharacter_Returns_1()
    {
        var inputCharacter = ZBase32Encoder.AcceptedCharacters[1];
        var result = ZBase32Encoder.Decode(inputCharacter);
        result.ShouldEqual(1);
    }

    [TestMethod]
    public void Decoding_SecondAndFirstValues_Shows_32()
    {
        var inputCharacters = ZBase32Encoder.AcceptedCharacters[1].ToString() + ZBase32Encoder.AcceptedCharacters[0];
        var result = ZBase32Encoder.Decode(inputCharacters);
        result.ShouldEqual(32);
    }

    [TestMethod]
    public void Decoding_ThirdAndFirstCharacters_Shows_64()
    {
        var inputCharacters = ZBase32Encoder.AcceptedCharacters[2].ToString() + ZBase32Encoder.AcceptedCharacters[0];
        var result = ZBase32Encoder.Decode(inputCharacters);
        result.ShouldEqual(64);
    }
}

Ответ 2

Возможно, вы захотите использовать свою собственную процедуру кодирования/декодирования?

Encode:

 string acceptedChar = "ABCDEFGHJKLMNPQRSTUWXZ0123456789";
 int yourNumber = 12345678;

 string response = "";
 while (yourNumber > 0)
 {
      response += acceptedChar[yourNumber % acceptedChar.Length];
      yourNumber /= acceptedChar.Length;
 }

Decode:

 string acceptedChar = "ABCDEFGHJKLMNPQRSTUWXZ0123456789";
 string inputStr = "ABCD";

 int yourNumber = 0;
 for (int i = inputStr.Length; i > 0; i--)
 {
     yourNumber *= acceptedChar.Length;
     yourNumber += acceptedChar.IndexOf(inputStr[i]);
 }    

(непроверенный код)

Ответ 3

Вот одна из реализаций кодировка zBase32 на платформе .NET(написана на С#).

Ответ 4

Если вы посмотрите на клавиатуру своего мобильного телефона, номер 1985239 может быть представлен с использованием этих символов (a, b, c), (w, x, y, z), (t, u, v),... Попробуйте найти алгоритм, который будет генерировать более-менее английские слова с учетом упорядоченного набора неупорядоченных наборов символов - это будет легче запомнить.

Ответ 5

небольшое улучшение на посту BenMaddox (с использованием do-while):

public static String encode(int num, String base) {
    String response = "";
    do{
        response = base.charAt(num % base.length()) + response;
        num /= base.length();
    } while(num>0); 
    return response;
}