mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
add methods
This commit is contained in:
@@ -3,6 +3,9 @@ package cn.hutool.core.codec;
|
|||||||
import cn.hutool.core.exceptions.UtilException;
|
import cn.hutool.core.exceptions.UtilException;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.text.StrUtil;
|
import cn.hutool.core.text.StrUtil;
|
||||||
|
import cn.hutool.core.util.CharUtil;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Punycode是一个根据RFC 3492标准而制定的编码系统,主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码
|
* Punycode是一个根据RFC 3492标准而制定的编码系统,主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码
|
||||||
@@ -24,6 +27,27 @@ public class PunyCode {
|
|||||||
|
|
||||||
public static final String PUNY_CODE_PREFIX = "xn--";
|
public static final String PUNY_CODE_PREFIX = "xn--";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将域名编码为PunyCode,会忽略"."的编码
|
||||||
|
*
|
||||||
|
* @param domain 域名
|
||||||
|
* @return 编码后的域名
|
||||||
|
* @throws UtilException 计算异常
|
||||||
|
*/
|
||||||
|
public static String encodeDomain(final String domain) throws UtilException {
|
||||||
|
Assert.notNull(domain, "domain must not be null!");
|
||||||
|
final List<String> split = StrUtil.split(domain, CharUtil.DOT);
|
||||||
|
final StringBuilder result = new StringBuilder(domain.length() * 4);
|
||||||
|
for (final String str : split) {
|
||||||
|
if (result.length() != 0) {
|
||||||
|
result.append(CharUtil.DOT);
|
||||||
|
}
|
||||||
|
result.append(encode(str, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将内容编码为PunyCode
|
* 将内容编码为PunyCode
|
||||||
*
|
*
|
||||||
@@ -48,9 +72,9 @@ public class PunyCode {
|
|||||||
int n = INITIAL_N;
|
int n = INITIAL_N;
|
||||||
int delta = 0;
|
int delta = 0;
|
||||||
int bias = INITIAL_BIAS;
|
int bias = INITIAL_BIAS;
|
||||||
final StringBuilder output = new StringBuilder();
|
|
||||||
// Copy all basic code points to the output
|
|
||||||
final int length = input.length();
|
final int length = input.length();
|
||||||
|
final StringBuilder output = new StringBuilder(length * 4);
|
||||||
|
// Copy all basic code points to the output
|
||||||
int b = 0;
|
int b = 0;
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
final char c = input.charAt(i);
|
final char c = input.charAt(i);
|
||||||
@@ -119,6 +143,27 @@ public class PunyCode {
|
|||||||
return output.toString();
|
return output.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解码 PunyCode为域名
|
||||||
|
*
|
||||||
|
* @param domain 域名
|
||||||
|
* @return 解码后的域名
|
||||||
|
* @throws UtilException 计算异常
|
||||||
|
*/
|
||||||
|
public static String decodeDomain(final String domain) throws UtilException {
|
||||||
|
Assert.notNull(domain, "domain must not be null!");
|
||||||
|
final List<String> split = StrUtil.split(domain, CharUtil.DOT);
|
||||||
|
final StringBuilder result = new StringBuilder(domain.length() / 4 + 1);
|
||||||
|
for (final String str : split) {
|
||||||
|
if (result.length() != 0) {
|
||||||
|
result.append(CharUtil.DOT);
|
||||||
|
}
|
||||||
|
result.append(decode(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解码 PunyCode为字符串
|
* 解码 PunyCode为字符串
|
||||||
*
|
*
|
||||||
@@ -133,7 +178,8 @@ public class PunyCode {
|
|||||||
int n = INITIAL_N;
|
int n = INITIAL_N;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int bias = INITIAL_BIAS;
|
int bias = INITIAL_BIAS;
|
||||||
final StringBuilder output = new StringBuilder();
|
final int length = input.length();
|
||||||
|
final StringBuilder output = new StringBuilder(length / 4 + 1);
|
||||||
int d = input.lastIndexOf(DELIMITER);
|
int d = input.lastIndexOf(DELIMITER);
|
||||||
if (d > 0) {
|
if (d > 0) {
|
||||||
for (int j = 0; j < d; j++) {
|
for (int j = 0; j < d; j++) {
|
||||||
@@ -146,7 +192,6 @@ public class PunyCode {
|
|||||||
} else {
|
} else {
|
||||||
d = 0;
|
d = 0;
|
||||||
}
|
}
|
||||||
final int length = input.length();
|
|
||||||
while (d < length) {
|
while (d < length) {
|
||||||
final int oldi = i;
|
final int oldi = i;
|
||||||
int w = 1;
|
int w = 1;
|
||||||
|
@@ -8,6 +8,7 @@ import cn.hutool.core.lang.func.Func1;
|
|||||||
import cn.hutool.core.math.NumberUtil;
|
import cn.hutool.core.math.NumberUtil;
|
||||||
import cn.hutool.core.regex.ReUtil;
|
import cn.hutool.core.regex.ReUtil;
|
||||||
import cn.hutool.core.text.finder.CharFinder;
|
import cn.hutool.core.text.finder.CharFinder;
|
||||||
|
import cn.hutool.core.text.finder.CharMatcherFinder;
|
||||||
import cn.hutool.core.text.finder.Finder;
|
import cn.hutool.core.text.finder.Finder;
|
||||||
import cn.hutool.core.text.finder.StrFinder;
|
import cn.hutool.core.text.finder.StrFinder;
|
||||||
import cn.hutool.core.text.split.SplitUtil;
|
import cn.hutool.core.text.split.SplitUtil;
|
||||||
@@ -743,11 +744,11 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
* @return 字符串含有非检查的字符,返回false
|
* @return 字符串含有非检查的字符,返回false
|
||||||
* @since 4.4.1
|
* @since 4.4.1
|
||||||
*/
|
*/
|
||||||
public static boolean containsAll(CharSequence str, CharSequence... testChars) {
|
public static boolean containsAll(final CharSequence str, final CharSequence... testChars) {
|
||||||
if (isBlank(str) || ArrayUtil.isEmpty(testChars)) {
|
if (isBlank(str) || ArrayUtil.isEmpty(testChars)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (CharSequence testChar : testChars) {
|
for (final CharSequence testChar : testChars) {
|
||||||
if (false == contains(str, testChar)) {
|
if (false == contains(str, testChar)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -800,6 +801,23 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
return new CharFinder(searchChar).setText(text).setEndIndex(end).start(start);
|
return new CharFinder(searchChar).setText(text).setEndIndex(end).start(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定范围内查找指定字符
|
||||||
|
*
|
||||||
|
* @param text 字符串
|
||||||
|
* @param matcher 被查找的字符匹配器
|
||||||
|
* @param start 起始位置,如果小于0,从0开始查找
|
||||||
|
* @param end 终止位置,如果超过str.length()则默认查找到字符串末尾
|
||||||
|
* @return 位置
|
||||||
|
* @since 6.0.0
|
||||||
|
*/
|
||||||
|
public static int indexOf(final CharSequence text, final Predicate<Character> matcher, final int start, final int end) {
|
||||||
|
if (isEmpty(text)) {
|
||||||
|
return INDEX_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return new CharMatcherFinder(matcher).setText(text).setEndIndex(end).start(start);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定范围内查找字符串,忽略大小写<br>
|
* 指定范围内查找字符串,忽略大小写<br>
|
||||||
*
|
*
|
||||||
@@ -3182,6 +3200,46 @@ public class CharSequenceUtil extends StrChecker {
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------ replace
|
// ------------------------------------------------------------------------ replace
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换字符串中第一个指定字符串
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param searchStr 被查找的字符串
|
||||||
|
* @param replacedStr 被替换的字符串
|
||||||
|
* @param ignoreCase 是否忽略大小写
|
||||||
|
* @return 替换后的字符串
|
||||||
|
*/
|
||||||
|
public static String replaceFirst(final CharSequence str, final CharSequence searchStr, final CharSequence replacedStr, final boolean ignoreCase) {
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
return str(str);
|
||||||
|
}
|
||||||
|
final int startInclude = indexOf(str, searchStr, 0, ignoreCase);
|
||||||
|
if (INDEX_NOT_FOUND == startInclude) {
|
||||||
|
return str(str);
|
||||||
|
}
|
||||||
|
return replace(str, startInclude, startInclude + searchStr.length(), replacedStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换字符串中最后一个指定字符串
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @param searchStr 被查找的字符串
|
||||||
|
* @param replacedStr 被替换的字符串
|
||||||
|
* @param ignoreCase 是否忽略大小写
|
||||||
|
* @return 替换后的字符串
|
||||||
|
*/
|
||||||
|
public static String replaceLast(final CharSequence str, final CharSequence searchStr, final CharSequence replacedStr, final boolean ignoreCase) {
|
||||||
|
if (isEmpty(str)) {
|
||||||
|
return str(str);
|
||||||
|
}
|
||||||
|
final int lastIndex = lastIndexOf(str, searchStr, str.length(), ignoreCase);
|
||||||
|
if (INDEX_NOT_FOUND == lastIndex) {
|
||||||
|
return str(str);
|
||||||
|
}
|
||||||
|
return replace(str, lastIndex, searchStr, replacedStr, ignoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 替换字符串中的指定字符串,忽略大小写
|
* 替换字符串中的指定字符串,忽略大小写
|
||||||
*
|
*
|
||||||
|
@@ -6,7 +6,7 @@ import org.junit.Test;
|
|||||||
public class PunyCodeTest {
|
public class PunyCodeTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encodeDecodeTest(){
|
public void encodeDecodeTest() {
|
||||||
final String text = "Hutool编码器";
|
final String text = "Hutool编码器";
|
||||||
final String strPunyCode = PunyCode.encode(text);
|
final String strPunyCode = PunyCode.encode(text);
|
||||||
Assert.assertEquals("Hutool-ux9js33tgln", strPunyCode);
|
Assert.assertEquals("Hutool-ux9js33tgln", strPunyCode);
|
||||||
@@ -15,4 +15,37 @@ public class PunyCodeTest {
|
|||||||
decode = PunyCode.decode("xn--Hutool-ux9js33tgln");
|
decode = PunyCode.decode("xn--Hutool-ux9js33tgln");
|
||||||
Assert.assertEquals(text, decode);
|
Assert.assertEquals(text, decode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void encodeDecodeDomainTest() {
|
||||||
|
// 全中文
|
||||||
|
final String text = "百度.中国";
|
||||||
|
final String strPunyCode = PunyCode.encodeDomain(text);
|
||||||
|
Assert.assertEquals("xn--wxtr44c.xn--fiqs8s", strPunyCode);
|
||||||
|
|
||||||
|
final String decode = PunyCode.decodeDomain(strPunyCode);
|
||||||
|
Assert.assertEquals(text, decode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void encodeDecodeDomainTest2() {
|
||||||
|
// 中英文分段
|
||||||
|
final String text = "hutool.中国";
|
||||||
|
final String strPunyCode = PunyCode.encodeDomain(text);
|
||||||
|
Assert.assertEquals("xn--hutool-.xn--fiqs8s", strPunyCode);
|
||||||
|
|
||||||
|
final String decode = PunyCode.decodeDomain(strPunyCode);
|
||||||
|
Assert.assertEquals(text, decode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void encodeDecodeDomainTest3() {
|
||||||
|
// 中英文混合
|
||||||
|
final String text = "hutool工具.中国";
|
||||||
|
final String strPunyCode = PunyCode.encodeDomain(text);
|
||||||
|
Assert.assertEquals("xn--hutool-up2j943f.xn--fiqs8s", strPunyCode);
|
||||||
|
|
||||||
|
final String decode = PunyCode.decodeDomain(strPunyCode);
|
||||||
|
Assert.assertEquals(text, decode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -195,4 +195,18 @@ public class CharSequenceUtilTest {
|
|||||||
(v) -> DateUtil.parse(v, DatePattern.NORM_DATETIME_PATTERN).toInstant(), Instant::now);
|
(v) -> DateUtil.parse(v, DatePattern.NORM_DATETIME_PATTERN).toInstant(), Instant::now);
|
||||||
Assert.assertNotNull(result2);
|
Assert.assertNotNull(result2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceLastTest() {
|
||||||
|
final String str = "i am jack and jack";
|
||||||
|
final String result = StrUtil.replaceLast(str, "JACK", null, true);
|
||||||
|
Assert.assertEquals(result, "i am jack and ");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void replaceFirstTest() {
|
||||||
|
final String str = "yes and yes i do";
|
||||||
|
final String result = StrUtil.replaceFirst(str, "YES", "", true);
|
||||||
|
Assert.assertEquals(result, " and yes i do");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user