序列号生成-模拟windows office序列号

本文介绍了一个使用Java实现的简单模拟Office激活码生成器。该生成器通过设定数字和字母的过滤规则来生成看起来更清晰易读的激活码。通过随机算法确保数字和字母混合出现,同时避免了一些容易混淆的字符。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近看到office2013在提示过期问题(升级win10后遗症),就想到模拟下office的激活码。~~

 

起初想到应该简单,最后越试越复杂。所以就记录下,毕竟花费了时间。

 

 

package test;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class SerialNum {

	//随机器,随机次数和符号等。
	private static Random r = new Random();
	
	//定义一些数字取值范围过滤,避免数字字母看起来混淆的问题,还有,避免暴力全遍历的问题。
	private static List<Integer> numFilter = new ArrayList<>();

	//定义一些字符取值范围过滤
	private static List<Integer> charFilter = new ArrayList<>();

	//初始化
	static {
		numFilter.add(0);
		numFilter.add(1);
		numFilter.add(5);

		charFilter.add(97);// a
		charFilter.add(65);
		charFilter.add(101);// e
		charFilter.add(69);
		charFilter.add(105);// i
		charFilter.add(73);
		charFilter.add(108);// l
		charFilter.add(76);
		charFilter.add(111);// o
		charFilter.add(79);
		charFilter.add(115);// s
		charFilter.add(83);
		charFilter.add(117);// u
		charFilter.add(85);
		charFilter.add(122);// z
		charFilter.add(90);
	}

	//main函数,批量生成多组
	public static void main(String[] args) {
		int i = 0;
		while (i < 10) {
			outSerialNum(5,5);
			i++;
		}
	}

	//获取一组序列,入参为序列有几组,每组长度为几
	private static void outSerialNum(int group,int len) {
		long start = System.currentTimeMillis();

		StringBuilder s = new StringBuilder();

		// 以随机串的分组数量为单位,获取每组的串
		for (int i = 0; i < group; i++) {
			// 传入每组串的长度
			s.append(getRandomStr(len) + "-");
		}
		System.out.println(s.toString().substring(0, s.length()-1));
		System.out.println("cost:" + (System.currentTimeMillis() - start));
	}

	// 获取一组长度为n的随机数字字母串
	private static String getRandomStr(int len) {
		StringBuilder sb = new StringBuilder();
		String[] unit = new String[len];
		// 随机出数字和字母出现的次数,保证数字和字母至少出现一次
		int numCount = r.nextInt(len);
		if (numCount == 0) {
			numCount = 1;
		}
		int charCount = len - numCount;

		// System.out.println("numCount=" + numCount + "; charCount=" +
		// charCount);

		// 获取二者中出现次数多的类型,优先随机插入数组
		int max = numCount;
		int flag = 0;// 表示数字类型
		if (charCount > numCount) {
			max = charCount;
			flag = 1;// 字母
		}

		// 优先随机位置插入出现次数多的类型
		for (int i = 0; i < max; i++) {
			int f = r.nextInt(len);
			if (flag == 0) {
				unit[f] = String.valueOf(getNum());
			} else {
				unit[f] = String.valueOf(getChar());
			}
		}

		// System.out.println("优先插入次数多的类型后:" + getArrayString(unit));

		// 遍历数组,如果不为空,加入已经存在的字符串;为空,字符串填充另一种类型
		for (String s : unit) {
			if (null == s) {
				// 与第一次插入采用相反的类型
				if (flag == 0) {
					sb.append(String.valueOf(getChar()));
				} else {
					sb.append(String.valueOf(getNum()));
				}
			} else {
				sb.append(s);
			}
		}
		return sb.toString();
	}

	private static int getNum() {
		int n = r.nextInt(10);
		return numFilter.contains(n) ? getNum() : n;// 不能在数字过滤器中
	}

	private static char getChar() {
		int c = r.nextInt(26) + 97;
		// 不能在字符过滤器中
		return charFilter.contains(c) ? getChar() : (char) c;
	}

}

 

 

 

 

 

