add methods

This commit is contained in:
Looly 2021-04-06 10:34:14 +08:00
parent dc7bb14494
commit 65812bc222
10 changed files with 119 additions and 166 deletions

View File

@ -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()传空返回trueissue#I3ETTY@Gitee

View File

@ -5,16 +5,18 @@ import java.time.LocalDate;
/**
* 天干地支类
* 天干地支简称为干支
*
* @author looly
* @since 5.4.1
*/
public class GanZhi {
/**
* @see <a href="https://baike.baidu.com/item/%E5%A4%A9%E5%B9%B2%E5%9C%B0%E6%94%AF/278140">天干地支简称干支</a>
* 十天干jiǎbǐngdīnggēngxīnrénguǐ
* 十二地支chǒuyínmǎochénwèishēnyǒuhài
* 十二地支对应十二生肖:------ ------
*
* @see <a href="https://baike.baidu.com/item/%E5%A4%A9%E5%B9%B2%E5%9C%B0%E6%94%AF/278140">天干地支简称干支</a>
*/
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));
}
}

View File

@ -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<Pair<Integer, Integer>, 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<String> 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++;
}
}

View File

@ -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.comjetz-chong@ hotmail.comjetz_chong@hotmail.comdazhi.duan@com.cn 宽松一点把都算是正常的邮箱
* 注意email 要宽松一点比如 jetz.chong@hutool.cnjetz-chong@ hutool.cnjetz_chong@hutool.cndazhi.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 13992位区域码标示+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 <a href="https://baike.baidu.com/item/800>800</a>
*
* @see <a href="https://baike.baidu.com/item/800">800</a>
*/
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挂学警港澳使领]))$");
/**
* 社会统一信用代码
* <pre>

View File

@ -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"
* </pre>
*
* @param str 字符串

View File

@ -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 = ',';
/** 字符常量:花括号(左) <code>'{'</code> */
/**
* 字符常量花括号 <code>'{'</code>
*/
public static final char DELIM_START = '{';
/** 字符常量:花括号(右) <code>'}'</code> */
/**
* 字符常量花括号 <code>'}'</code>
*/
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' - 'ⓐ'
* </pre>
*
* <p>
* 获取带圈数字 /封闭式字母数字 从1-20,超过1-20报错
* @see <a href="https://en.wikipedia.org/wiki/List_of_Unicode_characters#Unicode_symbols">Unicode_symbols</a>
* @see <a href="https://en.wikipedia.org/wiki/Enclosed_Alphanumerics">Alphanumerics</a>
* 有其他特殊的需求可以到 维基百科 查找说明
*
* @param c 被转换的字符如果字符不支持转换返回原字符
* @return 转换后的字符
* @see <a href="https://en.wikipedia.org/wiki/List_of_Unicode_characters#Unicode_symbols">Unicode_symbols</a>
* @see <a href="https://en.wikipedia.org/wiki/Enclosed_Alphanumerics">Alphanumerics</a>
* 有其他特殊的需求可以到 维基百科 查找说明
* @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 - '⑳'
* </pre>
* 也称作封闭式字符英文Enclosed Alphanumerics
* @author dazer
*
* @param number 被转换的数字
* @return 转换后的字符
* @since 5.6.2
*
* @author dazer
* @see <a href="https://en.wikipedia.org/wiki/List_of_Unicode_characters#Unicode_symbols">维基百科wikipedia-Unicode_symbols</a>
* @see <a href="https://zh.wikipedia.org/wiki/Unicode%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8">维基百科wikipedia-Unicode字符列表</a>
* @see <a href="https://coolsymbol.com/">coolsymbol</a>
* @see <a href="https://baike.baidu.com/item/%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6/112715?fr=aladdin">百度百科 特殊字符</a>
* @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);
}
}

View File

@ -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"
* </pre>
*
* @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();
}
}

View File

@ -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 youJAVA通过经纬度获取两点之间的距离 https://www.cnblogs.com/pxblog/p/13359801.html
* thank youJAVA根据经纬度获取两点之间的距离 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);
}
}

View File

@ -5,7 +5,12 @@ import cn.hutool.core.lang.Validator;
/**
* 手机号工具类
* 电话号码工具类包括
* <ul>
* <li>手机号码</li>
* <li>400800号码</li>
* <li>座机号码</li>
* </ul>
*
* @author dahuoyzs
* @since 5.3.11

View File

@ -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