我使用泛型类将INT转换为X base:
BaseX basex = new BaseX("abcdefghijklmnopqrstuvwxyz");
var a = basex.ToBaseX(1002);
var b = basex.FromBaseX("aghe");
BaseX类如下:
public class BaseX {
private readonly string _digits;
public BaseX(string digits) {
_digits = digits;
}
public string ToBaseX(int number) {
var output = "";
do {
output = _digits[number % _digits.Length] + output;
number = number / _digits.Length;
}
while (number > 0);
return output;
}
public int FromBaseX(string number) {
return number.Aggregate(0, (a, c) => a * _digits.Length + _digits.IndexOf(c));
}
}
我使用的是小写字母,但我可以使用任何其他基础。
是否可以使基本X中的输出始终具有相同的长度?
我认为我应该使用“Multiplicative Inverse”和一些类似的映射和编码过程,但我不知道该怎么做...
我可以帮助创建这个吗?
基本上,我的目标是创建一个固定长度的INT(数据库中的ID),而不是创建随机固定长度代码以用于促销或ID混淆。
谢谢你, 米格尔
答案 0 :(得分:4)
如果我理解正确,你想用“零”填充生成的值。例如。如果您使用普通数字并且您想要一个长度为10且ID为1234的ID,则填充的ID将为0000001234。
最简单的方法是填充生成的值。您可以向BaseX
类添加新方法:
public string ToBaseX(int number, int width) {
var output = ToBaseX(number);
return output.PadLeft(width, _digits[0]);
}
使用此方法basex.ToBaseX(1002, 10)
返回
aaaaaaabmo
和basex.FromBaseX("aaaaaaabmo")
返回
1002
在评论中,您指出结果字符串aaaaaaabmo
似乎不是随机的。但是,您可以使用Eric Lippert在您所指的文章A practical use of multiplicative inverses中描述的方法。
首先,您需要为要混淆的数字选择一个上限(此数字应该适合32位整数)。 Eric Lippert使用了10亿(10亿)。然后,您需要选择一个小于极限的极限值(例如,它们不共享任何素因子)。 Eric Lippert选择了387420489(并解释说,以9结尾的任何数字都将是一个10的幂数的互质)。然后,您需要计算此数字的模乘乘数,例如,满足以下条件的数字inverse-x
:
387420489 * inverse-x = 1 (mod 1000000000)
您可以使用扩展欧几里德算法进行此计算,例如使用an online calculator。模乘法逆是513180409。
要对您的编号进行模糊处理,您可以使用此代码(为避免溢出,使用64位整数执行计算非常重要):
var value = 1002;
var m = 1000000000L;
var x = 387420489L;
var inverseX = 513180409L;
var encoded = value*x%m;
var decoded = encoded*inverseX%m;
对于此特定计算,encoded
为195329978。
如果您想使用小写字母来表示模糊编号,您可以使用BaseX
类将数字转换为基数26.您可以计算代表10亿以下任何数字所需的最大字母数:
Math.Log(1000000000)/Math.Log(26) = 6.36054383137796
这意味着您需要不超过7个字母来代表您的电话号码。
我已将所有这些结合到两个简单的方法中,使用一些您可以轻松自定义的常量:
static class Obfuscator {
const Int64 modulo = 1000000000L;
const Int64 coprime = 280619659L;
const Int64 inverseCoprime = 687208739L;
const String digits = "abcdefghijklmnopqrstuvwxyz";
const Int32 maxDigits = 7; // Math.Log(modulo)/Math.Log(digits.Length) rounded up.
public static String Obfuscate(Int32 originalValue) {
if (originalValue >= modulo || originalValue < 0)
throw new ArgumentOutOfRangeException();
var value = (Int32) (originalValue*coprime%modulo);
var buffer = new Char[maxDigits];
var i = maxDigits;
do {
buffer[--i] = digits[value%digits.Length];
value /= digits.Length;
} while (value > 0);
while (i > 0)
buffer[--i] = digits[0];
return new String(buffer);
}
public static Int32 Deobfuscate(String obfuscatedValue) {
if (String.IsNullOrEmpty(obfuscatedValue))
throw new ArgumentException();
var value = obfuscatedValue
.Aggregate(0, (a, c) => a*digits.Length + digits.IndexOf(c));
return (Int32) (value*inverseCoprime%modulo);
}
}
只有要注意的细节是0
被混淆为aaaaaaa
。对于介于1和999999999之间的任何数字(包括7和999字符),您将得到一个7个字符的随机字符串。