diff --git a/CHANGELOG.md b/CHANGELOG.md index 69d5f1a31..2efde6f8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ * 【core 】 修改拆分byte数组时最后一组长度的规则(pr#1494@Github) * 【core 】 新增根据日期获取节气(pr#1496@Github) * 【core 】 mapToBean()添加对布尔值is前缀的识别(pr#294@Gitee) +* 【core 】 农历十月十一月改为寒月和冬月(pr#301@Gitee) +* 【core 】 增加港澳台电话正则(pr#301@Gitee) +* 【core 】 增加银行卡号脱敏(pr#301@Gitee) ### Bug修复 * 【core 】 修复Validator.isUrl()传空返回true(issue#I3ETTY@Gitee) diff --git a/hutool-core/src/main/java/cn/hutool/core/date/chinese/GanZhi.java b/hutool-core/src/main/java/cn/hutool/core/date/chinese/GanZhi.java index 73303f249..ae9fc1dab 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/chinese/GanZhi.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/chinese/GanZhi.java @@ -5,16 +5,18 @@ import java.time.LocalDate; /** * 天干地支类 * 天干地支,简称为干支 + * * @author looly * @since 5.4.1 */ public class GanZhi { /** - * @see 天干地支:简称,干支 * 十天干:甲(jiǎ)、乙(yǐ)、丙(bǐng)、丁(dīng)、戊(wù)、己(jǐ)、庚(gēng)、辛(xīn)、壬(rén)、癸(guǐ) * 十二地支:子(zǐ)、丑(chǒu)、寅(yín)、卯(mǎo)、辰(chén)、巳(sì)、午(wǔ)、未(wèi)、申(shēn)、酉(yǒu)、戌(xū)、亥(hài) * 十二地支对应十二生肖:子-鼠,丑-牛,寅-虎,卯-兔,辰-龙,巳-蛇, 午-马,未-羊,申-猴,酉-鸡,戌-狗,亥-猪 + * + * @see 天干地支:简称,干支 */ private static final String[] GAN = new String[]{"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"}; private static final String[] ZHI = new String[]{"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"}; @@ -55,7 +57,7 @@ public class GanZhi { int firstNode = SolarTerms.getTerm(year, (month * 2 - 1)); // 依据12节气修正干支月 int monthOffset = (year - LunarInfo.BASE_YEAR) * 12 + month + 11; - if(day >= firstNode){ + if (day >= firstNode) { monthOffset++; } return cyclicalm(monthOffset); @@ -74,6 +76,6 @@ public class GanZhi { // 与1970-01-01相差天数,不包括当天 final long days = LocalDate.of(year, month, day).toEpochDay() - 1; //1899-12-21是农历1899年腊月甲子日 40:相差1900-01-31有40天 - return cyclicalm((int)(days - LunarInfo.BASE_DAY + 40)); + return cyclicalm((int) (days - LunarInfo.BASE_DAY + 40)); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java b/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java index 34b33a63f..20e9e555b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java @@ -16,7 +16,8 @@ public class LunarFestival { //农历节日 *表示放假日 // 来自:https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E4%BC%A0%E7%BB%9F%E8%8A%82%E6%97%A5/396100 private static final TableMap, String> L_FTV = new TableMap<>(16); - static{ + + static { // 节日 L_FTV.put(new Pair<>(1, 1), "春节"); L_FTV.put(new Pair<>(1, 2), "犬日"); @@ -85,7 +86,7 @@ public class LunarFestival { /** * 获得节日列表 * - * @param year 年 + * @param year 年 * @param month 月 * @param day 日 * @return 获得农历节日 @@ -93,8 +94,8 @@ public class LunarFestival { */ public static List getFestivals(int year, int month, int day) { // 春节判断,如果12月是小月,则29为除夕,否则30为除夕 - if(12 == month && 29 == day){ - if(29 == LunarInfo.monthDays(year, month)){ + if (12 == month && 29 == day) { + if (29 == LunarInfo.monthDays(year, month)) { day++; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/PatternPool.java b/hutool-core/src/main/java/cn/hutool/core/lang/PatternPool.java index 053cd81a3..4ef6c1d70 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/PatternPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/PatternPool.java @@ -50,7 +50,7 @@ public class PatternPool { /** * 邮件,符合RFC 5322规范,正则来自:http://emailregex.com/ * What is the maximum length of a valid email address? https://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address/44317754 - * 注意email 要宽松一点。比如 jetz.chong@hotmail.com、jetz-chong@ hotmail.com、jetz_chong@hotmail.com、dazhi.duan@com.cn 宽松一点把,都算是正常的邮箱 + * 注意email 要宽松一点。比如 jetz.chong@hutool.cn、jetz-chong@ hutool.cn、jetz_chong@hutool.cn、dazhi.duan@hutool.cn 宽松一点把,都算是正常的邮箱 */ public final static Pattern EMAIL = Pattern.compile("(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)])", Pattern.CASE_INSENSITIVE); /** @@ -58,8 +58,8 @@ public class PatternPool { */ public final static Pattern MOBILE = Pattern.compile("(?:0|86|\\+86)?1[3-9]\\d{9}"); /** - * 香港移动电话 - * eg: 中国香港: +852 5100 4810, 三位区域码+10位数字, 香港手机号码8位数 + * 中国香港移动电话 + * eg: 中国香港: +852 5100 4810, 三位区域码+10位数字, 中国香港手机号码8位数 * eg: 中国大陆: +86 180 4953 1399,2位区域码标示+13位数字 * 中国大陆 +86 Mainland China * 中国香港 +852 Hong Kong @@ -73,14 +73,14 @@ public class PatternPool { public final static Pattern TEL = Pattern.compile("0\\d{2,3}-[1-9]\\d{6,7}"); /** * 座机号码+400+800电话 - * @see 800 */ public final static Pattern TEL_400_800 = Pattern.compile("(?:(?:0\\d{2,3}[\\- ]?[1-9]\\d{6,7})|(?:[48]00[\\- ]?[1-9]\\d{6}))"); /** * 18位身份证号码 */ public final static Pattern CITIZEN_ID = Pattern.compile("[1-9]\\d{5}[1-2]\\d{3}((0\\d)|(1[0-2]))(([012]\\d)|3[0-1])\\d{3}(\\d|X|x)"); - /** * 邮编,兼容港澳台 */ @@ -131,7 +131,6 @@ public class PatternPool { "([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]\\d{3}\\d{1,3}[领])|" + "([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$"); - /** * 社会统一信用代码 *
diff --git a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java
index d68b5d36c..6c721232d 100644
--- a/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/text/CharSequenceUtil.java
@@ -3648,7 +3648,7 @@ public class CharSequenceUtil {
 	 * StrUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtils.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn"
 	 * StrUtil.desensitized("1234567890", DesensitizedUtils.DesensitizedType.PASSWORD)) = "**********"
 	 * StrUtil.desensitized("苏D40000", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "苏D4***0"
-	 * StrUtil.desensitized("11011111222233333256", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "1101 **** **** **** 3256"
+	 * StrUtil.desensitized("11011111222233333256", DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256"
 	 * 
* * @param str 字符串 diff --git a/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java index c01f12cf4..fe7b142e4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java @@ -11,43 +11,81 @@ import cn.hutool.core.text.ASCIIStrCache; */ public class CharUtil { - /** 字符常量:空格符 {@code ' '} */ + /** + * 字符常量:空格符 {@code ' '} + */ public static final char SPACE = ' '; - /** 字符常量:制表符 {@code '\t'} */ + /** + * 字符常量:制表符 {@code '\t'} + */ public static final char TAB = ' '; - /** 字符常量:点 {@code '.'} */ + /** + * 字符常量:点 {@code '.'} + */ public static final char DOT = '.'; - /** 字符常量:斜杠 {@code '/'} */ + /** + * 字符常量:斜杠 {@code '/'} + */ public static final char SLASH = '/'; - /** 字符常量:反斜杠 {@code '\\'} */ + /** + * 字符常量:反斜杠 {@code '\\'} + */ public static final char BACKSLASH = '\\'; - /** 字符常量:回车符 {@code '\r'} */ + /** + * 字符常量:回车符 {@code '\r'} + */ public static final char CR = '\r'; - /** 字符常量:换行符 {@code '\n'} */ + /** + * 字符常量:换行符 {@code '\n'} + */ public static final char LF = '\n'; - /** 字符常量:减号(连接符) {@code '-'} */ + /** + * 字符常量:减号(连接符) {@code '-'} + */ public static final char DASHED = '-'; - /** 字符常量:下划线 {@code '_'} */ + /** + * 字符常量:下划线 {@code '_'} + */ public static final char UNDERLINE = '_'; - /** 字符常量:逗号 {@code ','} */ + /** + * 字符常量:逗号 {@code ','} + */ public static final char COMMA = ','; - /** 字符常量:花括号(左) '{' */ + /** + * 字符常量:花括号(左) '{' + */ public static final char DELIM_START = '{'; - /** 字符常量:花括号(右) '}' */ + /** + * 字符常量:花括号(右) '}' + */ public static final char DELIM_END = '}'; - /** 字符常量:中括号(左) {@code '['} */ + /** + * 字符常量:中括号(左) {@code '['} + */ public static final char BRACKET_START = '['; - /** 字符常量:中括号(右) {@code ']'} */ + /** + * 字符常量:中括号(右) {@code ']'} + */ public static final char BRACKET_END = ']'; - /** 字符常量:双引号 {@code '"'} */ + /** + * 字符常量:双引号 {@code '"'} + */ public static final char DOUBLE_QUOTES = '"'; - /** 字符常量:单引号 {@code '\''} */ + /** + * 字符常量:单引号 {@code '\''} + */ public static final char SINGLE_QUOTE = '\''; - /** 字符常量:与 {@code '&'} */ + /** + * 字符常量:与 {@code '&'} + */ public static final char AMP = '&'; - /** 字符常量:冒号 {@code ':'} */ + /** + * 字符常量:冒号 {@code ':'} + */ public static final char COLON = ':'; - /** 字符常量:艾特 {@code '@'} */ + /** + * 字符常量:艾特 {@code '@'} + */ public static final char AT = '@'; /** @@ -374,23 +412,23 @@ public class CharUtil { * 'A' -》 'Ⓐ' * 'a' -》 'ⓐ' * - * + *

* 获取带圈数字 /封闭式字母数字 ,从1-20,超过1-20报错 - * @see Unicode_symbols - * @see Alphanumerics - * 有其他特殊的需求,可以到 维基百科 查找说明 * * @param c 被转换的字符,如果字符不支持转换,返回原字符 * @return 转换后的字符 + * @see Unicode_symbols + * @see Alphanumerics + * 有其他特殊的需求,可以到 维基百科 查找说明 * @since 5.6.2 */ - public static char toCloseChar(char c){ + public static char toCloseChar(char c) { int result = c; - if(c >='1' && c <= '9'){ + if (c >= '1' && c <= '9') { result = '①' + c - '1'; - } else if(c >='A' && c <= 'Z'){ + } else if (c >= 'A' && c <= 'Z') { result = 'Ⓐ' + c - 'A'; - } else if(c >='a' && c <= 'z'){ + } else if (c >= 'a' && c <= 'z') { result = 'ⓐ' + c - 'a'; } return (char) result; @@ -404,30 +442,20 @@ public class CharUtil { * 20 -》 '⑳' * * 也称作:封闭式字符,英文:Enclosed Alphanumerics - * @author dazer + * * @param number 被转换的数字 * @return 转换后的字符 - * @since 5.6.2 - * + * @author dazer * @see 维基百科wikipedia-Unicode_symbols * @see 维基百科wikipedia-Unicode字符列表 * @see coolsymbol * @see 百度百科 特殊字符 + * @since 5.6.2 */ - public static char toCloseByNumber(int number){ - if(number > 20){ + public static char toCloseByNumber(int number) { + if (number > 20) { throw new IllegalArgumentException("Number must be [1-20]"); } return (char) ('①' + number - 1); } - - /** - * 获取带圈字符 - * Enclosed Alphanumerics - * @since 5.6.3 - * @see CharUtil#toEnclosedAlphanumericsCircleByInt(int) - */ - public static char toEnclosedAlphanumericsCircleByInt(int number){ - return CharUtil.toCloseByNumber(number); - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/DesensitizedUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/DesensitizedUtil.java index 17f327d53..0654a1ff5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/DesensitizedUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/DesensitizedUtil.java @@ -45,6 +45,7 @@ public class DesensitizedUtil { PASSWORD, //中国大陆车牌,包含普通车辆、新能源车辆 CAR_LICENSE, + //银行卡 BANK_CARD } @@ -60,7 +61,7 @@ public class DesensitizedUtil { * DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtils.DesensitizedType.EMAIL)) = "d*************@gmail.com.cn" * DesensitizedUtil.desensitized("1234567890", DesensitizedUtils.DesensitizedType.PASSWORD)) = "**********" * DesensitizedUtil.desensitized("苏D40000", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "苏D4***0" - * DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtils.DesensitizedType.CAR_LICENSE)) = "1101 **** **** **** 3256" + * DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtils.DesensitizedType.BANK_CARD)) = "1101 **** **** **** 3256" * * * @param str 字符串 @@ -256,28 +257,32 @@ public class DesensitizedUtil { /** * 银行卡号脱敏 * eg: 1101 **** **** **** 3256 - * @param s 银行卡号 + * + * @param bankCardNo 银行卡号 * @return 脱敏之后的银行卡号 * @since 5.6.3 */ - public static String bankCard(String s) { - if (StrUtil.isBlank(s)) { - return StrUtil.EMPTY; + public static String bankCard(String bankCardNo) { + if (StrUtil.isBlank(bankCardNo)) { + return bankCardNo; } - s = StrUtil.trim(s); - if (s.length() < 9) { - return s; + bankCardNo = StrUtil.trim(bankCardNo); + if (bankCardNo.length() < 9) { + return bankCardNo; } - String s1 = s.substring(0, 4); - String s2 = s.substring(s.length() - 4, s.length()); - String sMiddle = s.substring(4, s.length() - 4); - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < sMiddle.length(); ++i) { - buf.append("*"); - if ((i + 1) % 4 == 0) { - buf.append(" "); + + final int length = bankCardNo.length(); + final int midLength = length - 8; + final StringBuilder buf = new StringBuilder(); + + buf.append(bankCardNo, 0, 4); + for (int i = 0; i < midLength; ++i) { + if (i % 4 == 0) { + buf.append(CharUtil.SPACE); } + buf.append('*'); } - return s1 + " " + buf.toString() + " " + s2 + ""; + buf.append(CharUtil.SPACE).append(bankCardNo, length - 4, length); + return buf.toString(); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/DistanceUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/DistanceUtil.java deleted file mode 100644 index 683056ab9..000000000 --- a/hutool-core/src/main/java/cn/hutool/core/util/DistanceUtil.java +++ /dev/null @@ -1,92 +0,0 @@ -package cn.hutool.core.util; - -import java.awt.geom.Point2D; - -/** - * 通过经纬度获取地球上两点之间的距离 - * @author dazer & neusoft - * @date 2021/4/4 23:42 - * @since 5.6.3 - * thank you:JAVA通过经纬度获取两点之间的距离 https://www.cnblogs.com/pxblog/p/13359801.html - * thank you:JAVA根据经纬度获取两点之间的距离 https://blog.csdn.net/weixin_35815479/article/details/106972772 - * 百度地图拾取系统:http://api.map.baidu.com/lbsapi/getpoint/index.html - * 高德地图拾取:https://lbs.amap.com/tools/picker - */ -public class DistanceUtil { - /**地球半径,单位KM*/ - private static final double EARTH_RADIUS = 6378.137; - - private static double rad(double d) { - return d * Math.PI / 180.0; - } - - /** - * 根据两个位置的经纬度,来计算两地的距离(单位为KM) - * “经度”【longitude】、“纬度”【 Latitude】。 - * 参数为String类型 - * @param lat1Str 第一个位置经度 - * @param lng1Str 第一个位置纬度 - * @param lat2Str 第二个位置经度 - * @param lng2Str 第二个位置纬度 - * @return 地球上两点之间的距离,单位KM - */ - public static String getDistance(String lat1Str, String lng1Str, String lat2Str, String lng2Str) { - double lat1 = 0; - double lng1 = 0; - double lat2 = 0; - double lng2 = 0; - try { - lat1 = Double.parseDouble(lat1Str); - lng1 = Double.parseDouble(lng1Str); - lat2 = Double.parseDouble(lat2Str); - lng2 = Double.parseDouble(lng2Str); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("经纬度入参不合法,请检查!", e); - } - - double radLat1 = rad(lat1); - double radLat2 = rad(lat2); - double difference = radLat1 - radLat2; - double mdifference = rad(lng1) - rad(lng2); - double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(difference / 2), 2) - + Math.cos(radLat1) * Math.cos(radLat2) - * Math.pow(Math.sin(mdifference / 2), 2))); - distance = distance * EARTH_RADIUS; - distance = Math.round(distance * 10000) / 10000.0; - String distanceStr = distance+""; - distanceStr = distanceStr. - substring(0, distanceStr.indexOf(".")); - return distanceStr; - } - - /** - * 通过AB点经纬度获取距离 整数 - * @param pointA A点(经,纬) - * @param pointB B点(经,纬) - * @return 距离(单位:米) - */ - public static long getDistance(Point2D pointA, Point2D pointB) { - // 经纬度(角度)转弧度。弧度用作参数,以调用Math.cos和Math.sin - // A经弧度 - double radiansAx = Math.toRadians(pointA.getX()); - // A纬弧度 - double radiansAy = Math.toRadians(pointA.getY()); - // B经弧度 - double radiansBx = Math.toRadians(pointB.getX()); - // B纬弧度 - double radiansBy = Math.toRadians(pointB.getY()); - // 公式中“cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2”的部分,得到∠AOB的cos值 - double cos = Math.cos(radiansAy) * Math.cos(radiansBy) * Math.cos(radiansAx - radiansBx) - + Math.sin(radiansAy) * Math.sin(radiansBy); - // 反余弦值 - double acos = Math.acos(cos); - // 最终结果 - double h = EARTH_RADIUS * acos; - - //四舍五入 - //保留小数后两位 - /** BigDecimal b = new BigDecimal(h); - double f1 = b.setScale(2, RoundingMode.HALF_UP).doubleValue();*/ - return Math.round(h); - } -} diff --git a/hutool-core/src/main/java/cn/hutool/core/util/PhoneUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/PhoneUtil.java index 263b405fc..753a1b5f9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/PhoneUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/PhoneUtil.java @@ -5,7 +5,12 @@ import cn.hutool.core.lang.Validator; /** - * 手机号工具类 + * 电话号码工具类,包括: + *

* * @author dahuoyzs * @since 5.3.11 diff --git a/hutool-core/src/test/java/cn/hutool/core/util/DesensitizedUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/DesensitizedUtilTest.java index 373fb3577..2bd7e0b42 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/DesensitizedUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/DesensitizedUtilTest.java @@ -30,6 +30,8 @@ public class DesensitizedUtilTest { Assert.assertEquals("北京市海淀区马********", DesensitizedUtil.desensitized("北京市海淀区马连洼街道289号", DesensitizedUtil.DesensitizedType.ADDRESS)); Assert.assertEquals("d*************@gmail.com.cn", DesensitizedUtil.desensitized("duandazhi-jack@gmail.com.cn", DesensitizedUtil.DesensitizedType.EMAIL)); Assert.assertEquals("**********", DesensitizedUtil.desensitized("1234567890", DesensitizedUtil.DesensitizedType.PASSWORD)); + Assert.assertEquals("1101 **** **** **** 3256", DesensitizedUtil.desensitized("11011111222233333256", DesensitizedUtil.DesensitizedType.BANK_CARD)); + Assert.assertEquals("6227 **** **** *** 5123", DesensitizedUtil.desensitized("6227880100100105123", DesensitizedUtil.DesensitizedType.BANK_CARD)); } @Test