假设我有
String input = "1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,0,4,0,0,0,4,0,3";
我想将它编码为一个字符较少的字符串,实际上通过用罗马字符IE表示它来隐藏实际信息。以上编码为"Adqwqkjlhs"
。如果给定编码字符串,则必须能够解码为原始字符串。
字符串输入实际上是我从URL的散列中解析的内容,但原始格式很长并且可以操作。
有什么想法吗?
由于
编辑#1
数字可以是0到99,每个数字用逗号分隔String.split(“,”)来检索String []
编辑#2(编码字符串的目的)
假设上面的字符串编码为bmtwva1131gpefvb1xv
,那么我可以使用www.shortstring.com/input#bmtwva1131gpefvb1xv
之类的URL链接。从那里我将bmtwva1131gpefvb1xv
解码为逗号分隔数字。
答案 0 :(得分:1)
如何将其保存为36号码?
在Java中将是
new java.math.BigInteger("120000000000000000012230400403").toString(36)
将评估为"bmtwva1131gpefvb1xv"
您将使用
返回原始号码new java.math.BigInteger("bmtwva1131gpefvb1xv", 36)
这是一个很好的观点,这不会处理领先的0(Thilo的建议添加领先的1将起作用)。关于逗号:如果数字大小相等(01而不是1),那么我认为不需要逗号。
答案 1 :(得分:1)
这与Nathan Hughes的解决方案并没有太大的改善,但是Strings的时间越长,你获得的节省就越多。
编码:创建一个以“1”开头的字符串,使源字符串中的每个数字都为2位,因此“0”变为“00”,“5”变为“05”,“99”变为“99”等等。将结果数字表示在基数36中。
解码:取基数为36的数字/字符串,将其更改回基数10,跳过第一个“1”,然后将每2个数字/字母转换为int并重建原始字符串。
示例代码:
String s = "1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,0,4,0,0,0,4,0,3";
// ENCODE the string
StringTokenizer tokenizer = new StringTokenizer(s,",");
StringBuilder b = new StringBuilder();
b.append("1"); // This is a primer character, in case we end up with a bunch of zeroes at the beginning
while(tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken().trim();
if(token.length()==1) {
b.append("0");
b.append(token);
}
else {
b.append(token);
}
}
System.out.println(b);
// We get this String: 101020000000000000000000000000000000000010202030004000000040003
String encoded = (new BigInteger(b.toString())).toString(36);
System.out.println(encoded);
// We get this String: kcocwisb8v46v8lbqjw0n3oaad49dkfdbc5zl9vn
// DECODE the string
String decoded = (new BigInteger(encoded, 36)).toString();
System.out.println(decoded);
// We should get this String: 101020000000000000000000000000000000000010202030004000000040003
StringBuilder p = new StringBuilder();
int index = 1; // we skip the first "1", it was our primer
while(index<decoded.length()) {
if(index>1) {
p.append(",");
}
p.append(Integer.parseInt(decoded.substring(index,index+2)));
index = index+2;
}
System.out.println(p);
// We should get this String: 1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,0,4,0,0,0,4,0,3
我不知道将一个大数字变成基数64的简单方法。精心挑选的符号(如+,, - )可以进行URL编码,所以0-9,az,AZ,使用“”和“ - ”使64.BigInteger.toString()方法只占用Character.MAX_RADIX,即36(无大写字母)。如果你能找到一种方法来取大数并改为base 64,那么生成的编码字符串将更短。
编辑:看起来这样做适合你:http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html
答案 2 :(得分:0)
建议您查看base64,每个字符提供6位信息 - 通常,您的编码效率为每个符号的log 2 (K)位,其中K是符号数在允许符号集中。
对于8位字符集,其中许多是URL中不允许的,因此您需要选择一些合法URL字符的子集。
只是为了澄清:我并不是要编码你的“1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,1,2,2,3,0,4,0,0,0,4,0,3“string as base64 - 我的意思是找出你真正想要编码的信息,表示为一串原始信息二进制字节,并在base64中编码 。它将排除控制字符(尽管您可能希望使用alternate form,其中所有64个字符都可以在URL中使用而不会转义)并且比将数字转换为可打印的数字形式更有效。
数字可以是0到99,每个数字用逗号分隔String.split(“,”)来检索String []
好的,现在你有一个明确的定义。这是一个建议:
将您的信息从其原始格式转换为二进制数字/字节数组。如果您拥有的是一串逗号分隔的数字,从0到99,那么这里有两个选项:
(慢) - 在基数100中视为数字,转换为BigInteger(例如,对于数组中的每个数字x,n = n * 100 + x [i]),转换为字节数组,以及确保在整个事物的长度之前,以便“0,0,0,0”可以与“0,0”区分开(在数字上等于100,但它有不同的长度。然后将结果转换为base64
(更有效率) - 将基数128视为数字(因为它是2的幂),并使用100-127中的任何数字作为终止字符。因此,每个6个数字的块包含42(= 6 * 7)位信息,可以使用base64将其编码为7个字符的字符串。 (根据需要填充终止字符,以达到原始数字的6个偶数倍。)
因为你有一个可能变长的数字数组作为输入,你需要以某种方式编码长度 - 直接作为前缀,或间接使用终止字符。
对于逆算法,只需反转步骤,您将得到一个0到99之间的数字数组 - 使用前缀长度或终止字符来确定数组的大小 - 您可以将其转换为用逗号分隔的人类可读字符串。
如果您可以在将原始信息编码为字符串之前以原始二进制形式访问原始信息,请使用该信息。 (但请发布有关该信息的输入格式要求的问题)
答案 3 :(得分:0)
如果数字介于0到255之间,则可以从中创建一个字节数组。一旦你有一个字节数组,你有manu选择:
要转换回来,你显然必须以相反的方式应用所选择的算法。
答案 4 :(得分:0)
修改过的UUENCODE: -
将二进制文件拆分为6位组
创建一个包含64个字符的数组(选择允许的字符并按ASCII顺序保存以便于搜索): - 0..9,A..Z,_,a..z,〜
二进制和字符之间的映射。