这是一个附带的项目,我已经着手解决一个无法解决的问题,为工作。我们的系统输出一段代码来表示另一件事情的组合。一些示例代码是:
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-2-0-0-1-6-0-7
到目前为止,我在其中一个插槽中看到的最大数约为150,但它们很可能会更高。
当系统被设计时,不需要这些代码看起来像什么。但是现在客户希望能够从一张纸上手工输入,上面的代码是不适合的。我们已经说过我们不会采取任何行动,但这似乎是一个有趣的挑战承担。
我的问题是,从哪里开始对代码进行无损压缩是个好地方?显而易见的解决方案,如用较短的键存储此代码,不是一个选项;我们的数据库是只读的。我需要构建一个双向的方法,使这个代码更人性化。
发布于 2011-09-04 05:24:55
1)我同意你确实需要一个校验和-数据输入错误是很常见的,除非你有真正训练有素的工作人员和独立的重复键控与自动交叉检查。
2)我建议http://en.wikipedia.org/wiki/Huffman_coding将您的数字列表转换为一个位流。要获得这方面所需的概率,您需要一个相当大小的真实数据样本,这样您就可以进行计数,将Ni设置为我在数据中出现的次数。然后,我建议设置Pi = (Ni + 1) / (Sum_i (Ni + 1)) -,这样可以稍微平滑概率。此外,使用此方法,如果您看到数字0-150,您可以通过输入数字151-255并将其设置为Ni = 0来增加一些松弛。另一种方法是添加某种形式的转义序列,以绕过罕见的大数。
3)找到一种方法让人们键入产生的位序列是一个实际的心理学问题,但这里有一些建议。
( 3a)软件许可证--在大约64个字符的字母表中,每个字符只编码6位,但分组字符的方式使人们更容易保持位置,例如to 017-06777-14871-160C4。
3b)英国汽车牌照。使用改变字母表向人们展示如何分组字符,例如ABCD0123EFGH4567IJKL.
( 3c)一个非常大的字母表--给自己列一张2^n个单词的列表,并把n位编码成一个单词,例如绿色魔法逻辑学家.-
发布于 2011-09-03 23:59:32
我之前担心过这个问题。事实证明,您不能比base64做得更好--尝试每一个字符再挤几个比特并不值得(一旦进入“奇怪”位数的编码和解码变得更加复杂)。但同时,当输入时可能会出现错误(将0与O等混淆)。一种选择是选择一组修改过的字符和字母(因此它仍然是基数64,但是,比方说,您用">“代替"0”。另一种方法是添加校验和。同样,为了实现的简单性,我觉得校验和方法更好。
不幸的是,我没有得到任何进一步-事情改变方向-所以我不能提供代码或一个特定的校验和选择。
ps我意识到还有一个我没有解释的步骤:我打算在编码之前将文本压缩成一些二进制形式(使用一些标准的压缩算法)。总结如下:压缩,加校验和,base64编码;基础64解码,校验和,解压缩。
发布于 2011-09-06 04:22:22
这与我过去所使用的类似。当然有更好的方法可以做到这一点,但是我使用这种方法是因为在Transact-SQL中很容易镜像,这是当时的要求。如果您的id的分布是非随机的,那么当然可以修改它以包含Huffman编码,但这可能是不必要的。
您没有指定语言,所以这是在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();
}
}https://stackoverflow.com/questions/7296513
复制相似问题