diff --git a/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java b/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java index 5d4ea75b7..b9027beb3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java @@ -36,7 +36,7 @@ public class ChineseDate { private final int gyear; //公历月 private final int gmonth; - //公里日 + //公历日 private final int gday; //是否闰年 diff --git a/hutool-core/src/main/java/cn/hutool/core/date/chinese/ChineseMonth.java b/hutool-core/src/main/java/cn/hutool/core/date/chinese/ChineseMonth.java index 088291724..ccf1573db 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/chinese/ChineseMonth.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/chinese/ChineseMonth.java @@ -9,7 +9,7 @@ package cn.hutool.core.date.chinese; public class ChineseMonth { private static final String[] MONTH_NAME = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"}; - private static final String[] MONTH_NAME_TRADITIONAL = {"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊"}; + private static final String[] MONTH_NAME_TRADITIONAL = {"正", "二", "三", "四", "五", "六", "七", "八", "九", "寒", "冬", "腊"}; /** * 当前农历月份是否为闰月 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 b1eb98f4d..73303f249 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 @@ -4,12 +4,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) + * 十二地支对应十二生肖:子-鼠,丑-牛,寅-虎,卯-兔,辰-龙,巳-蛇, 午-马,未-羊,申-猴,酉-鸡,戌-狗,亥-猪 + */ private static final String[] GAN = new String[]{"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"}; private static final String[] ZHI = new String[]{"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"}; 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 fce8ef2f9..34b33a63f 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 @@ -30,7 +30,7 @@ public class LunarFestival { L_FTV.put(new Pair<>(1, 10), "地日 石头生日"); L_FTV.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日"); L_FTV.put(new Pair<>(1, 13), "上(试)灯日 关公升天日"); - L_FTV.put(new Pair<>(1, 15), "元宵节"); + L_FTV.put(new Pair<>(1, 15), "元宵节 上元节"); L_FTV.put(new Pair<>(1, 18), "落灯日"); // 二月 @@ -48,7 +48,7 @@ public class LunarFestival { L_FTV.put(new Pair<>(4, 8), "佛诞节"); // 五月 - L_FTV.put(new Pair<>(5, 5), "端午节"); + L_FTV.put(new Pair<>(5, 5), "端午节 端阳节"); // 六月 L_FTV.put(new Pair<>(6, 6), "晒衣节 姑姑节"); @@ -59,7 +59,7 @@ public class LunarFestival { L_FTV.put(new Pair<>(7, 7), "七夕"); L_FTV.put(new Pair<>(7, 14), "鬼节(南方)"); L_FTV.put(new Pair<>(7, 15), "中元节"); - L_FTV.put(new Pair<>(7, 15), "盂兰盆节"); + L_FTV.put(new Pair<>(7, 15), "盂兰盆节 中元节"); L_FTV.put(new Pair<>(7, 30), "地藏节"); // 八月 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 153d6c122..053cd81a3 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 @@ -49,17 +49,33 @@ public class PatternPool { public final static Pattern MONEY = Pattern.compile("^(\\d+(?:\\.\\d+)?)$"); /** * 邮件,符合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 宽松一点把,都算是正常的邮箱 */ - // public final static Pattern EMAIL = Pattern.compile("(\\w|.)+@\\w+(\\.\\w+){1,2}"); 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); /** * 移动电话 */ public final static Pattern MOBILE = Pattern.compile("(?:0|86|\\+86)?1[3-9]\\d{9}"); + /** + * 香港移动电话 + * eg: 中国香港: +852 5100 4810, 三位区域码+10位数字, 香港手机号码8位数 + * eg: 中国大陆: +86 180 4953 1399,2位区域码标示+13位数字 + * 中国大陆 +86 Mainland China + * 中国香港 +852 Hong Kong + * 中国澳门 +853 Macau + * 中国台湾 +886 Taiwan + */ + public final static Pattern MOBILE_HK = Pattern.compile("(?:0|852|\\+852)?\\d{8}"); /** * 座机号码 */ public final static Pattern TEL = Pattern.compile("0\\d{2,3}-[1-9]\\d{6,7}"); + /** + * 座机号码+400+800电话 + * @see * * @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 820b3e736..c01f12cf4 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 @@ -375,6 +375,11 @@ public class CharUtil { * 'a' -》 'ⓐ' * * + * 获取带圈数字 /封闭式字母数字 ,从1-20,超过1-20报错 + * @see Unicode_symbols + * @see Alphanumerics + * 有其他特殊的需求,可以到 维基百科 查找说明 + * * @param c 被转换的字符,如果字符不支持转换,返回原字符 * @return 转换后的字符 * @since 5.6.2 @@ -399,14 +404,15 @@ public class CharUtil { * 20 -》 '⑳' * * 也称作:封闭式字符,英文:Enclosed Alphanumerics - * 见: 维基百科wikipedia-Unicode_symbols https://en.wikipedia.org/wiki/List_of_Unicode_characters#Unicode_symbols - * 见: 维基百科wikipedia-Unicode字符列表 https://zh.wikipedia.org/wiki/Unicode%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8 - * 见: coolsymbol https://coolsymbol.com/ - * 见: 百度百科 https://baike.baidu.com/item/%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6/112715?fr=aladdin - * + * @author dazer * @param number 被转换的数字 * @return 转换后的字符 * @since 5.6.2 + * + * @see 维基百科wikipedia-Unicode_symbols + * @see 维基百科wikipedia-Unicode字符列表 + * @see coolsymbol + * @see 百度百科 特殊字符 */ public static char toCloseByNumber(int number){ if(number > 20){ @@ -414,4 +420,14 @@ public class CharUtil { } 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 9f6cbdd0c..17f327d53 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 @@ -12,6 +12,8 @@ package cn.hutool.core.util; *
  • 地址
  • *
  • 电子邮件
  • *
  • 密码
  • + *
  • 车牌
  • + *
  • 银行卡号
  • * * * @author dazer and neusoft and qiaomu @@ -42,7 +44,8 @@ public class DesensitizedUtil { //密码 PASSWORD, //中国大陆车牌,包含普通车辆、新能源车辆 - CAR_LICENSE + CAR_LICENSE, + BANK_CARD } /** @@ -57,6 +60,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" * * * @param str 字符串 @@ -98,6 +102,9 @@ public class DesensitizedUtil { case CAR_LICENSE: newStr = DesensitizedUtil.carLicense(String.valueOf(str)); break; + case BANK_CARD: + newStr = DesensitizedUtil.bankCard(String.valueOf(str)); + break; default: } return newStr; @@ -245,4 +252,32 @@ public class DesensitizedUtil { } return carLicense; } + + /** + * 银行卡号脱敏 + * eg: 1101 **** **** **** 3256 + * @param s 银行卡号 + * @return 脱敏之后的银行卡号 + * @since 5.6.3 + */ + public static String bankCard(String s) { + if (StrUtil.isBlank(s)) { + return StrUtil.EMPTY; + } + s = StrUtil.trim(s); + if (s.length() < 9) { + return s; + } + 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(" "); + } + } + return s1 + " " + buf.toString() + " " + s2 + ""; + } } 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 new file mode 100644 index 000000000..683056ab9 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/util/DistanceUtil.java @@ -0,0 +1,92 @@ +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 885bd705a..263b405fc 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 @@ -23,6 +23,17 @@ public class PhoneUtil { return Validator.isMatchRegex(PatternPool.MOBILE, value); } + /** + * 验证是否为手机号码(香港) + * @param value 手机号码 + * @return 是否为香港手机号码 + * @since 5.6.3 + * @author dazer & ourslook + */ + public static boolean isMobileHk(CharSequence value) { + return Validator.isMatchRegex(PatternPool.MOBILE_HK, value); + } + /** * 验证是否为座机号码(中国) * @@ -35,14 +46,26 @@ public class PhoneUtil { } /** - * 验证是否为座机号码+手机号码(中国) + * 验证是否为座机号码(中国)+ 400 + 800 * * @param value 值 - * @return 是否为座机号码+手机号码(中国) + * @return 是否为座机号码(中国) + * @since 5.6.3 + * @author dazer & ourslook + */ + public static boolean isTel400800(CharSequence value) { + return Validator.isMatchRegex(PatternPool.TEL_400_800, value); + } + + /** + * 验证是否为座机号码+手机号码(CharUtil中国)+ 400 + 800电话 + 手机号号码(香港) + * + * @param value 值 + * @return 是否为座机号码+手机号码(中国)+手机号码(香港) * @since 5.3.11 */ public static boolean isPhone(CharSequence value) { - return isMobile(value) || isTel(value); + return isMobile(value) || isTel400800(value) || isMobileHk(value); } /** @@ -111,5 +134,4 @@ public class PhoneUtil { public static CharSequence subAfter(CharSequence phone) { return StrUtil.sub(phone, 7, 11); } - } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java index e9ba1b01d..c819bd0ee 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java @@ -486,7 +486,7 @@ public class RandomUtil { * 获得一个随机的字符串(只包含数字和字符) 并排除指定字符串 * * @param length 字符串的长度 - * @param elemData 要排除的字符串 + * @param elemData 要排除的字符串,如:去重容易混淆的字符串,oO0、lL1、q9Q、pP * @return 随机字符串 */ public static String randomStringWithoutStr(int length, String elemData) {