add method for extra

This commit is contained in:
Looly
2020-05-05 23:11:53 +08:00
parent 33b2a3dc51
commit dc2460106f
94 changed files with 616 additions and 68 deletions

View File

@@ -220,6 +220,18 @@
<version>2.0.3.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.stuxuhai</groupId>
<artifactId>jpinyin</artifactId>
<version>1.1.8</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@@ -0,0 +1,53 @@
package cn.hutool.extra.pinyin;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
/**
* 拼音引擎接口,具体的拼音实现通过实现此接口,完成具体实现功能
*
* @author looly
* @since 5.3.3
*/
public interface PinyinEngine {
/**
* 如果c为汉字则返回大写拼音如果c不是汉字则返回String.valueOf(c)
*
* @param c 任意字符,汉字返回拼音,非汉字原样返回
* @return 汉字返回拼音,非汉字原样返回
*/
String getPinyin(char c);
/**
* 获取字符串对应的完整拼音,非中文返回原字符
*
* @param str 字符串
* @param separator 拼音之间的分隔符
* @return 拼音
*/
String getPinyin(String str, String separator);
/**
* 将输入字符串转为拼音首字母,其它字符原样返回
*
* @param c 任意字符,汉字返回拼音,非汉字原样返回
* @return 汉字返回拼音,非汉字原样返回
*/
default char getFirstLetter(char c) {
return getPinyin(c).charAt(0);
}
/**
* 将输入字符串转为拼音首字母,其它字符原样返回
*
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @param separator 分隔符
* @return 汉字返回拼音,非汉字原样返回
*/
default String getFirstLetter(String str, String separator) {
final String splitSeparator = StrUtil.isEmpty(separator) ? "#" : separator;
final String[] split = StrUtil.split(getPinyin(str, splitSeparator), splitSeparator);
return ArrayUtil.join(split, separator, (s)->String.valueOf(s.charAt(0)));
}
}

View File

@@ -0,0 +1,33 @@
package cn.hutool.extra.pinyin;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
/**
* 模板异常
*
* @author xiaoleilu
*/
public class PinyinException extends RuntimeException {
private static final long serialVersionUID = 1L;
public PinyinException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public PinyinException(String message) {
super(message);
}
public PinyinException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public PinyinException(String message, Throwable throwable) {
super(message, throwable);
}
public PinyinException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}

View File

