万能进制--任意相互转换算法-进制上不封顶

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qiziyiming/article/details/83443771

万能进制转换算法:N进制转M进制以X进制显示。

JS版:https://blog.csdn.net/qiziyiming/article/details/83445624

以java为例,其它语音只需要改变变量声明和方法声明即可,如果没有的可以使用其它方法替代

代码也有许多注释,也欢迎━(*`∀´*)ノ亻!各位优化指点


import java.util.ArrayList;


/**
 * 进制转换 <br>
 * 可以是绝对任意进制,,如果进制大于62进制,则必须使用其它进制表示一位, <br>
 * 比如256进制可以使用两个16进制表示一位(xx-xx-xx) <br>
 * 62进制中(Z~A:61~36;z~a:35~10;9~0)
 * 
 * @author Administrator
 * 
 */
public class Hexadecimal {
	/**
	 * 62进制
	 */
	char[] bdm62 = new char[62];
	/**
	 * 一个62个字符,方便查询,0~9a~zA~Z <br>
	 * 对应62进制
	 */
	public String bdm62Str = null;
	/**
	 * 使最后输出double类型的值不以科学计数法输出
	 */
	java.text.NumberFormat nf = java.text.NumberFormat.getInstance(); 
	public Hexadecimal() {
		/**
		 * 使最后输出double类型的值不以科学计数法输出
		 */
		nf.setGroupingUsed(false);
		for (int i = 0; i <= 9; i++) { /* 0~9 */
			bdm62[i] = (char) (i + 48);
		}
		for (int i = 0; i < 26; i++) { /* a~z */
			bdm62[i + 10] = (char) (i + 97);
		}
		for (int i = 0; i < 26; i++) { /* A~Z */
			bdm62[i + 36] = (char) (i + 65);
		}
		bdm62Str = new String(bdm62);
	}
	/**
	 * 测试
	 */
	public void test() {
		try {
			/**
			 * 现进制或者需要进制
			 */
			int get=32;
			/**
			 * 进制位表示进制
			 */
			int pos=16;
			String get10ToN ="";
			/**
			 * 幂运算
			 */
			double pow = Math.pow(2565,13);
			/**
			 * double不以科学计数法输出
			 */
			System.out.println(getDoubleStr(pow));
			/**
			 * 10进制转N进制
			 */
			get10ToN = get10ToN(pow,get,pos,"-",true);
			/**
			 * 输出10进制转N进制的最后字符串
			 */
			System.out.println(get10ToN);
			/**
			 * N进制转10进制的反向操作
			 */
			double nto10 = getNto10(get10ToN, "-", get, pos);
			/**
			 * 输出N进制转10进制的最后结果
			 */
			System.out.println(getDoubleStr(nto10));
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Hexadecimal hexadecimal=new Hexadecimal();
		hexadecimal.test();
	}
	
	/**
	 * @see #getNto10(String,String,int,int)
	 * @param name {@link #getNto10(String, String, int, int)}
	 * @param now  {@link #getNto10(String, String, int, int)}
	 * @param pos  {@link #getNto10(String, String, int, int)}
	 * @return
	 * @throws Exception
	 */
	public double getNto10(String name, int now, int pos) throws Exception {
		return getNto10(name,"-",now,pos);
	}
	/**
	 * N进制转10进制
	 * 
	 * @param name
	 *            N进制表示信息<br>
	 *            xxxnxnxnn(没有进制位,最大62进制Aa0)或者<br>
	 *            xn-xn-xx-nn(每一位使用其它进制表示, <br>
	 *            比如256进制可以使用两个16进制表示一位(xx-xx-xx))
	 * @param nameSplit 分隔的字符
	 * 
	 * @param now
	 *            现在的进制
	 * @param pos
	 *            进制位是多少进制表示,最大62(pos<2默认62)
	 * @return
	 */
	public double getNto10(String name,String nameSplit, int now, int pos) throws Exception {
		/**
		 * 判断最大位进制表示
		 */
		if (pos > 62) {
			pos = 62;
		} else if (pos < 2) {
			pos = 62;
		}
		/**
		 * 最后的计算的结果
		 */
		double m = 0;
		/**
		 * 如果现进制大于位进制
		 */
		if (now > pos) {
			/**
			 * 位进制的合理表示长度
			 */
			int k = 0;
			/**
			 * 使用对数计算最佳长度
			 * 例如256进制使用16进制表示,最多需要2位16进制表示一位
			 * 它们之间存在对数关系
			 */
			double lon = lon(now, pos);
			k=(int)lon;
			/**
			 * 如果存在小数
			 */
			if(lon>k){
				k++;
			}
			/**
			 * 数组,把每阶的数转换成位进制后保存到数组中,然后再次进行阶运算
			 */
			ArrayList<Double> arrayList = new ArrayList<Double>();
			/**
			 * 如果使用了分隔符
			 */
			if (name.indexOf(nameSplit) > 0||name.length()<k) {
				String[] split = name.split(nameSplit);
				/**
				 * 先计算每组的10进制数
				 */
				for (int i = 0; i < split.length; i++) {
					/**
					 * 如果这一组长度不符合,则退出计算,返回错误提示
					 */
					if (split[i].length() > k) {
						throw new Exception(name + "\t(" + split[i]
								+ ")格式错误,长度应为:" + k);
					}
					/**
					 * 递归调用,返回这一组的10进制数
					 */
					double setHdl10 = getNto10(split[i],nameSplit, pos, 0);
					/**
					 * 保持到数组
					 */
					arrayList.add(setHdl10);
				}
			} else {
				/**
				 * 没有使用分隔符,长度必须符合
				 */
				int i=0;
				while(true){
					/**
					 * 字符串截取,每次截取k个
					 */
					if(name.length()>(i + 1) * k){
						String substring=name.substring(i * k, (i + 1) * k);
						double setHdl10 = getNto10(substring,nameSplit, pos, 0);
						arrayList.add(setHdl10);
					}else {
						/**
						 * 如果正好等于或者小于
						 */
						String substring=name.substring(i * k,name.length());
						double setHdl10 = getNto10(substring,nameSplit, pos, 0);
						arrayList.add(setHdl10);
						break ;
					}
					i++;
				}
			}
			/**
			 * 再把每组的10进制数据再做阶级计算
			 * 例:34567
			 * 7+0
			 * 7+0+6*10
			 * 7+0+6*10+5*100
			 * 7+0+6*10+5*100+4*1000
			 * 7+0+6*10+5*100+4*1000+3*10000=34567
			 */
			int length = arrayList.size() - 1;
			for (int i = length; i >= 0; i--) {
				Double double1 = arrayList.get(i);
				/**
				 * 幂运算
				 */
				double pow = Math.pow(now, length - i);
				m += double1 * pow;
			}
		} else {
			/**
			 * 先判断字符串是否符合当前进制规则
			 * 10进制:0~9
			 * 16进制:0~9a~f
			 */
			if (getSpecial(name, now)) {
				int length = name.length() - 1;
				/**
				 * 再阶级幂运算
				 * 例16进制:adb467
				 * 7+0
				 * 7+0+6*16
				 * 7+0+ 6*16+ 4*16*16
				 * 7+0+ 6*16+ 4*16*16+ 11[b]*16*16*16
				 * 7+0+ 6*16+ 4*16*16+ 11[b]*16*16*16+ 13[d]*16(4个)
				 * ......
				 */
				for (int i = length; i >= 0; i--) {
					/**
					 * 获取当前为字符
					 */
					char charAt = name.charAt(i);
					/**
					 * 查找字符的位置,它的位置正好是它表示的数值
					 */
					int indexOf = bdm62Str.indexOf(charAt);
					/**
					 * 阶级幂运算
					 */
					double pow = Math.pow(now, length - i);
					/**
					 * 如果当前为为0,则不需要
					 */
					if(indexOf>0){
						m += indexOf * pow;
					}
				}
			} else {
				throw new Exception(name + "不符合" + now + "进制:"
						+ bdm62Str.substring(0, now));
			}
		}
		return m;
	}
	/**
	 * @see #get10ToN(double, double, double, String)
	 * @param name
	 * @param get
	 * @param pos
	 * @return
	 * @throws Exception 
	 */
	public String get10ToN(double name,int get,int pos) throws Exception {
		return get10ToN(name, get, pos, null,true);
	}
	/**
	 * N进制转换
	 * @param name 数据
	 * @param get N进制
	 * @param pos 进制位表示
	 * @param nameSplit 分隔符,空则不使用
	 * @param isReverse 字符串是否倒序
	 * @return
	 * @throws Exception 
	 */
	public String get10ToN(double name,int get,int pos,String nameSplit,boolean isReverse) throws Exception {
		
		boolean split = nameSplit==null||nameSplit.isEmpty();
		if(get>pos && split){
			throw new Exception("必须使用分隔符");
		}
		if(name<0){
			name*=-1;
		}
		/**
		 * 字符串累加
		 */
		StringBuilder stringBuilder = new StringBuilder();
		/**
		 * 判断最大位进制表示
		 */
		if (pos > 62) {
			pos = 62;
		} else if (pos < 2) {
			pos = 62;
		}
		if(get>pos){
			/**
			 * 刚好是get进制的倍数
			 */
			double d = lon(name,get);
			if(Math.rint(d)==d){
				for (int i = 0; i < d; i++) {
					stringBuilder.append('0');
					stringBuilder.append(nameSplit);
				}
				stringBuilder.append('1');
			}else {
				/**
				 * 
				 */
				while (name>0) {
					/**
					 * 
					 */
					d = name%get;
					name-=d;
					if(d>0){
						/**
						 * 递归调用,计算表示进制
						 */
						String strTem = get10ToN(d, pos, pos, nameSplit,false);
						stringBuilder.append(strTem);
						/**
						 * 后面还有数
						 */
						if(name>0){
							stringBuilder.append(nameSplit);
						}
					}else {
						stringBuilder.append("0");
						/**
						 * 后面还有数
						 */
						if(name>0){
							stringBuilder.append(nameSplit);
						}
					}
					name/=get;
				}
			}
		}else {
			/**
			 * 刚好是get进制的倍数
			 */
			double d = lon(name,get);
			/**
			 * 取最近的整数比较
			 */
			if(Math.rint(d)==d){
				for (int i = 0; i < d; i++) {
					stringBuilder.append('0');
				}
				stringBuilder.append('1');
			}else {
				/**
				 * 
				 * 不是进制的倍数
				 */
				while (name>0) {
					/**
					 * 例如时间毫秒值的计算:1000*60*60*10=10小时=3600000
					 * 3600000%1000							3600000%1000微秒
					 * (3600000-3600000%1000)/1000=3600		3600000%1000秒
					 * (3600-3600%60)/60=600				3600%60分
					 * (600-600%60)/60=10					小时
					 */
					d =name%get;
					name-=d;
					stringBuilder.append(bdm62Str.charAt((int)d));
					name/=get;
				}
			}
		}
		if(isReverse){
			/**
			 * 倒序后,再返回最后的字符串,
			 */
			return stringBuilder.reverse().toString();
		}else {
			return stringBuilder.toString();
		}
	}
	/**
	 * 去除double类型的科学计数法
	 * @param d
	 * @return
	 */
	public String getDoubleStr(double d){
		return nf.format(d);
	}
	/**
	 * 换底公式
	 * @param value	对数
	 * @param base 底数
	 * @return
	 */
	public double lon(double value, double base){
		return Math.log(value)/Math.log(base);
	}
	/**
	 * 判断字符串是否符合K进制要求
	 * 
	 * @param name
	 * @param k
	 * @return
	 */
	public boolean getSpecial(String name, int k) throws Exception {
		String substring = bdm62Str.substring(0, k);
		String matches = "^[" + substring + "]*$";
		return getSpecial(name, matches);
	}

	/**
	 * 判断字符串是否符合规则
	 * 
	 * @param name
	 *            字符串
	 * @param matches
	 *            正则表达式
	 * 
	 * @return
	 */
	public boolean getSpecial(String name, String matches) {
		return name.matches(matches);
	}
}

猜你喜欢

转载自blog.csdn.net/qiziyiming/article/details/83443771