输入一个字符串,如何将字符随机打乱顺序,生成新的字符串?且新字符串仍可还原为原字符串。
一、正变换
思路:
1、计算出待变换的字符串长度 length ,生成一个长度为 length 的 int 数组,且数组中的各个值为
0 - (length - 1) 之间的所有整数值。
2、将原字符串按照整形数组设置的规则做相应变换,得出变换后的字符串。
例如,原字符串为 “bcKM1A7B3q”,字符串长度为 10。定义乱序整形数组 int[] varyIndex = {2, 6, 8, 4, 1, 5, 9, 3, 7, 0} ,数组长度为 10,且各个节点值为 0 - 9 之间的不重复的整数值(具体生成不重复乱序数组的方法可见本人另一篇博客 乱序且不重复的输出 0 - 99 之间的所有整数)。int数组第0个位置上的值为2, 表示原字符串第一个字符 ‘b’ 应该放到新字符串的第2个位置上(位置从0开始)。int数组第1个位置上的值为6, 表示原字符串第二个字符 ‘c’ 应该放到新字符串的第6个位置上。依此类推,将所有字符串移动完毕即完成字符变换。移位后,字符串为:q1bBMAc3K7。
二、字符串还原
思路:
根据正变换思路,较易得出逆变换流程。int[] varyIndex = {2, 6, 8, 4, 1, 5, 9, 3, 7, 0} ,即原字符串第 0 个字符为新字符串的第 2 位(位置从 0 开始),原字符串第 1 个字符为新字符串的第 6 位。依此类推,将所有字符串得出,即可恢复出原来字符串。
三、源码如下
package com.example.demo.utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
/**
* @description 字符串移位变换和还原
* @date 2019/3/13 10:33
*/
public class CheckCodeUtil {
private static Logger logger = LoggerFactory.getLogger(CheckCodeUtil.class);
// 原字符串长度为10位
private static int range = 10;
private static int[] varyIndex = {2, 6, 8, 4, 1, 5, 9, 3, 7, 0};
public static void main(String[] args) {
// 原字符串
String content = "bcKM1A7B3q";
logger.info("原字符串为:{}", content);
String code = varyStr(content);
logger.info("移位后的字符串为:{}", code);
// 字符串还原
String decodeStr = decode(code);
logger.info("字符串还原为:{}", decodeStr);
}
/**
* 字符串按照 varyIndex 规则进行移位变换
*
* @param content 待变换的字符串
* @return 返回值如下
* 1、正常流程对传入字符串做字符移位变换,返回变换后的字符串;
* 2、当传入参数不符合格式要求时,返回 null。
*/
private static String varyStr(String content) {
// 校验参数非空且字符长度合法
if (StringUtils.isEmpty(content) || content.length() != range) {
logger.warn("content为空或字符串长度不符");
return null;
} else {
// 参数合法,通过校验。将待变换的字符串按照变换规则生成新字符串
char chars[] = new char[range];
for (int i = 0; i < range; i++) {
// 将content字符串各个字符依次按照varyIndex设置的规则放置于chars数组中对应的index处
// 例如:varyIndex[0] = 6,则将字符串第一个字符存储于数组第7位
chars[varyIndex[i]] = content.charAt(i);
}
// 将chars数组生成字符串并返回
return new String(chars);
}
}
/**
* 字符串逆变换
*
* @param checkCode 待还原的字符串
* @return 返回原字符串
* 1、checkCode 合法时,返回还原后的字符串;
* 2、checkCode 非法时,返回 null。
*/
private static String decode(String checkCode) {
if (StringUtils.isEmpty(checkCode) || checkCode.length() != range) {
logger.warn("checkCode为空或长度非10位");
return null;
} else {
StringBuilder decodeStr = new StringBuilder();
for (int i = 0; i < range; i++) {
decodeStr.append(checkCode.charAt(varyIndex[i]));
}
return decodeStr.toString();
}
}
}
/**
22:03:30.700 [main] INFO com.example.demo.utils.CheckCodeUtil - 原字符串为:bcKM1A7B3q
22:03:30.724 [main] INFO com.example.demo.utils.CheckCodeUtil - 移位后的字符串为:q1bBMAc3K7
22:03:30.725 [main] INFO com.example.demo.utils.CheckCodeUtil - 字符串还原为:bcKM1A7B3q
**/