最近一直在介绍密码学的相关知识,但是理论的知识总是枯燥的,需要来点实战,为此我在研究了DES的算法后,发现可以从这里入手进行开发—————那就是字符串转二进制。
这个也比较简单,八进制转二进制可以根据八进制按位进行分割,每位替换成三位二进制数(因为2^3=8),十六进制则是四位。
为了方便起见,我们先设置一个枚举类型,就叫做进制(EncodeRadix) 如下图所示,有什么用之后再说:
/**
* 枚举类型
* @author zygswo
*
*/
public enum EncodeRadix{
DEC(10,null),
OCT(8,3),
HEX(16,4),
BINARY(2,1);
private int value = 2;
private Integer length = 1;
private EncodeRadix(int value, Integer length) {
this.value = value;
this.length = length;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
}
解释一下,第一个参数是位的进制值,第二个为转换成二进制所需要的位数。
下面是创建一个进制数表,以十六进制为例,为何这里要创建进制表呢?大家都知道数组查询是O(1)级别的,那么查询速度会很快,并且能够获取每一位字符对应的值,如“1”对应 1,“2”对应2,"A"对应10等。
private static char[] HEX_TABLE = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
接下去就是转换的代码了,转换也很简单,只要把每一位进制数和进制数表中的数据一一对应起来,之后再获取每一位的值,再转成二进制即可。当然,在转换前我们需要查询当前的字符串和输入的枚举类型所对应的进制值是否匹配,代码如下:
/**
* 判断是否属于该进制
* @param text 要转的文本
* @param radix 原进制
* @return
*/
private static boolean verifyRadix(String text, EncodeRadix radix) {
int value = radix.getValue();
String str = new String(HEX_TABLE);
for(char ch : text.toCharArray()) {
int index = str.indexOf(ch);
if (index <0 || index >= value) {
return false;
}
}
return true;
}
这里就体现了枚举类型的好处了,我们获取枚举类型的第一个参数值,也就是枚举类型对应的进制值,然后判断text文本是否符合规则即可(循环遍历每一位上的数)。这里将进制转换成String类型的目的是为了更快的获取每位上的字符对应的该进制数值。(用indexOf获取,也就是说下标即进制数值)
接下去我们就可以进行进制的转换了,代码如下:
/**
* 转2进制(10进制、16进制和8进制转成二进制)
* @param text 要转的文本
* @param radix 原进制
* @return
*/
public static String toBinary(String text, EncodeRadix radix) {
//判断是否符合进制规则
if (!verifyRadix(text, radix)) {
throw new RuntimeException("进制有误");
}
//将进制数表转换成String类型,好处是可以更快的获取每个位的该进制数值
String str = new String(HEX_TABLE);
StringBuilder result = new StringBuilder("");
//10转2进制
if (radix.getValue() == 10) {
long l = Long.valueOf(text);
while(l > 0) {
result.append(l % 2);
l = l >> 1;
}
result = result.reverse();
} else {
//16、8转2进制
//取每一位上的数字
for(char ch : text.toCharArray()) {
int index = str.indexOf(ch);
int res = index, pre = index;
String res1 = "";
//keypoint1:关键点一
while(res > 0) {
res = res >> 1 << 1;
res1 = ((pre ^ res) == 0 ? "0" : "1") + res1; //异或判断当前位上数字是否为1
res = res >> 1;
pre = pre >> 1;
}
//keypoint1:关键点二
//扩充n位
while (radix.getLength()!= null &&
res1.length() < radix.getLength()) {
res1 = "0" + res1;
}
result.append(res1);
}
}
return result.toString();
}
关键点1: 使用了位运算
这样做无疑会增加理解成本,但是可以减少运算耗时成本。那么怎么理解这几行代码呢?
举例:输入为10,即(1010)2,
首先res表示每次将末尾的数字替换为0后前面几位数的值,即在第一轮为(1010)2,第二轮为(0100)2 [逻辑右移一位,后末尾改为0]
而pre表示原来的数据,末尾不用0替换,即在第一轮为(1010)2,第二轮为(0101)2 [逻辑右移一位,后末尾改为0]
大家看到这里应该就能猜到后续了,就是拿res和pre进行异或运算,如果为0就表示末尾数字为0,为1就表示末尾数字为1,这样就能够获取每次循环后最右位(末尾位)的数值。之后再每次对pre和res进行逻辑右移即可,直至res为0。
关键点二:扩充运算
位扩充是为了弥补位数不够的情况,注意补位在前。
最后通过stringbuilder的tostring就能获取二进制的字符串了,而且不限位数。
这里我们先上代码:
/**
* 转2进制(字符串转成二进制)
* @param text 要转的文本
* @return
*/
public static String strtoBinary(String text) {
StringBuilder result = new StringBuilder("");
//取每一位上的数字
for(char ch : text.toCharArray()) {
int res = ch, pre = ch;
String res1 = "";
while(res > 0) {
res = res >> 1 << 1;
res1 = ((pre ^ res) == 0 ? "0" : "1") + res1; //异或判断当前位上数字是否为1
res = res >> 1;
pre = pre >> 1;
}
//扩充至8位
while (res1.length() < 8) {
res1 = "0" + res1;
}
result.append(res1);
}
return result.toString();
}
就讲一下变化的部分,一个是获取的字符串的值没有进制了,二是直接将字符串转换成ascii码再进行运算。
整体代码如下:
package common;
/**
* 进制转换类
* @author zygswo
*
*/
public class EncodeUtil {
private static char[] HEX_TABLE = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/**
* 枚举类型
* @author zygswo
*
*/
public enum EncodeRadix{
DEC(10,null),
OCT(8,3),
HEX(16,4),
BINARY(2,1);
private int value = 2;
private Integer length = 1;
private EncodeRadix(int value, Integer length) {
this.value = value;
this.length = length;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
}
/**
* 转2进制(10进制、16进制和8进制转成二进制)
* @param text 要转的文本
* @param radix 原进制
* @return
*/
public static String toBinary(String text, EncodeRadix radix) {
if (!verifyRadix(text, radix)) {
throw new RuntimeException("进制有误");
}
String str = new String(HEX_TABLE);
StringBuilder result = new StringBuilder("");
System.out.println(text);
//10转2进制
if (radix.getValue() == 10) {
long l = Long.valueOf(text);
while(l > 0) {
result.append(l % 2);
l = l >> 1;
}
result = result.reverse();
} else {
//16、8转2进制
//取每一位上的数字
for(char ch : text.toCharArray()) {
int index = str.indexOf(ch);
int res = index, pre = index;
String res1 = "";
while(res > 0) {
res = res >> 1 << 1;
res1 = ((pre ^ res) == 0 ? "0" : "1") + res1; //异或判断当前位上数字是否为1
res = res >> 1;
pre = pre >> 1;
}
//扩充n位
while (radix.getLength()!= null &&
res1.length() < radix.getLength()) {
res1 = "0" + res1;
}
System.out.println("res1 = " + res1);
result.append(res1);
}
}
return result.toString();
}
/**
* 转2进制(字符串转成二进制)
* @param text 要转的文本
* @return
*/
public static String strtoBinary(String text) {
StringBuilder result = new StringBuilder("");
//取每一位上的数字
for(char ch : text.toCharArray()) {
int res = ch, pre = ch;
String res1 = "";
while(res > 0) {
res = res >> 1 << 1;
res1 = ((pre ^ res) == 0 ? "0" : "1") + res1; //异或判断当前位上数字是否为1
res = res >> 1;
pre = pre >> 1;
}
//扩充至8位
while (res1.length() < 8) {
res1 = "0" + res1;
}
// System.out.println("res1 = " + res1);
result.append(res1);
}
return result.toString();
}
/**
* 转字符串(二进制转成字符串)
* @param encodedText 二进制文本
* @return
*/
public static String binaryToStr(String encodedText) {
int count = 8,chNum = 0;
StringBuilder result = new StringBuilder("");
//取每一位上的数字
for(char ch : encodedText.toCharArray()) {
chNum += (ch - '0') << (--count);
// System.out.println("count=" + count);
// System.out.println("ch=" + ch);
// System.out.println("chNum=" + chNum);
if (count == 0) {
count = 8;
char res = (char)chNum;
result.append(res);
chNum = 0;
}
}
return result.toString();
}
/**
* 判断是否属于该进制
* @param text 要转的文本
* @param radix 原进制
* @return
*/
private static boolean verifyRadix(String text, EncodeRadix radix) {
int value = radix.getValue();
String str = new String(HEX_TABLE);
for(char ch : text.toCharArray()) {
int index = str.indexOf(ch);
if (index <0 || index >= value) {
return false;
}
}
return true;
}
public static void main(String[] args) {
System.out.println(toBinary("123456789", EncodeRadix.HEX));
}
}
———————————————小尾巴——————————————————
未完待续