数值与字符串转换算法

很多场景需要将数据库记录主键发送到前端,对于递增或趋势递增的主键很容易被恶意用户推测出来,因此需要一种可逆性的算法能够将数值型与字符串进行互换。

方案一(数组)、
1.随机生成一个种子([1-9]内的正整数)

int seed = new Random().nextInt(10); // 0要排除掉

2.随意一个十进制的数值,每一位都是有[0-9]组成的,所以[0-9] * seed = [0-81],因此我们需要至少82个不重复的字符

'u','4','+','1','2','I','B','U','x','z','@','c','M','G','f','<','b','(','O','T','H','=','C','D','$','&','p','d','m','o','i','n','a','Z','_','s','3','^','*','P','8','%','/','l','F','R','r','A','9','y','v','.','#','N','g','e','>',')','t','!','5','7','`','?','h','V','S','Q','0','X','K','j','W','J','q','w','|','E','6','k','L','Y'

3.以数值【52337610997641216】举例说明,假设seed取值为3
数值–>字符串

5 2 3 3 7 6 1 0 9 9 7 6 4 1 2 1 6
5*seed 2*seed 3*seed 3*seed 7*seed 6*seed 1*seed 0*seed 9*seed 9*seed 7*seed 6*seed 4*seed 1*seed 2*seed 1*seed 6*seed
15 6 9 9 21 18 3 0 27 27 21 18 12 3 6 3 18
< B z z = O 1 u d d = O M 1 B 1 O

最终得到字符串:

字符串–>数值

< B z z = O 1 u d d = O M 1 B 1 O
15 6 9 9 21 18 3 0 27 27 21 18 12 3 6 3 18
15/seed 6/seed 9/seed 9/seed 21/seed 18/seed 3/seed 0/seed 27/seed 27/seed 21/seed 18/seed 12/seed 3/seed 6/seed 3/seed 18/seed
5 2 3 3 7 6 1 0 9 9 7 6 4 1 2 1 6

最终还原数值:52337610997641216

优点:算法简单
缺点:1.一次转换中,相同的数值对应的字符相同,容易让恶意用户推测出算法;2.种子只有9个取值,因此一个数值最多只有9种组合方式,第十次一定会出现重复。

一定要保证随意两个数相乘的最大值要小于等于不重复的字符个数。因为如果最大值大于字符个数,就会出现两个数对应同一个字符,在字符串反转为数值就可能出现错误(当然可以增加标识为,但是会导致字符串边长切算法更复杂,而且我们也没有这么多不重复的英文字符可用)


方案二(环路)、
方案二主要针对方案一的缺点进行改进。
1.还是用方案一中的82个字符组合,只不过在方案一是数组格式,方案二我们改进成环,将82个字符收尾相连组成一个环路。

数值与字符串转换算法_第1张图片

2.生成种子
由于82个字符都不重复,[0-81]范围内的正整数都可以作为种子

int seed = new Random().nextInt(82);

3.以数值【52337610997641216】举例说明,假设seed取值为45
n = 1 --> offset1 = seed + number(1);
n > 1 --> offset(n) = offset(n-1) + number(n)

数值–>字符串

5 2 3 3 7 6 1 0 9 9 7 6 4 1 2 1 6
(45+5)%82 (50+2)%82 (52+3)%82 (55+3)%82 (58+7)%82 (65+6)%82 (71+1)%82 (72+0)%82 (72+9)%82 (81+9)%82 (90+7)%82 (97+6)%82 (103+4)%82 (107+1)%82 (108+2)%82 (110+1)%82 (111+6)%82
50 52 55 58 65 71 72 72 81 8 15 21 25 26 28 29 35
v # e t V j W W Y x < = & p m o s

最终得到字符串:v#etVjWWYx<=&pmos

字符串–>数值
n = 1 --> val(1) = index(1) - seed;
n > 1 --> val(n) = index(n) - index(n-1);

v # e t V j W W Y x < = & p m o s
50 52 55 58 65 71 72 72 81 8 15 21 25 26 28 29 35
50-45 52-50 55-52 58-55 65-58 71-65 72-71 72-72 81-72 90-81 15-8 21-15 25-21 26-25 28-26 29-28 35-29
5 2 3 3 7 6 1 0 9 9 7 6 4 1 2 1 6

最终还原数值:52337610997641216

优点:改进了方案一中的两个缺点
缺点:如果数组中有0,则相邻两位字符相同

方案三(环路+m)、
方案三主要针对方案二的缺点进行改进。假设m=1

n = 1 --> offset1 = seed + number(1) + m;
n > 1 --> offset(n) = offset(n-1) + number(n) + m

数值–>字符串

5 2 3 3 7 6 1 0 9 9 7 6 4 1 2 1 6
(45+5)%82+1 (51+2)%82+1 (54+3)%82+1 (58+3)%82+1 (62+7)%82+1 (70+6)%82+1 (77+1)%82+1 (79+0)%82+1 (80+9)%82+1 (90+9)%82+1 (100+7)%82+1 (108+6)%82+1 (115+4)%82+1 (120+1)%82+1 (122+2)%82+1 (125+1)%82+1 (127+6)%82+1
51 54 58 62 70 77 79 80 8 18 26 33 38 40 43 45 52
. g t ` K E k L x O p Z * 8 l R #

最终得到字符串:v#etVjWWYx<=&pmos

字符串–>数值
n = 1 --> val(1) = (index(1) - 1) - seed;
n > 1 --> val(n) = (index(n) - 1) - index(n-1);

. g t ` K E k L x O p Z * 8 l R #
51 54 58 62 70 77 79 80 8 18 26 33 38 40 43 45 52
(51-1)-45 (54-1)-51 (58-1)-54 (62-1)-58 (70-1)-62 (77-1)-70 (79-1)-77 (80-1)-79 (8+82-1)-80 (18-1)-8) (26-1)-18 (33-1)-26 (38-1)-33 (40-1)-38 (43-1)-40 (45-1)-43 (52-1)-45
5 2 3 3 7 6 1 0 9 9 7 6 4 1 2 1 6

最终还原数值:52337610997641216

优点:改进了方案而中的缺点

方案四(checksum)、
以上三个方案都能一定程度上防止恶意用户所以输入字符串,但是可能会出现恶意用户输入的字符串正好能转换为一个数值。因此需要增加一个冗余校验,考虑到复杂度和冗余字符串长度,这里采用类似checksum的冗余校验方案。
number % 82生成随机seed,然后将seed对应下标下的字符加到最终字符串中。然后在字符串转换为数值后,将数值整除82,再获取相应下标的字符串,最终进行比对。

你可能感兴趣的:(开发笔记,数据结构)