add methods

This commit is contained in:
Looly
2022-08-18 12:12:31 +08:00
parent f536f4f47a
commit 1079533d5b
4 changed files with 157 additions and 7 deletions

View File

@@ -3,6 +3,9 @@ package cn.hutool.core.codec;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.CharUtil;
import java.util.List;
/**
* Punycode是一个根据RFC 3492标准而制定的编码系统主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码
@@ -24,6 +27,27 @@ public class PunyCode {
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
*
@@ -48,9 +72,9 @@ public class PunyCode {
int n = INITIAL_N;
int delta = 0;
int bias = INITIAL_BIAS;
final StringBuilder output = new StringBuilder();
// Copy all basic code points to the output
final int length = input.length();
final StringBuilder output = new StringBuilder(length * 4);
// Copy all basic code points to the output
int b = 0;
for (int i = 0; i < length; i++) {
final char c = input.charAt(i);
@@ -119,6 +143,27 @@ public class PunyCode {
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为字符串
*
@@ -133,7 +178,8 @@ public class PunyCode {
int n = INITIAL_N;
int i = 0;
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);
if (d > 0) {
for (int j = 0; j < d; j++) {
@@ -146,7 +192,6 @@ public class PunyCode {
} else {
d = 0;
}
final int length = input.length();
while (d < length) {
final int oldi = i;
int w = 1;

View File

@@ -8,6 +8,7 @@ import cn.hutool.core.lang.func.Func1;
import cn.hutool.core.math.NumberUtil;
import cn.hutool.core.regex.ReUtil;
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.StrFinder;
import cn.hutool.core.text.split.SplitUtil;
@@ -743,11 +744,11 @@ public class CharSequenceUtil extends StrChecker {
* @return 字符串含有非检查的字符返回false
* @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)) {
return false;
}
for (CharSequence testChar : testChars) {
for (final CharSequence testChar : testChars) {
if (false == contains(str, testChar)) {
return false;
}
@@ -800,6 +801,23 @@ public class CharSequenceUtil extends StrChecker {
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>
*
@@ -3182,6 +3200,46 @@ public class CharSequenceUtil extends StrChecker {
// ------------------------------------------------------------------------ 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);
}
/**
* 替换字符串中的指定字符串,忽略大小写
*

View File

@@ -6,7 +6,7 @@ import org.junit.Test;
public class PunyCodeTest {
@Test
public void encodeDecodeTest(){
public void encodeDecodeTest() {
final String text = "Hutool编码器";
final String strPunyCode = PunyCode.encode(text);
Assert.assertEquals("Hutool-ux9js33tgln", strPunyCode);
@@ -15,4 +15,37 @@ public class PunyCodeTest {
decode = PunyCode.decode("xn--Hutool-ux9js33tgln");
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);
}
}

View File

@@ -195,4 +195,18 @@ public class CharSequenceUtilTest {
(v) -> DateUtil.parse(v, DatePattern.NORM_DATETIME_PATTERN).toInstant(), Instant::now);
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");
}
}