编码步骤:
1.设置一个D[k]数组D[0],...,D[k-1]用于存放原文字节数据,K为明文长度
2.设置一个C[k/2+1]数组,C[0],...,C[k/2]用于存放校验和
C[0] = 1
C[i] = (C[i-1] * 5 + (D[i * 2 -2] * 7 + D[i * 2 - 1])) % 36,i是从1到k/2的数组下标
3.设置一个二维数组T[k/2][5],T[0],...T[k/2-1]用于存放元组<a, b, c, d, e>
T[i] = <a, b, c, d, e>
a = (((D[i*2] >> 6) & 3) + C[i]) % 6;
b = (D[i*2] >> 2) & 15;
c = (D[i*2] & 3) + (C[i]/6) % 6;
d = (D[i*2+1] >> 4) & 15;
e = (D[i*2+1]) & 15;
4.设置一个数组P[3],用于存放三元组<a, b, c>
p = <a, b, c>
如果k是偶数:
a = C[k/2] % 6
b = 16
c = C[k/2] / 6
如果k是奇数:
a = (((D[k-1] >> 6) & 3) + C[k/2]) % 6;
b = (D[k-1] >> 2) & 15;
c = ((D[k-1] & 3) + C[k/2] / 6) % 6;
5.元音表(vowel table,用V表示)
0 - a
1 - e
2 - i
3 - o
4 - u
5 - y
6.常量表(consonant, 用C表示)
0 - b
1 - c
2 - d
3 - f
4 - g
5 - h
6 - k
7 - l
8 - m
9 - n
10 - p
11 - r
12 - s
13 - t
14 - v
15 - z
16 - x
7.依次对T[i] = <a, b, c, d, e>的元组进行编码,规则如下
V[a] C[b] V[c] C[d] '-' C[e]
8.在对编码后的元组后再加上对P编码的元组,规则如下
V[a] C[b] V[c]
9.最后再编码后的字符串的一头一尾加上x,结果如下
XE(T[1]) E(T[2]) ... E(T[|K/2|]) E(P)X
java实现编码和解码
public class MyBubbleBubble {
static final String vowels = "aeiouy";//元音表
static final String consonants = "bcdfghklmnprstvzx";//常量表
/**
* 对原文进行bubble bubble编码
* @param str 原文字符串
* @return 编码字符串
*/
static String encrypt(String str){
int k = str.length();//明文长度
byte[] D = str.getBytes();//字节数据
byte[] C = new byte[k/2+1];//校验和
int[][] T = new int[k/2][5];//5元组
int[] P = new int[3];//三元组
for(int i=0; i<k/2+1; i++){
C[i] = i==0 ? 1:(byte) ((C[i-1]*5 + D[(i+1)*2-3-1]*7 + D[(i+1)*2 - 2 -1]) % 36);
}
for(int i=0; i<k/2; ++i){//每两个数据构建一个五元组
int a = (((D[i*2] >> 6) & 3) + C[i]) % 6;
int b = (D[i*2] >> 2) & 15;
int c = (D[i*2] & 3) + (C[i]/6) % 6;
if(2*i+1 >= k)
break;
int d = (D[i*2+1] >> 4) & 15;
int e = (D[i*2+1]) & 15;
T[i][0] = a;
T[i][1] = b;
T[i][2] = c;
T[i][3] = d;
T[i][4] = e;
}
//三元组
P[0] = k%2 == 0 ? C[k/2] % 6 : (((D[k-1] >> 6) & 3) + C[k/2]) % 6;
P[1] = k%2 == 0 ? 16 : (D[k-1] >> 2) & 15;
P[2] = k%2 == 0 ? C[k/2] / 6 : ((D[k-1] & 3) + C[k/2] / 6) % 6;
String out = "x";
for(int i=0; i<T.length; i++){
out += vowels.charAt(T[i][0]) + ""+ consonants.charAt(T[i][1]) + vowels.charAt(T[i][2]) + consonants.charAt(T[i][3]) + "-" + consonants.charAt(T[i][4]);
}
out +=vowels.charAt(P[0]);
out +=consonants.charAt(P[1]);
out +=vowels.charAt(P[2]);
out += 'x';
System.out.println(out);
return out;
}
/**
* 对bubble bubble 编码的字符串进行解码
* @param str 编码字符串
* @return 原始数据
*/
public static String decrypt(String str){
int c = 1;
String output = "";
str = str.substring(1, str.length()-1);//取出x
HashMap<Integer, String> map = new HashMap<>();
for(int i=0, j=0; i<str.length(); i+=6, j++){//因为每6个字符中去除-就是一个五元组
map.put(j, str.substring(i, i+6 > str.length() ? str.length():i+6));
}
int lastTupple = map.size()-1;
for(Map.Entry<Integer, String> each: map.entrySet()){
int index = each.getKey();
String val = each.getValue();
ArrayList<String> tup = new ArrayList();
tup.add(""+vowels.indexOf(val.charAt(0)));
tup.add(""+consonants.indexOf(val.charAt(1)));
tup.add(""+vowels.indexOf(val.charAt(2)));
try{
tup.add(""+consonants.indexOf(val.charAt(3)));
tup.add("-");
tup.add(""+consonants.indexOf(val.charAt(5)));
}catch (Exception e){
}
int high = (Integer.parseInt(tup.get(0)) - (c % 6) + 6) % 6;
int mid = Integer.parseInt(tup.get(1));
int low = (Integer.parseInt(tup.get(2)) - (c/6%6) + 6) % 6;
byte b = (byte) (high << 6 | mid << 2 | low);
if(lastTupple == index){
if(!tup.get(1).equals("16")){
output += (char)b;
}
}else{
output += (char)b;
byte b1 = (byte) (Integer.parseInt(tup.get(3)) << 4 | Integer.parseInt(tup.get(5)));
output += (char)b1;
c = (c*5 + b*7 + b1) % 36;
}
}
System.out.println(output);
return output;
}
public static void main(String[] args) {
decrypt(encrypt("Pineapple"));
}
}