Сделать список целых чисел более удобным для человека - PullRequest
0 голосов
/ 04 сентября 2011

Это небольшой побочный проект, который я взял на себя, чтобы решить проблему без исправлений для работы. Наша система выводит код для представления комбинации вещей в другом. Некоторые примеры кодов:

9-9-0-4-4-5-4-0-2-0-0-0-2-0-0-0-0-0-2-1-2-1-2-2 -2-4

9-5-0-7-4-3-5-7-4-0-5-1-4-2-1-5-5-4-6-3-7-9-72

9-15-0-9-1-6-2-1-2-0-0-1-6-0-7

Максимальное число в одном из слотов, которые я видел до сих пор, составляет около 150, но они, вероятно, пойдут выше.

Когда система была разработана, не было требований к тому, как будет выглядеть этот код. Но теперь клиент хочет иметь возможность вводить его вручную с листа бумаги, для чего приведенный выше код не подходит. Мы сказали, что ничего не будем с этим делать, но это кажется забавным испытанием.

Мой вопрос: где хорошее место для начала сжатия этого кода без потерь? Очевидные решения, такие как хранение этого кода с более коротким ключом, не подходят; наша база данных только для чтения. Мне нужно создать двухсторонний метод, чтобы сделать этот код более удобным для человека.

Ответы [ 4 ]

1 голос
/ 04 сентября 2011

1) Я согласен, что вам определенно нужна контрольная сумма - ошибки при вводе данных очень распространены, если у вас нет действительно хорошо обученного персонала и независимого дублирующего набора с автоматической перекрестной проверкой.

2) Я предлагаю http://en.wikipedia.org/wiki/Huffman_coding, чтобы превратить ваш список чисел в поток битов.Чтобы получить вероятности, требуемые для этого, вам нужна выборка реальных данных приличного размера, чтобы вы могли сделать подсчет, установив Ni в число раз, которое число i появляется в данных.Затем я предлагаю установить Pi = (Ni + 1) / (Sum_i (Ni + 1)) - что немного сглаживает вероятности.Кроме того, с помощью этого метода, если вы видите, например, числа 0-150, вы можете добавить немного провисания, введя числа 151-255 и установив их в Ni = 0. Другой способ обойти редкие большие числа - добавить некую escape-последовательность..

3) Поиск способа напечатать результирующую последовательность битов на самом деле является проблемой прикладной психологии, но вот несколько советов, как ущипнуть.

3a) Лицензии на программное обеспечение - просто кодируйтешесть битов на символ в некотором 64-символьном алфавите, но сгруппируйте символы таким образом, чтобы людям было легче сохранять свое место, например, BC017-06777-14871-160C4

3b) номерные знаки автомобилей в Великобритании.Используйте изменение алфавита, чтобы показать людям, как группировать символы, например, ABCD0123EFGH4567IJKL ...

3c) Действительно большой алфавит - составьте список из 2 ^ n слов для некоторого приличного размера n и закодируйте n бит какслово напр. ЗЕЛЕНЫЙ ЗАЧАТНЫЙ ЛОГИК ... -

0 голосов
/ 06 сентября 2011

Это похоже на то, что я использовал в прошлом. Конечно, есть лучшие способы сделать это, но я использовал этот метод, потому что было легко отражать в Transact-SQL, который был требованием в то время. Вы, конечно, можете изменить это, чтобы включить кодировку Хаффмана, если распределение ваших идентификаторов неслучайно, но, вероятно, в этом нет необходимости.

Вы не указали язык, так что это на c #, но переход на любой язык должен быть очень простым. В поиске вы увидите, что часто запутанные символы опущены. Это должно ускорить вход. У меня также было требование иметь фиксированную длину, но вам было бы легко изменить это.

static public class CodeGenerator
{
    static Dictionary<int, char> _lookupTable = new Dictionary<int, char>();

    static CodeGenerator()
    {
        PrepLookupTable();
    }

