字符串的(编码/加密)与(解码/解密)

package com.gembler; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; /** * 字符串的(编码/加密)与(解码/解密)。 * * 规则: * * 在Base64中,码表是由[A-Z,a-z,0-9,+,/,=(pad)]组成的。 * 而在这里,码表由[a-z,2-7]组成的: * ----------------------------------------------- * a b c d e f g h i j k l m n o p q r * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 * ----------------------------------------------- * s t u v w x y z 2 3 4 5 6 7 * 18 19 20 21 22 23 24 25 26 27 28 29 30 31 * ------------------------------------------------ * * 在Base64中,是将二进制连成一串,然后再按6位来分割,分割完后在前面补0,这个地球人都知道,不多说了。 * 而在这里,在分割的那一步稍微有变动,是按5位来分割,如果刚好够分,那就好了,如果不够,那咋办呢? * * 在Base64中,是用"="来解决的吧。 * 而在这里,就是在前面补0,然后在后面再补零。 * * 例如:字符串 "aaa",(编码/加密)后是 "mfqwc" * * 二进制:01100001 01100001 01100001 * 转换后:(000)01100 (000)00101 (000)10000 (000)10110 (000)0001(0) * 十进制: 12 5 16 22 2 * 码表对应: m f q w c * * (解码/解密)就更简单了: * * 码表对应: m f q w c * 十进制: 12 5 16 22 2 * 二进制: 00001100 00000101 00010000 00010110 00000010 * 去前0后:01100 00101 10000 10110 00010 * 合并后: 0110000101100001011000010 * * 然后把合并后的串的长度除一下8,发现多了个0: * * 二进制:01100001 01100001 01100001 0 * * 多了就算了,不要了(其实是在{编码/加密}的分割时候,在分剩的余数的后面补的0)。 * 然后再将 byte[] 转回字符串,OK!又见"aaa"了。 * * 有一点值得注意的,UTF-8、GBK、GB18030 一般都没什么问题, * 但是 GB2312 可能字符集不够丰富,繁体字在decode的时候成问号了。 * * * @author gembler * @version 2008-12-3 下午03:01:50 * */ public class Codec { /** * 码表 */ private final static String CODEC_TABLE = "abcdefghijklmnopqrstuvwxyz234567"; /** * 表示5bit的字节 */ public final static int FIVE_BIT = 5; /** * 表示8bit的字节 */ public final static int EIGHT_BIT = 8; /** * 表示二进制 */ public final static int BINARY = 2; /** * (编码/加密)字符串,采用默认语言环境的 character set。 * * @author gembler * @version 2008-12-3 下午03:14:36 * * @param keys * 需要(编码/加密)的字符串 * * @return (编码/加密)后的字符串 */ public static String encode(String keys) { return encode(keys, null); } /** * (编码/加密)字符串 * * @author gembler * @version 2008-12-3 下午03:14:39 * * @param keys * 需要(编码/加密)的字符串 * @param characterSet * 字符集 * * @return (编码/加密)后的字符串 */ public static String encode(String keys, String characterSet) { if (keys == null || "".equals(keys)) { return ""; } byte[] keyBytes = null; if (characterSet == null || characterSet.length() < 1) { // 采用默认语言环境的 character set。 keyBytes = keys.getBytes(); } else { try { // 采用指定的 character set。 keyBytes = keys.getBytes(characterSet); } catch (UnsupportedEncodingException e) { // ignore... } } return encode(keyBytes); } /** * (编码/加密)字节数组 * * @author gembler * @version 2008-12-3 下午03:14:43 * * @param keyBytes * 需要(编码/加密)的字节数组 * * @return (编码/加密)后的字符串 */ private static String encode(byte[] keyBytes) { if (keyBytes == null || keyBytes.length < 1) { return ""; } /* * 合并二进制码, * 如: * 00101010 11010011 00101101 10100011 * to * 00101010110100110010110110100011 */ StringBuilder mergrd = new StringBuilder(); for (int i = 0; i < keyBytes.length; i++) { FormatUtil.formatBinary(keyBytes[i], mergrd); } /* * 以5个bit为单位,计算能分多少组, * 如: * 00101010110100110010110110100011 * to * 00101 01011 01001 10010 11011 01000 11 * | * (这个11为余下的位) */ int groupCount = mergrd.length() / FIVE_BIT; // 计算余下的位数 int lastCount = mergrd.length() % FIVE_BIT; // 类似数据分页的算法,有余数的情况下需要加 1。 if (lastCount > 0) { groupCount += 1; } /* * (编码/加密) */ StringBuilder sbEncoded = new StringBuilder(); // 循环所需的条件 int forMax = groupCount * FIVE_BIT; // 每次递增5位来截取 for (int i = 0; i < forMax; i += FIVE_BIT) { // 结束点 int end = i + FIVE_BIT; /* * 如果结束点比已合并的二进制码串的长度要大, * 相当于有余数, * 并且表示当前循环到了(已合并的二进制码串的长度 % FIVE_BIT)的那一截。 */ // 标记是否到了余数的那一截 boolean flag = false; if (end > mergrd.length()) { /* * 如果结束点比已合并的二进制码串的长度要大, * 结束点需要被重设为: * 已合并的二进制码串的长度,等价于(i + lastCount). 并且重设标记。 */ end = (i + lastCount); flag = true; } // 截取 String strFiveBit = mergrd.substring(i, end); // 截取后从二进制转为十进制 int intFiveBit = Integer.parseInt(strFiveBit, BINARY); if (flag) { /* * 如果结束点比已合并的二进制码串的长度要大, * 或者是到了余数的那一截: * 需要左移操作,假设余下的二进制位为:11, * 那么需要从后面补0,左移操作后为 (000)11(000) */ intFiveBit <<= (FIVE_BIT - lastCount); } // 利用该十进制数作为码表的索引获取对应的字符,并追加到sbEncoded sbEncoded.append(CODEC_TABLE.charAt(intFiveBit)); } return sbEncoded.toString(); } /** * (解码/解密)字符串,采用默认语言环境的 character set。 * * @author gembler * @version 2008-12-3 下午03:14:57 * * @param code * 需要(解码/解密)的字符串 * * @return (解码/解密)后的字符串 */ public static String decode(String code) { return decode(code, null); } /** * (解码/解密)字符串 * * @author gembler * @version 2008-12-3 下午03:15:00 * * @param code * 需要(解码/解密)的字符串 * @param characterSet * 字符集 * * @return (解码/解密)后的字符串 */ public static String decode(String code, String characterSet) { if (code == null || code.length() < 1) { return ""; } /* * 拆除每一个字符,从码表里获取相应的索引。 */ StringBuilder sbBinarys = new StringBuilder(); for (int i = 0; i < code.length(); i++) { // 从码表里获取相应的索引 int index = getCodecTableIndex(code.charAt(i)); // 将十进制的索引转换为二进制串 String indexBinary = Integer.toBinaryString(index); // 去掉前3个0,并且追加到sbBinarys FormatUtil.formatBinary(indexBinary, sbBinarys, FIVE_BIT); } /* * 按8个bit拆分,剩下的余数扔掉。 * 扔掉的余数是在(编码/加密)的分割时候,在分剩的余数的后面补的0 */ byte[] binarys = new byte[sbBinarys.length() / EIGHT_BIT]; for (int i = 0, j = 0; i < binarys.length; i++) { // 每8个bit截取一份 String sub = sbBinarys.substring(j, j += EIGHT_BIT); // 将截取下来的二进制串转换为十进制 Integer intBinary = Integer.valueOf(sub, BINARY); binarys[i] = intBinary.byteValue(); } String decoded = null; if (characterSet == null || characterSet.length() < 1) { // 采用默认语言环境的 character set。 decoded = new String(binarys); } else { try { // 采用指定的 character set。 return new String(binarys, characterSet); } catch (UnsupportedEncodingException e) { // ignore... } } return decoded; } /** * 根据所给出的字符,遍历CODEC_TABLE,返回对应的下标。 * 如果没找到,则返回 -1。 * * @author gembler * @version 2008-12-3 下午03:14:53 * * @param code * 在CODEC_TABLE范围内的字符。 * * @return 字符在CODEC_TABLE里对应的下标,如果没找到,则返回 -1。 */ private static int getCodecTableIndex(char code) { for (int i = 0; i < CODEC_TABLE.length(); i++) { if (CODEC_TABLE.charAt(i) == code) { return i; } } return -1; } /** * 测试 * * @author gembler * @version 2008-12-3 下午03:05:52 * * @param args */ public static void main(String[] args) { try { BufferedReader br = new BufferedReader(new InputStreamReader( System.in)); while (true) { System.out.print("输入字符号串:"); String in = br.readLine(); if ("exit".equalsIgnoreCase(in)) { break; } String enCode = Codec.encode(in); String deCode = Codec.decode(enCode); System.out.println(); System.out.println("------------------------------test"); System.out.println("original: " + in); System.out.println("encode: " + enCode); System.out.println("decode: " + deCode); System.out.println("------------------------------test"); System.out.println(); } } catch (IOException e) { e.printStackTrace(); } } }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值