!301 PhoneUtil add 对 hk电话支持

Merge pull request !301 from dazer007/v5-dev
This commit is contained in:
Looly 2021-04-06 09:45:53 +08:00 committed by Gitee
commit dc7bb14494
11 changed files with 206 additions and 18 deletions

View File

@ -36,7 +36,7 @@ public class ChineseDate {
private final int gyear;
//公历月
private final int gmonth;
//
//
private final int gday;
//是否闰年

View File

@ -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 = {"", "", "", "", "", "", "", "", "", "", "", ""};
/**
* 当前农历月份是否为闰月

View File

@ -4,12 +4,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
* 十二地支对应十二生肖:------ ------
*/
private static final String[] GAN = new String[]{"", "", "", "", "", "", "", "", "", ""};
private static final String[] ZHI = new String[]{"", "", "", "", "", "", "", "", "", "", "", ""};

View File

@ -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), "地藏节");
// 八月

View File

@ -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.comjetz-chong@ hotmail.comjetz_chong@hotmail.comdazhi.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 13992位区域码标示+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 <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位身份证号码
*/

View File

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

View File

@ -375,6 +375,11 @@ public class CharUtil {
* 'a' - 'ⓐ'
* </pre>
*
* 获取带圈数字 /封闭式字母数字 从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 转换后的字符
* @since 5.6.2
@ -399,14 +404,15 @@ public class CharUtil {
* 20 - '⑳'
* </pre>
* 也称作封闭式字符英文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 <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>
*/
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);
}
}

View File

@ -12,6 +12,8 @@ package cn.hutool.core.util;
* <li>地址</li>
* <li>电子邮件</li>
* <li>密码</li>
* <li>车牌</li>
* <li>银行卡号</li>
* </ul>
*
* @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"
* </pre>
*
* @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 + "";
}
}

View File

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

@ -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);
}
}

View File

@ -486,7 +486,7 @@ public class RandomUtil {
* 获得一个随机的字符串只包含数字和字符 并排除指定字符串
*
* @param length 字符串的长度
* @param elemData 要排除的字符串
* @param elemData 要排除的字符串,去重容易混淆的字符串oO0lL1q9QpP
* @return 随机字符串
*/
public static String randomStringWithoutStr(int length, String elemData) {