我想实现一个简单的替换密码来屏蔽URL中的私有ID。
我知道我的ID会是什么样子(大写ASCII字母,数字和下划线的组合),并且它们将很长,因为它们是组合键。我想使用更长的字母来缩短生成的代码(我想使用大写和小写ASCII字母,数字以及其他任何东西)。所以我传入的字母是
[A-Z0-9_] (37 chars)
我传出的字母是
[A-Za-z0-9] (62 chars)
因此可以使用 接近50%的 合理压缩量。
假设我的网址如下所示:
/my/page/GFZHFFFZFZTFZTF_24_F34
我希望他们看起来像这样:
/my/page/Ft32zfegZFV5
显然,两个数组都将被改组以引入一些随机顺序。
这不一定是安全的。如果有人弄清楚了:很好,但是我不希望该计划变得显而易见。
我想要的解决方案是将字符串转换为基数37的整数表示形式,将基数转换为62并使用第二个字母写出该数字。有没有提供类似功能的示例代码?Integer.parseInt()具有类似的逻辑,但是使用标准数字行为进行了硬编码。
Integer.parseInt()
有任何想法吗?
我正在使用Java来实现此目的,但是使用任何其他语言的代码或伪代码当然也有帮助。
莫名其妙地Character.MAX_RADIX只有36,但是您始终可以编写自己的基本转换例程。以下实现不是高性能的,但它应该是一个很好的起点:
Character.MAX_RADIX
import java.math.BigInteger; public class BaseConvert { static BigInteger fromString(String s, int base, String symbols) { BigInteger num = BigInteger.ZERO; BigInteger biBase = BigInteger.valueOf(base); for (char ch : s.toCharArray()) { num = num.multiply(biBase) .add(BigInteger.valueOf(symbols.indexOf(ch))); } return num; } static String toString(BigInteger num, int base, String symbols) { StringBuilder sb = new StringBuilder(); BigInteger biBase = BigInteger.valueOf(base); while (!num.equals(BigInteger.ZERO)) { sb.append(symbols.charAt(num.mod(biBase).intValue())); num = num.divide(biBase); } return sb.reverse().toString(); } static String span(char from, char to) { StringBuilder sb = new StringBuilder(); for (char ch = from; ch <= to; ch++) { sb.append(ch); } return sb.toString(); } }
然后,您可以使用如下所示的main()测试工具:
main()
public static void main(String[] args) { final String SYMBOLS_AZ09_ = span('A','Z') + span('0','9') + "_"; final String SYMBOLS_09AZ = span('0','9') + span('A','Z'); final String SYMBOLS_AZaz09 = span('A','Z') + span('a','z') + span('0','9'); BigInteger n = fromString("GFZHFFFZFZTFZTF_24_F34", 37, SYMBOLS_AZ09_); // let's convert back to base 37 first... System.out.println(toString(n, 37, SYMBOLS_AZ09_)); // prints "GFZHFFFZFZTFZTF_24_F34" // now let's see what it looks like in base 62... System.out.println(toString(n, 62, SYMBOLS_AZaz09)); // prints "ctJvrR5kII1vdHKvjA4" // now let's test with something we're more familiar with... System.out.println(fromString("CAFEBABE", 16, SYMBOLS_09AZ)); // prints "3405691582" n = BigInteger.valueOf(3405691582L); System.out.println(toString(n, 16, SYMBOLS_09AZ)); // prints "CAFEBABE" }
BigInteger
long
char
String
通常,您不能期望基数62的字符串短于基数36的字符串一半。这Long.MAX_VALUE是以10、20和30为基数的:
Long.MAX_VALUE
System.out.format("%s%n%s%n%s%n", Long.toString(Long.MAX_VALUE, 10), // "9223372036854775807" Long.toString(Long.MAX_VALUE, 20), // "5cbfjia3fh26ja7" Long.toString(Long.MAX_VALUE, 30) // "hajppbc1fc207" );