public synchronized String nextId() { long timestamp = timeGen(); //获取当前毫秒数 //如果服务器时间有问题(时钟后退) 报错。 if (timestamp < lastTimestamp) { throw new RuntimeException(String.format( "Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } //如果上次生成时间和当前时间相同,在同一毫秒内 if (lastTimestamp == timestamp) { //sequence自增,因为sequence只有12bit,所以和sequenceMask相与一下,去掉高位 sequence = (sequence + 1) & sequenceMask; //判断是否溢出,也就是每毫秒内超过4095,当为4096时,与sequenceMask相与,sequence就等于0 if (sequence == 0) { timestamp = tilNextMillis(lastTimestamp); //自旋等待到下一毫秒 } } else { sequence = 0L; //如果和上次生成时间不同,重置sequence,就是下一毫秒开始,sequence计数重新从0开始累加 } lastTimestamp = timestamp; long suffix = (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; String datePrefix = DateFormatUtils.format(timestamp, "yyyyMMddHHMMssSSS"); return datePrefix + suffix; } protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } protected long timeGen() { return System.currentTimeMillis(); } private byte getLastIP(){ byte lastip = 0; try{ InetAddress ip = InetAddress.getLocalHost(); byte[] ipByte = ip.getAddress(); lastip = ipByte[ipByte.length - 1]; } catch (UnknownHostException e) { e.printStackTrace(); } return lastip; }
Axure RP 能帮助网站需求设计者,快捷而简便的创建基于网站构架图的带注释页面示意图、操作流程图、以及交互设计,并可自动生成用于演示的网页文件和规格文件,以提供演示与开发。   那请问Axure如何发音?问这个问题的时候,为了确认我写的是否正确我在很多群里问了同样的问题,回答的结果很有趣,大家也可以试试。Axure的正确发音是“Ack-Sure”,RP则是”RapidPrototyping”快速原型的缩写。 Axure RP 特点   1.Axure RP快速创建带注释的wireframe文件,并可根据所设置的时间周期,软件自动保存文档,确保文件安全。   2.Axure RP在不写任何一条html与javascript语句的情况下,通过创建的文档以及相关条件和注释,一键生成html prototype演示。   3.Axure RP根据设计稿,一键生成一致而专业的word版本的原型设计文档。   Axure RP 交流论坛(中文) Axure RP六合一功能:   一.网站构架图(Site Structure) AxureRP可以快速绘制树状的网站构架图,而且可以让构架图中的每一个页面节点,直接连接到对应网页。Axure RP软件画面    二.示意图(Wireframe) Axure RP内建了许多会经常使用到的widget元件,例如:按钮(Button)、图片(Image)、文字面板(Text Panel)、选择钮(Radio Button)、下拉式菜单(Droplist)。    三.流程图(Flowchart)AxureRPFlowDiagram快速建立流程图就像建立wireframe一样容易,Flow Widget中有设计流程图时会经常用到的形状,您可以轻松在流程之间加入连接线并设定连接的格式。    四.交互设计(InteractionDesign) 大多数的widget可以对一个或多个事件产生动作,包括OnClick、OnMouseOver和OnMouseLeave等    五.自动输出网站原型(HTML Prototype): Axure RP可以将wireframe,输出成符合InternetExplorer或Firefox等不同浏览器的HTML prototype。    六.自动输出word格式规格文件(Specification) Axure RP可以输出Word的格式的文件,规格文件包含了目录、网页清单、网页和附有注解的Master、Annotation、Interaction和Widget特定的资讯,以及结尾文件(例如:附录),规格的内容与格式也可以依据不同的阅读对象来变更。 Axure RP 免费下载   1. 英文官方下载站点 http://www.axure.com/downloads.aspx   2. 中文官方下载站点 http://cn.userxper.com/axure_download Axure RP 在线交流论坛   http://groups.google.com.tw/group/axure-rp-groups Axure RP 版本与现状   1. AxureRP最新版本是6 版   2. AxureRP目前有英文版本及日文版,尚未有其他语言版。在中文环境的兼容性上没有问题,可以输入中文,也可以显示中文。   3. AxureRP中文输入不是很好。可以尝试多种输入法解决支持,比如搜狗等等,也可以在文本框里先写好再黏贴到软件上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值