前言
这是笔试的一道题目,挺有意思的,就做了个总结
题目:
现有某移位加密算法,对明文字符串的每个字符进行不同的移位来实现加密,例如:
明文:hello world
密码:big
密文:imrmw cpzre
本例中,h由密码b(相对a的位移为1)移位到i,e由密码i(位移8)移位到m,
l由密码g(位移6)移位到r,l由密码b(位移1)移位到m,o由密码i移位到w,
空格保持不变,w由密码g移位到c(z之后又从a开始),其余依次类推。
请根据上面的描述,编写代码实现根据用户输入的密码对明文字符(只包含小写英文字母和空格)进行加密处理。
解题代码:
package com.guo.bishi;
import java.util.Scanner;
/**
* @Author FireLightGuo
* @Date 2021/10/30 13:46
**/
public class ShiftEncrypt {
/*
(plainText)明文
(code)密码
(cipherText)密文
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String plainText = sc.nextLine();
String code = sc.nextLine();
String cipherText = encrypt(plainText, code);
System.out.println(cipherText);
}
/**
* 加密算法
* @param plainText 明文
* @param code 密码
* @return 加密后的密文
*/
public static String encrypt(String plainText, String code) {
// 明文的字符数组
char[] plainChars = plainText.toCharArray();
// 密文的字符数组,待填充
char[] cipherChars = new char[plainChars.length];
// 根据密码计算出的位移量
int[] shifts = new int[code.length()];
// 密码的字符数组
char[] codes = code.toCharArray();
// 计算出位移量数组
for (int i = 0; i < shifts.length; i++) {
shifts[i] = codes[i] - 'a';
}
/**
* 将明文字符数组加密
* i指向待加密的明文字符,j指向位移量,j需要循环+1,通过对位移数组长度取模实现
*/
for (int i = 0, j = 0;
i < plainChars.length;
i++, j = (j+1) % shifts.length ) {
if (plainChars[i] == ' ') { // 空格保持原样
cipherChars[i] = ' ';
j--; // (与for循环中的j+1抵消)保持位移量下标不变
} else {
// 计算出加密后的字符的ASCII编码值
int codeOfChar = plainChars[i]+shifts[j];
// 如果编码值大于’z‘,需要根据字母表顺序循环移动,如’z‘ + 2 ==> 'b'
if (codeOfChar > 'z') {
codeOfChar = (codeOfChar - ('z'-'a'+1));
}
cipherChars[i] = (char) codeOfChar;
}
}
return new String(cipherChars);
}
}
总结
当时笔试的时候时间不够,没做出来,现在把这些遗憾补上。
这道题总体不难,只是有一些细节需要注意,比如:
- java char类型的运算,
- 如:当char与int类型运算时,char会自动转换为int类型 ,所以需要再次强制转换得到char类型
- 例子:
char a = 'a'; int i = a + 2; // 结果为int类型的99,即‘a’的Unicode编码97再加上2 char c = (char) (a + 2); // 结果为'c',即99对应的unicode字符 ‘c’
- 如:当char与int类型运算时,char会自动转换为int类型 ,所以需要再次强制转换得到char类型
- for循环中的 j 需要循环+1;
- 加密后的字符需要判断是否超过了’z’,超过就需要从a开始
- 这里的具体实现也挺细节的,需要减去(‘z’-‘a’ + 1),细节就是这里的+1