@@ -1,87 +1,85 @@
package cn.hutool.extra.pinyin;
import com.github.promeg.pinyinhelper.Pinyin;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.engine.PinyinFactory;
/**
* 拼音工具类封装了TinyPinyin
*
* <p>
* TinyPinyin(https://github.com/promeG/TinyPinyin)提供者未提交Maven中央库<br>
* 因此使用
* https://github.com/biezhi/TinyPinyin打包的版本
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;io.github.biezhi&lt;/groupId&gt;
* &lt;artifactId&gt;TinyPinyin&lt;/artifactId&gt;
* &lt;version&gt;2.0.3.RELEASE&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
* 拼音工具类封装了TinyPinyin、JPinyin、Pinyin4j通过SPI自动识别。
*
* @author looly
*/
public class PinyinUtil {
private static final String CHINESE_REGEX = "[\\u4e00-\\u9fa5]";
/**
* 自定义拼音全局配置,例如加入自定义字典等
* 获得全局单例的拼音引擎
*
* @param config 配置通过Pinyin.newConfig().with(dict)添加字典
* @return 全局单例的拼音引擎
*/
public static void init(Pinyin.Config config) {
Pinyin.init(config);
public static PinyinEngine getEngine(){
return PinyinFactory.get();
}
/**
* 如果c为汉字则返回大写拼音如果c不是汉字则返回String.valueOf(c)
*
* @param c 任意字符,汉字返回拼音,非汉字原样返回
* @param isToUpperCase 是否转换为大写
* @param c 任意字符,汉字返回拼音,非汉字原样返回
* @return 汉字返回拼音,非汉字原样返回
*/
public static String getPinyin(char c, boolean isToUpperCase) {
final String pinyin = Pinyin.toPinyin(c);
return isToUpperCase ? pinyin : pinyin.toLowerCase();
public static String getPinyin(char c) {
return getEngine().getPinyin(c);
}
/**
* 将输入字符串转为拼音,每个字之间的拼音使用空格分隔
*
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @param isToUpperCase 是否转换为大写
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @return 汉字返回拼音,非汉字原样返回
*/
public static String getPinyin(String str, boolean isToUpperCase) {
return getPinyin(str, " ", isToUpperCase);
public static String getPinyin(String str) {
return getPinyin(str, StrUtil.SPACE);
}
/**
* 将输入字符串转为拼音,以字符为单位插入分隔符
*
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @param separator 每个字拼音之间的分隔符
* @param isToUpperCase 是否转换为大写
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @param separator 每个字拼音之间的分隔符
* @return 汉字返回拼音,非汉字原样返回
*/
public static String getPinyin(String str, String separator, boolean isToUpperCase) {
final String pinyin = Pinyin.toPinyin(str, separator);
return isToUpperCase ? pinyin : pinyin.toLowerCase();
public static String getPinyin(String str, String separator) {
return getEngine().getPinyin(str, separator);
}
/**
* 将输入字符串转为拼音首字母,其它字符原样返回
*
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @param isToUpperCase 是否转换为大写
* @param c 任意字符,汉字返回拼音,非汉字原样返回
* @return 汉字返回拼音,非汉字原样返回
*/
public static char[] getFirstLetter(String str, boolean isToUpperCase) {
final char[] result = new char[str.length()];
for(int i=0; i < result.length; i++){
result[i] = getPinyin(str.charAt(i), isToUpperCase).charAt(0);
}
return result;
public static char getFirstLetter(char c) {
return getEngine().getFirstLetter(c);
}
/**
* 将输入字符串转为拼音首字母,其它字符原样返回
*
* @param str 任意字符,汉字返回拼音,非汉字原样返回
* @param separator 分隔符
* @return 汉字返回拼音,非汉字原样返回
*/
public static String getFirstLetter(String str, String separator) {
return getEngine().getFirstLetter(str, separator);
}
/**
* 是否为中文字符
*
* @param c 字符
* @return 是否为中文字符
*/
public static boolean isChinese(char c) {
return '' == c || String.valueOf(c).matches(CHINESE_REGEX);
}
}

View File

@@ -0,0 +1,52 @@
package cn.hutool.extra.pinyin.engine;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.pinyin.PinyinEngine;
import cn.hutool.extra.template.TemplateException;
import cn.hutool.log.StaticLog;
/**
* 简单拼音引擎工厂用于根据用户引入的拼音库jar自动创建对应的拼音引擎对象
*
* @author looly
*/
public class PinyinFactory {
/**
* 获得单例的PinyinEngine
*
* @return 单例的PinyinEngine
*/
public static PinyinEngine get(){
return Singleton.get(PinyinEngine.class.getName(), PinyinFactory::create);
}
/**
* 根据用户引入的拼音引擎jar自动创建对应的拼音引擎对象<br>
* 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
*
* @return {@link PinyinEngine}
*/
public static PinyinEngine create() {
final PinyinEngine engine = doCreate();
StaticLog.debug("Use [{}] Engine As Default.", StrUtil.removeSuffix(engine.getClass().getSimpleName(), "Engine"));
return engine;
}
/**
* 根据用户引入的拼音引擎jar自动创建对应的拼音引擎对象<br>
* 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
*
* @return {@link PinyinEngine}
*/
private static PinyinEngine doCreate() {
final PinyinEngine engine = ServiceLoaderUtil.loadFirstAvailable(PinyinEngine.class);
if(null != engine){
return engine;
}
throw new TemplateException("No template found ! Please add one of pinyin jar to your project !");
}
}

View File

@@ -0,0 +1,64 @@
package cn.hutool.extra.pinyin.engine.jpinyin;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.extra.pinyin.PinyinEngine;
import com.github.stuxuhai.jpinyin.PinyinException;
import com.github.stuxuhai.jpinyin.PinyinFormat;
import com.github.stuxuhai.jpinyin.PinyinHelper;
/**
* 封装了Jpinyin的引擎。
*
* <p>
* jpinyingithub库作者已删除封装。
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;com.github.stuxuhai&lt;/groupId&gt;
* &lt;artifactId&gt;jpinyin&lt;/artifactId&gt;
* &lt;version&gt;1.1.8&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
*
* @author looly
*/
public class JPinyinEngine implements PinyinEngine {
//设置汉子拼音输出的格式
PinyinFormat format;
public JPinyinEngine(){
this(null);
}
public JPinyinEngine(PinyinFormat format){
init(format);
}
public void init(PinyinFormat format){
if(null == format){
// 不加声调
format = PinyinFormat.WITHOUT_TONE;
}
this.format = format;
}
@Override
public String getPinyin(char c) {
String[] results = PinyinHelper.convertToPinyinArray(c, format);
return ArrayUtil.isEmpty(results) ? String.valueOf(c) : results[0];
}
@Override
public String getPinyin(String str, String separator) {
try {
return PinyinHelper.convertToPinyinString(str, separator, format);
} catch (PinyinException e) {
throw new cn.hutool.extra.pinyin.PinyinException(e);
}
}
}

View File

@@ -0,0 +1,20 @@
/**
* 封装了Jpinyin的引擎。
*
* <p>
* jpinyingithub库作者已删除封装。
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;com.github.stuxuhai&lt;/groupId&gt;
* &lt;artifactId&gt;jpinyin&lt;/artifactId&gt;
* &lt;version&gt;1.1.8&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
*
* @author looly
*/
package cn.hutool.extra.pinyin.engine.jpinyin;

View File

@@ -0,0 +1,7 @@
/**
* 拼音具体实现
*
* @author looly
*
*/
package cn.hutool.extra.pinyin.engine;

View File

@@ -0,0 +1,92 @@
package cn.hutool.extra.pinyin.engine.pinyin4j;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.extra.pinyin.PinyinEngine;
import cn.hutool.extra.pinyin.PinyinException;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
/**
* 封装了Pinyin4j的引擎。
*
* <p>
* pinyin4j(http://sourceforge.net/projects/pinyin4j)封装。
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;com.belerweb&lt;/groupId&gt;
* &lt;artifactId&gt;pinyin4j&lt;/artifactId&gt;
* &lt;version&gt;2.5.1&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
*
* @author looly
*/
public class Pinyin4jEngine implements PinyinEngine {
//设置汉子拼音输出的格式
HanyuPinyinOutputFormat format;
/**
* 构造
*/
public Pinyin4jEngine() {
this(null);
}
/**
* 构造
*
* @param format 格式
*/
public Pinyin4jEngine(HanyuPinyinOutputFormat format) {
init(format);
}
/**
* 初始化
*
* @param format 格式
*/
public void init(HanyuPinyinOutputFormat format) {
if (null == format) {
format = new HanyuPinyinOutputFormat();
// 小写
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
// 不加声调
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
// 'ü' 使用 "v" 代替
format.setVCharType(HanyuPinyinVCharType.WITH_V);
}
this.format = format;
}
@Override
public String getPinyin(char c) {
String result;
try {
String[] results = PinyinHelper.toHanyuPinyinStringArray(c, format);
result = ArrayUtil.isEmpty(results) ? String.valueOf(c) : results[0];
} catch (BadHanyuPinyinOutputFormatCombination e) {
result = String.valueOf(c);
}
return result;
}
@Override
public String getPinyin(String str, String separator) {
try {
return PinyinHelper.toHanYuPinyinString(str, format, separator, true);
} catch (BadHanyuPinyinOutputFormatCombination e) {
throw new PinyinException(e);
}
}
}

View File

@@ -0,0 +1,20 @@
/**
* 封装了Pinyin4j的引擎。
*
* <p>
* pinyin4j(http://sourceforge.net/projects/pinyin4j)封装。
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;com.belerweb&lt;/groupId&gt;
* &lt;artifactId&gt;pinyin4j&lt;/artifactId&gt;
* &lt;version&gt;2.5.1&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
*
* @author looly
*/
package cn.hutool.extra.pinyin.engine.pinyin4j;

View File

@@ -0,0 +1,56 @@
package cn.hutool.extra.pinyin.engine.tinypinyin;
import cn.hutool.extra.pinyin.PinyinEngine;
import com.github.promeg.pinyinhelper.Pinyin;
/**
* 封装了TinyPinyin的引擎。
*
* <p>
* TinyPinyin(https://github.com/promeG/TinyPinyin)提供者未提交Maven中央库<br>
* 因此使用
* https://github.com/biezhi/TinyPinyin打包的版本
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;io.github.biezhi&lt;/groupId&gt;
* &lt;artifactId&gt;TinyPinyin&lt;/artifactId&gt;
* &lt;version&gt;2.0.3.RELEASE&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
*
* @author looly
*/
public class TinyPinyinEngine implements PinyinEngine {
/**
* 构造
*/
public TinyPinyinEngine(){
}
/**
* 构造
* @param config 配置
*/
public TinyPinyinEngine(Pinyin.Config config){
Pinyin.init(config);
}
@Override
public String getPinyin(char c) {
if(false == Pinyin.isChinese(c)){
return String.valueOf(c);
}
return Pinyin.toPinyin(c).toLowerCase();
}
@Override
public String getPinyin(String str, String separator) {
return Pinyin.toPinyin(str, separator).toLowerCase();
}
}

View File

@@ -0,0 +1,22 @@
/**
* 封装了TinyPinyin的引擎。
*
* <p>
* TinyPinyin(https://github.com/promeG/TinyPinyin)提供者未提交Maven中央库<br>
* 因此使用
* https://github.com/biezhi/TinyPinyin打包的版本
* </p>
*
* <p>
* 引入:
* <pre>
* &lt;dependency&gt;
* &lt;groupId&gt;io.github.biezhi&lt;/groupId&gt;
* &lt;artifactId&gt;TinyPinyin&lt;/artifactId&gt;
* &lt;version&gt;2.0.3.RELEASE&lt;/version&gt;
* &lt;/dependency&gt;
* </pre>
*
* @author looly
*/
package cn.hutool.extra.pinyin.engine.tinypinyin;

View File

@@ -18,7 +18,7 @@ public class TemplateUtil {
* @since 4.1.11
*/
public static TemplateEngine createEngine() {
return createEngine(new TemplateConfig());
return TemplateFactory.create();
}
/**

View File

@@ -1,5 +1,6 @@
package cn.hutool.extra.template.engine;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.StrUtil;
@@ -14,6 +15,28 @@ import cn.hutool.log.StaticLog;
* @author looly
*/
public class TemplateFactory {
/**
* 根据用户引入的模板引擎jar自动创建对应的模板引擎对象<br>
* 获得的是单例的TemplateEngine
*
* @return 单例的TemplateEngine
*/
public static TemplateEngine get(){
return Singleton.get(TemplateEngine.class.getName(), TemplateFactory::create);
}
/**
* 根据用户引入的模板引擎jar自动创建对应的模板引擎对象<br>
* 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎
*
* @return {@link TemplateEngine}
* @since 5.3.3
*/
public static TemplateEngine create() {
return create(new TemplateConfig());
}
/**
* 根据用户引入的模板引擎jar自动创建对应的模板引擎对象<br>
* 推荐创建的引擎单例使用,此方法每次调用会返回新的引擎

View File

@@ -1,5 +1,6 @@
package cn.hutool.extra.tokenizer.engine;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.util.ServiceLoaderUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.tokenizer.TokenizerEngine;
@@ -13,6 +14,18 @@ import cn.hutool.log.StaticLog;
*
*/
public class TokenizerFactory {
/**
* 根据用户引入的模板引擎jar自动创建对应的分词引擎对象<br>
* 获得的是单例的TokenizerEngine
*
* @return 单例的TokenizerEngine
* @since 5.3.3
*/
public static TokenizerEngine get(){
return Singleton.get(TokenizerEngine.class.getName(), TokenizerFactory::create);
}
/**
* 根据用户引入的分词引擎jar自动创建对应的分词引擎对象
*

View File

@@ -0,0 +1,3 @@
cn.hutool.extra.pinyin.engine.tinypinyin.TinyPinyinEngine
cn.hutool.extra.pinyin.engine.jpinyin.JPinyinEngine
cn.hutool.extra.pinyin.engine.pinyin4j.Pinyin4jEngine

View File

@@ -1,6 +1,5 @@
package cn.hutool.extra.pinyin;
import cn.hutool.core.util.ArrayUtil;
import org.junit.Assert;
import org.junit.Test;
@@ -8,19 +7,19 @@ public class PinyinUtilTest {
@Test
public void getPinyinTest(){
final String pinyin = PinyinUtil.getPinyin("你好", false);
final String pinyin = PinyinUtil.getPinyin("你好", " ");
Assert.assertEquals("ni hao", pinyin);
}
@Test
public void getPinyinUpperCaseTest(){
final String pinyin = PinyinUtil.getPinyin("你好怡", true);
Assert.assertEquals("NI HAO YI", pinyin);
final String pinyin = PinyinUtil.getPinyin("你好怡", " ");
Assert.assertEquals("ni hao yi", pinyin);
}
@Test
public void getFirstLetterTest(){
final char[] result = PinyinUtil.getFirstLetter("H是第一个", false);
Assert.assertEquals("h, s, d, y, g", ArrayUtil.join(result, ", "));
final String result = PinyinUtil.getFirstLetter("H是第一个", ", ");
Assert.assertEquals("h, s, d, y, g", result);
}
}