diff --git a/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java b/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java index a148c51..3a939c0 100644 --- a/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java +++ b/src/main/java/com/example/demo/draft/demo043/util/FormatUtil.java @@ -625,112 +625,111 @@ public class FormatUtil { /** * 坐标系转换 - 经纬度格式转换 - * + * *

支持不同格式的经纬度坐标转换,如度分秒转十进制、十进制转度分秒等。

- * - * @param coordinate 原始坐标字符串 + * 转换逻辑说明: + * 1. 度分秒格式(dms)通常表示为:度°分'秒"(例如:116°23'45.67") + * 2. 十进制格式(decimal)表示为:小数形式(例如:116.396019) + * 3. 转换精度通过参数控制,默认为6位小数 + * + * @param coordinate 原始坐标字符串,不能为空 * @param params 参数映射,包含: - * - fromFormat: 原始格式("dms"-度分秒, "decimal"-十进制) - * - toFormat: 目标格式("dms"-度分秒, "decimal"-十进制) - * - precision: 精度(小数位数,默认6) - * @return 转换后的坐标字符串 + * - fromFormat: 原始格式("dms"-度分秒, "decimal"-十进制,默认"decimal") + * - toFormat: 目标格式("dms"-度分秒, "decimal"-十进制,默认"decimal") + * - precision: 精度(小数位数,默认6,用于十进制结果或作为秒小数位的默认值) + * - secondsPrecision: 秒的小数位数(仅用于度分秒结果,优先级高于precision) + * @return 转换后的坐标字符串,转换失败时返回原始坐标 */ public static String coordinateConvert(String coordinate, Map params) { + // 校验输入坐标是否为空 if (coordinate == null || coordinate.trim().isEmpty()) { return coordinate; } - - String fromFormat = params.containsKey("fromFormat") ? - params.get("fromFormat").toString() : "decimal"; - String toFormat = params.containsKey("toFormat") ? - params.get("toFormat").toString() : "decimal"; - int precision = params.containsKey("precision") ? - Integer.parseInt(params.get("precision").toString()) : 6; - + + // 获取转换参数,使用默认值处理未提供的参数 + String fromFormat = params.containsKey("fromFormat") ? + params.get("fromFormat").toString() : "decimal"; + String toFormat = params.containsKey("toFormat") ? + params.get("toFormat").toString() : "decimal"; + int precision = params.containsKey("precision") ? + Integer.parseInt(params.get("precision").toString()) : 6; + // 秒的小数位数,优先使用secondsPrecision,否则使用precision + int secondsPrecision = params.containsKey("secondsPrecision") ? + Integer.parseInt(params.get("secondsPrecision").toString()) : precision; + try { + // 格式相同则直接返回原始坐标 if (fromFormat.equals(toFormat)) { - return coordinate; // 格式相同,直接返回 + return coordinate; } - + + // 度分秒转十进制 if (fromFormat.equals("dms") && toFormat.equals("decimal")) { - // 度分秒转十进制 return dmsToDecimal(coordinate, precision); - } else if (fromFormat.equals("decimal") && toFormat.equals("dms")) { - // 十进制转度分秒 - return decimalToDms(coordinate, precision); } - - return coordinate; // 不支持的转换类型 + // 十进制转度分秒 + else if (fromFormat.equals("decimal") && toFormat.equals("dms")) { + return decimalToDms(coordinate, secondsPrecision); + } + + // 不支持的转换类型,返回原始坐标 + return coordinate; } catch (Exception e) { - return coordinate; // 转换失败,返回原字符串 + // 转换过程中发生异常,返回原始坐标 + return coordinate; } } /** - * 度分秒转十进制 - * - * @param dms 度分秒格式字符串(如:116°23'45.67") - * @param precision 精度 - * @return 十进制格式坐标 + * 将度分秒格式坐标转换为十进制格式 + * + * @param dmsStr 度分秒格式字符串(例如:116°23'45.67") + * @param precision 十进制结果的小数位数 + * @return 十进制格式的坐标字符串 + * @throws NumberFormatException 当输入格式不正确时抛出 */ - private static String dmsToDecimal(String dms, int precision) { - try { - // 提取度、分、秒 - Pattern pattern = Pattern.compile("([+-]?\\d+)[°]?\\s*([\\d.]+)?['′]?\\s*([\\d.]+)?[\"″]?"); - Matcher matcher = pattern.matcher(dms); - - if (matcher.find()) { - double degrees = Double.parseDouble(matcher.group(1)); - double minutes = 0; - double seconds = 0; - - if (matcher.group(2) != null) { - minutes = Double.parseDouble(matcher.group(2)); - } - if (matcher.group(3) != null) { - seconds = Double.parseDouble(matcher.group(3)); - } - - // 计算十进制 - double decimal = degrees + minutes/60.0 + seconds/3600.0; - - // 格式化输出 - String format = "%." + precision + "f"; - return String.format(format, decimal); - } - } catch (Exception e) { - // 解析失败 - } - return dms; + private static String dmsToDecimal(String dmsStr, int precision) throws NumberFormatException { + // 移除所有非数字和小数点的特殊字符,保留度数符号前的数字 + String[] parts = dmsStr.replaceAll("[°′'\"]", ",").split(","); + + // 解析度、分、秒的值 + double degrees = Double.parseDouble(parts[0].trim()); + double minutes = Double.parseDouble(parts[1].trim()); + double seconds = Double.parseDouble(parts[2].trim()); + + // 计算十进制度数:度 + 分/60 + 秒/3600 + double decimal = degrees + minutes / 60 + seconds / 3600; + + // 格式化输出精度 + return String.format("%." + precision + "f", decimal); } /** - * 十进制转度分秒 - * - * @param decimal 十进制格式坐标 - * @param precision 精度 - * @return 度分秒格式字符串 + * 将十进制格式坐标转换为度分秒格式 + * + * @param decimalStr 十进制格式字符串(例如:116.396019) + * @param secondsPrecision 秒的小数位数 + * @return 度分秒格式的坐标字符串(例如:116°23'45.67") + * @throws NumberFormatException 当输入不是有效的数字时抛出 */ - private static String decimalToDms(String decimal, int precision) { - try { - double value = Double.parseDouble(decimal); - boolean isNegative = value < 0; - value = Math.abs(value); - - // 提取度、分、秒 - int degrees = (int) Math.floor(value); - double minutesDecimal = (value - degrees) * 60; - int minutes = (int) Math.floor(minutesDecimal); - double seconds = (minutesDecimal - minutes) * 60; - - // 格式化输出 - String sign = isNegative ? "-" : ""; - String format = "%s%d°%d'%." + Math.max(0, precision-2) + "f\""; - return String.format(format, sign, degrees, minutes, seconds); - } catch (Exception e) { - // 解析失败 - } - return decimal; + private static String decimalToDms(String decimalStr, int secondsPrecision) throws NumberFormatException { + // 解析十进制数值 + double decimal = Double.parseDouble(decimalStr.trim()); + + // 获取度数部分(整数部分) + int degrees = (int) Math.floor(Math.abs(decimal)); + + // 计算剩余的小数部分并转换为分 + double remaining = Math.abs(decimal) - degrees; + double totalMinutes = remaining * 60; + int minutes = (int) Math.floor(totalMinutes); + + // 计算剩余的秒数 + double seconds = (totalMinutes - minutes) * 60; + + // 格式化输出,添加度数符号、分符号和秒符号,使用指定的秒小数位数 + String format = "%d°%d'%." + secondsPrecision + "f\""; + return String.format(format, degrees, minutes, seconds); } /** diff --git a/src/test/java/com/example/demo/FormatUtilTest.java b/src/test/java/com/example/demo/FormatUtilTest.java index b912dda..ad1afcd 100644 --- a/src/test/java/com/example/demo/FormatUtilTest.java +++ b/src/test/java/com/example/demo/FormatUtilTest.java @@ -74,7 +74,7 @@ public class FormatUtilTest { *

预期结果:转换后的时间格式正确

*/ @Test - @DisplayName("formatTime方法测试 - 正常格式转换") + @DisplayName("formatTime方法测试 - 正常格式转换 - 【已验证】") void testFormatTime_NormalConversion() { System.out.println(); log.info("========== 时间格式化模块测试 - 正常格式转换 =========="); @@ -88,18 +88,14 @@ public class FormatUtilTest { log.info(" - 时间字符串: {}", inputTime); log.info(" - 源格式: {}", params.get("fromFormat")); log.info(" - 目标格式: {}", params.get("toFormat")); - - // 预期结果 - String expectedResult = "2024/01/15"; - log.info("预期结果: {}", expectedResult); - + // 执行测试 Object result = FormatUtil.formatTime(inputTime, params); - - // 实际结果 - log.info("实际结果: {}", result); - + // 断言验证 + String expectedResult = "2024/01/15"; + log.info("预期结果: {}", expectedResult); + log.info("实际结果: {}", result); assertEquals(expectedResult, result); log.info("✓ 测试通过 - 格式转换结果正确"); } @@ -112,7 +108,7 @@ public class FormatUtilTest { *

预期结果:返回空字符串或默认值

*/ @Test - @DisplayName("formatTime方法测试 - 空值处理") + @DisplayName("formatTime方法测试 - 空值处理 - 【已验证】") void testFormatTime_EmptyInput() { System.out.println(); log.info("========== 时间格式化模块测试 - 空值处理 =========="); @@ -185,7 +181,7 @@ public class FormatUtilTest { *

预期结果:正确提取开始时间

*/ @Test - @DisplayName("extractTimeRange方法测试 - 正常提取开始时间") + @DisplayName("extractTimeRange方法测试 - 正常提取开始时间 - 【已验证】") void testExtractTimeRange_ExtractStartTime() { System.out.println(); log.info("========== 时间范围提取模块测试 - 正常提取开始时间 =========="); @@ -197,18 +193,12 @@ public class FormatUtilTest { log.info("输入参数:"); log.info(" - 时间范围字符串: {}", inputTimeRange); log.info(" - 提取类型: {}", params.get("type")); - - // 预期结果 - String expectedResult = "2024-01-15 14:30:25"; - log.info("预期结果: {}", expectedResult); - + // 执行测试 Object result = FormatUtil.extractTimeRange(inputTimeRange, params); - - // 实际结果 - log.info("实际结果: {}", result); - + // 断言验证 + String expectedResult = "2024-01-15 14:30:25"; log.info("预期结果:'{}'", expectedResult); log.info("实际结果:'{}'", result); assertEquals(expectedResult, result); @@ -220,10 +210,10 @@ public class FormatUtilTest { * *

测试目的:验证extractTimeRange方法对无分隔符情况的处理

*

测试场景:时间范围字符串中无分隔符

- *

预期结果:返回原始字符串或错误信息

+ *

预期结果:返回原始字符串

*/ @Test - @DisplayName("extractTimeRange方法测试 - 无分隔符处理") + @DisplayName("extractTimeRange方法测试 - 无分隔符处理 - 【已验证】") void testExtractTimeRange_NoSeparator() { System.out.println(); log.info("========== 时间范围提取模块测试 - 无分隔符处理 =========="); @@ -490,7 +480,7 @@ public class FormatUtilTest { *

预计结果:替换结果正确

*/ @Test - @DisplayName("regexReplace方法测试 - 正则替换") + @DisplayName("regexReplace方法测试 - 正则替换 - 【已验证】") void testRegexReplace_NormalCase() { System.out.println(); log.info("========== 正则表达式替换模块测试 - 正则替换 =========="); @@ -506,18 +496,14 @@ public class FormatUtilTest { log.info(" - 输入字符串: {}", inputString); log.info(" - 正则表达式: {}", regex); log.info(" - 替换字符串: {}", replacement); - - // 预期结果 - String expectedResult = "abc*def*"; - log.info("预期结果: {}", expectedResult); - + // 执行测试 Object result = FormatUtil.regexReplace(inputString, params); - - // 实际结果 - log.info("实际结果: {}", result); - + // 断言验证 + String expectedResult = "abc*def*"; + log.info("预期结果: {}", expectedResult); + log.info("实际结果: {}", result); assertEquals(expectedResult, result); log.info("✓ 测试通过 - 正则替换正确"); } @@ -530,7 +516,7 @@ public class FormatUtilTest { *

预计结果:替换结果正确

*/ @Test - @DisplayName("regexReplace方法测试 - 三种测试") + @DisplayName("regexReplace方法测试 - 三种测试 - 【已验证】") void testRegexReplace_NormalCase3() { System.out.println(); log.info("========== 正则表达式替换模块测试 - 正则替换 =========="); @@ -624,7 +610,7 @@ public class FormatUtilTest { *

预计结果:去除空格后结果正确

*/ @Test - @DisplayName("trim方法测试 - 去除空格") + @DisplayName("trim方法测试 - 去除空格 - 【已验证】") void testTrim_NormalCase() { System.out.println(); log.info("========== 字符串空格处理模块测试 - 去除空格 =========="); @@ -635,18 +621,14 @@ public class FormatUtilTest { log.info("输入参数:"); log.info(" - 输入字符串: '{}'", inputString); log.info(" - 注意: 字符串前后有空格"); - - // 预期结果 - String expectedResult = "hello world"; - log.info("预期结果: '{}'", expectedResult); - + // 执行测试 Object result = FormatUtil.trim(inputString, params); - - // 实际结果 - log.info("实际结果: '{}'", result); - + // 断言验证 + String expectedResult = "hello world"; + log.info("预期结果: '{}'", expectedResult); + log.info("实际结果: '{}'", result); assertEquals(expectedResult, result); log.info("✓ 测试通过 - 空格去除正确"); } @@ -697,7 +679,7 @@ public class FormatUtilTest { *

预计结果:大小写敏感替换结果正确

*/ @Test - @DisplayName("stealBeamsAndReplacePillars方法测试 - 大小写敏感") + @DisplayName("stealBeamsAndReplacePillars方法测试 - 大小写敏感 - 【已验证】") void testStealBeamsAndReplacePillars_CaseSensitive() { System.out.println(); log.info("========== 字符串替换模块测试 - 大小写敏感替换 =========="); @@ -714,18 +696,14 @@ public class FormatUtilTest { log.info(" - 替换映射: {}", JSON.toJSONString(replacementMap)); log.info(" - 大小写敏感: {}", caseSensitive); log.info(" - 注意: 'Hello'与'hello'大小写不匹配"); - - // 预期结果 - String expectedResult = "hello universe"; - log.info("预期结果:'{}'", expectedResult); - + // 执行测试 String result = FormatUtil.stealBeamsAndReplacePillars(inputString, replacementMap, caseSensitive); - - // 实际结果 - log.info("实际结果:'{}'", result); - + // 断言验证 + String expectedResult = "hello universe"; + log.info("预期结果:'{}'", expectedResult); + log.info("实际结果:'{}'", result); assertEquals(expectedResult, result); log.info("✓ 测试通过 - 大小写敏感替换正确"); } @@ -820,30 +798,25 @@ public class FormatUtilTest { *

预计结果:转换结果正确

*/ @Test - @DisplayName("coordinateConvert方法测试 - 十进制转度分秒") + @DisplayName("coordinateConvert方法测试 - 十进制转度分秒 - 【已验证】") void testCoordinateConvert_DecimalToDms() { System.out.println(); log.info("========== 坐标系转换模块测试 - 十进制转度分秒 =========="); // 输入参数 String coordinate = "116.396019"; - params.put("fromType", "decimal"); - params.put("toType", "dms"); - + params.put("fromFormat", "decimal"); + params.put("toFormat", "dms"); + params.put("precision", "2"); + log.info("输入参数:"); log.info(" - 坐标值: {}", coordinate); - log.info(" - 源格式: {}", params.get("fromType")); - log.info(" - 目标格式: {}", params.get("toType")); + log.info(" - 源格式: {}", params.get("fromFormat")); + log.info(" - 目标格式: {}", params.get("toFormat")); log.info(" - 注意: 116.396019 ≈ 116°23'45.67\""); - - // 预期结果 - log.info("预期结果: 非空转换结果"); - + // 执行测试 Object result = FormatUtil.coordinateConvert(coordinate, params); - - // 实际结果 - log.info("实际结果: {}", result); // 断言验证 String expectedResult = "116°23'45.67\""; @@ -1106,7 +1079,7 @@ public class FormatUtilTest { *

预计结果:转换结果正确

*/ @Test - @DisplayName("kvMapping方法测试 - 键名格式转换") + @DisplayName("kvMapping方法测试 - 键名格式转换 - 【验证中】") void testKvMapping_KeyFormatConversion() { System.out.println(); log.info("========== 数据KV映射模块测试 - 键名格式转换 =========="); @@ -1186,7 +1159,7 @@ public class FormatUtilTest { *

预计结果:排序结果正确

*/ @Test - @DisplayName("kvMapping方法测试 - 分组排序") + @DisplayName("kvMapping方法测试 - 分组排序 - 【已验证】") void testKvMapping_GroupingSorting() { System.out.println(); log.info("========== 数据KV映射模块测试 - 分组排序 =========="); @@ -1384,17 +1357,17 @@ public class FormatUtilTest { } /** - * 异常处理测试 - 无效参数组合 + * 默认参数值 * *

测试目的:验证方法对无效参数组合的容错能力

*

测试场景:提供相互冲突的参数

- *

预计结果:返回合理的错误信息或默认值

+ *

预计结果:返回合理的默认值

*/ @Test - @DisplayName("异常处理测试 - 无效参数组合") + @DisplayName("formatTime - 默认参数值 - 【已验证】") void testErrorHandling_InvalidParameterCombination() { System.out.println(); - log.info("========== 异常处理测试 - 无效参数组合 =========="); + log.info("========== 默认参数值 =========="); // 输入参数 String inputTime = "2024-01-15"; @@ -1408,16 +1381,16 @@ public class FormatUtilTest { log.info(" - 注意: 日期格式到时间格式的无效转换"); // 预期结果 - log.info("预期结果: 返回合理的错误信息或默认值"); + log.info("预期结果: 返回默认值"); // 执行测试 Object result = FormatUtil.formatTime(inputTime, params); - - // 实际结果 - log.info("实际结果: {}", result); - + // 断言验证 - assertNotNull(result); + String expectedResult = "00:00:00"; + log.info("预期结果: {}", expectedResult); + log.info("实际结果: {}", result); + assertEquals(expectedResult, result); log.info("✓ 测试通过 - 异常处理正确"); }