    private static void PrepLookupTable()
    {
        _lookupTable.Add(0,'3');
        _lookupTable.Add(1,'2');
        _lookupTable.Add(2,'5');
        _lookupTable.Add(3,'4');
        _lookupTable.Add(4,'7');
        _lookupTable.Add(5,'6');
        _lookupTable.Add(6,'9');
        _lookupTable.Add(7,'8');
        _lookupTable.Add(8,'W');
        _lookupTable.Add(9,'Q');
        _lookupTable.Add(10,'E');
        _lookupTable.Add(11,'T');
        _lookupTable.Add(12,'R');
        _lookupTable.Add(13,'Y');
        _lookupTable.Add(14,'U');
        _lookupTable.Add(15,'A');
        _lookupTable.Add(16,'P');
        _lookupTable.Add(17,'D');
        _lookupTable.Add(18,'S');
        _lookupTable.Add(19,'G');
        _lookupTable.Add(20,'F');
        _lookupTable.Add(21,'J');
        _lookupTable.Add(22,'H');
        _lookupTable.Add(23,'K');
        _lookupTable.Add(24,'L');
        _lookupTable.Add(25,'Z');
        _lookupTable.Add(26,'X');
        _lookupTable.Add(27,'V');
        _lookupTable.Add(28,'C');
        _lookupTable.Add(29,'N');
        _lookupTable.Add(30,'B');          
    }


    public static bool TryPCodeDecrypt(string iPCode, out Int64 oDecryptedInt)
    {
        //Prep the result so we can exit without having to fiddle with it if we hit an error.
        oDecryptedInt = 0;

        if (iPCode.Length > 3)
        {
            Char[] Bits = iPCode.ToCharArray(0,iPCode.Length-2);

            int CheckInt7 = 0; 
            int CheckInt3 = 0;
            if (!int.TryParse(iPCode[iPCode.Length-1].ToString(),out CheckInt7) ||
                !int.TryParse(iPCode[iPCode.Length-2].ToString(),out CheckInt3))
            {
                //Unsuccessful -- the last check ints are not integers.
                return false;
            }
            //Adjust the CheckInts to the right values.
            CheckInt3 -= 2;
            CheckInt7 -= 2;

            int COffset = iPCode.LastIndexOf('M')+1;


            Int64 tempResult = 0;
            int cBPos = 0;
            while ((cBPos + COffset) < Bits.Length)
            {
                //Calculate the current position.
                int cNum = 0;
                foreach (int cKey in _lookupTable.Keys)
                {
                    if (_lookupTable[cKey] == Bits[cBPos + COffset])
                    {
                        cNum = cKey;
                    }
                }
                tempResult += cNum * (Int64)Math.Pow((double)31, (double)(Bits.Length - (cBPos + COffset + 1)));
                cBPos += 1;
            }

            if (tempResult % 7 == CheckInt7 && tempResult % 3 == CheckInt3)
            {
                 oDecryptedInt =  tempResult;
                return true;    
            }


            return false;

        }
        else
        {
            //Unsuccessful -- too short.
            return false;
        }
    }
    public static string PCodeEncrypt(int iIntToEncrypt, int iMinLength)
    {
        int Check7 = (iIntToEncrypt % 7) + 2;
        int Check3 = (iIntToEncrypt % 3) + 2;

        StringBuilder result = new StringBuilder();
        result.Insert(0, Check7);
        result.Insert(0, Check3);

        int workingNum = iIntToEncrypt;

        while (workingNum > 0)
        {
            result.Insert(0, _lookupTable[workingNum % 31]);
            workingNum /= 31;
        }

        if (result.Length < iMinLength)
        {
            for (int i = result.Length + 1; i <= iMinLength; i++)
            {
                result.Insert(0, 'M');
            }
        }

        return result.ToString();
    }

}
0 голосов
/ 04 сентября 2011

Я беспокоился об этой проблеме некоторое время назад.оказывается, что вы не можете сделать намного лучше, чем base64 - попытка сжать еще несколько бит на символ не стоит усилий (как только вы попадаете в «странные» числа, кодирование и декодирование битов становится более сложным).но в то же время вы получите что-то, что может привести к ошибкам при вводе (путая 0 с O и т. д.).одним из вариантов является выбор измененного набора символов и букв (так что это все еще базовая 64, но, скажем, вы заменяете «>» на «0». другой - добавить контрольную сумму. еще раз, для простоты реализации, я чувствовал, чтоПодход к контрольной сумме был лучше.

к сожалению, я никогда не шел дальше - все изменилось, поэтому я не могу предложить код или конкретный выбор контрольной суммы.

ps Я понял, что пропущенный шаг я не сделалОбъясните: я собирался сжать текст в некоторую двоичную форму перед кодированием (используя некоторый стандартный алгоритм сжатия). Итак, подведем итог: сжимать, добавлять контрольную сумму, кодировать base64; декодировать base 64, проверять контрольную сумму, распаковывать.

0 голосов
/ 04 сентября 2011

На этот вопрос есть довольно аккуратные ответы, которые могут вам помочь:

Как преобразовать целое число в самую короткую URL-безопасную строку в Python?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...