在开发大屏系统时遇到个问题,客户提供的数据中存在 1.02×10³ 样式的数据,此数据Java无法直接解析成 Double类型数据进行运算操作,需要编写程序进行处理,为此特意编写出此工具类方法用于解决这个问题。核心思路为通过对字符串进行切割处理得到相应的底数和指数,最终得到幂值
public class ScientificNotationUtils {
//0~9的上标标识
private final static Map<Character, Integer> superNumMap = new HashMap<Character, Integer>() {{
put('\u2070', 0);
put('\u00B9', 1);
put('\u00B2', 2);
put('\u00B3', 3);
put('\u2074', 4);
put('\u2075', 5);
put('\u2076', 6);
put('\u2077', 7);
put('\u2078', 8);
put('\u2079', 9);
}};
//格式错误提示语
private final static String FORMAT_ERROR_TIP = "输入表达式{%s}不符合手写科学计数法样式(如:1.02×10³)";
/**
* 将手写的科学计数法表达式字符串转换为Double类型数据,
* 如 :1.02×10³ 转换为 1020
*
* @param str
* @return
*/
public static Double stringToDouble(String str) {
Assert.notEmpty(str, "需要转换的字符串不能为空");
String[] strings = str.split("×");
if (strings.length != 2) {
strings = str.split("x");
}
if (strings.length != 2) {
strings = str.split("\\*");
}
if (strings.length > 2 ){
throw new NumberFormatException(String.format(FORMAT_ERROR_TIP, str));
}
String numStr1 = null;
String numStr2 = null;
if (strings.length == 2){
numStr1 = strings[0].trim();
numStr2 = strings[1].trim();
}else {
numStr2 = str;
}
char[] chars = numStr2.toCharArray();
//指数字符
StringBuilder indexNumStr = new StringBuilder();
//底数字符
StringBuilder baseNumberStr = new StringBuilder();
for (int i = chars.length-1; i >= 0 ; i--) {
Integer integer = superNumMap.get(chars[i]);
if (ObjectUtil.isNotNull(integer)){
indexNumStr.append(integer);
continue;
}
// 0 ~ 9 的ASCII码为 48 ~ 57 小数点 的ASCII码为46
if ((chars[i]>=48 && chars[i]<=57) || chars[i] == 46){
baseNumberStr.append(chars[i]);
}else {
throw new NumberFormatException(String.format(FORMAT_ERROR_TIP, str));
}
}
double powValue = 0d;
try{
//获取底数和指数的幂值
powValue = Math.pow(Double.parseDouble(baseNumberStr.reverse().toString()), Double.parseDouble(indexNumStr.reverse().toString()));
}catch (Exception e){
throw new NumberFormatException(String.format(FORMAT_ERROR_TIP, str));
}
if (StringUtil.isNullOrEmpty(numStr1)){
return powValue;
}
BigDecimal resultBigDecimal = NumberUtil.mul(new BigDecimal(numStr1), BigDecimal.valueOf(powValue));
return resultBigDecimal.doubleValue();
}
}