一、SpEL语法案例
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.PropertyPlaceholderHelper;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
public class PlaceholderResolver {
public static void main(String[] args) throws NoSuchMethodException {
ExpressionParser parser = new SpelExpressionParser();
//字符串解析
String str = (String) parser.parseExpression("'你好'").getValue();
System.out.println(str);
//整型解析
int intVal = (Integer) parser.parseExpression("0x2F").getValue();
System.out.println(intVal);
//双精度浮点型解析
double doubleVal = (Double) parser.parseExpression("4329759E+22").getValue();
System.out.println(doubleVal);
//布尔型解析
boolean booleanVal = (boolean) parser.parseExpression("true").getValue();
System.out.println(booleanVal);
//执行表达式,默认容器是spring本身的容器:ApplicationContext
List<Integer> result1 = parser.parseExpression("{1,2,3}").getValue(List.class);
//等同于如下java代码
Integer[] integer = new Integer[]{1,2,3};
List<Integer> result2 = Arrays.asList(integer);
//创建ctx容器
StandardEvaluationContext ctx = new StandardEvaluationContext();
//获取java自带的Integer类的parseInt(String)方法
Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);
//将parseInt方法注册在ctx容器内, 推荐这样使用
ctx.registerFunction("parseInt", parseInt);
//再将parseInt方法设为parseInt2
ctx.setVariable("parseInt2", parseInt);
//创建ExpressionParser解析表达式
ExpressionParser parsers = new SpelExpressionParser();
//SpEL语法,比对两个方法执行完成后,结果是否相同
String expressionString = "#parseInt('2') == #parseInt2('3')";
//执行SpEL
Expression expression = parsers.parseExpression(expressionString);
Boolean values = expression.getValue(ctx, Boolean.class);
System.out.println(values);
}
private static final PropertyPlaceholderHelper defaultHelper = new PropertyPlaceholderHelper("${", "}");
private static PlaceholderResolver defaultResolver = new PlaceholderResolver();
private PropertyPlaceholderHelper propertyPlaceholderHelper;
private PlaceholderResolver() {
propertyPlaceholderHelper = defaultHelper;
}
private PlaceholderResolver(String placeholderPrefix, String placeholderSuffix) {
propertyPlaceholderHelper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix);
}
/**
* 获取默认的占位符解析器,即占位符前缀为"${", 后缀为"}"
*
* @return
*/
public static PlaceholderResolver getDefaultResolver() {
return defaultResolver;
}
public static PlaceholderResolver getResolver(String placeholderPrefix, String placeholderSuffix) {
return new PlaceholderResolver(placeholderPrefix, placeholderSuffix);
}
/**
* 解析带有指定占位符的模板字符串
* 如:content = ${0}今年${1}岁
* values = {"xiaoming", "18"}
* result 小明今年18岁
*
* @param content 要解析的带有占位符的模板字符串
* @param values 按照模板占位符索引位置设置对应的值
* @return
*/
public String resolve(String content, String... values) {
return propertyPlaceholderHelper.replacePlaceholders(content, placeholderName -> {
return values[Integer.valueOf(placeholderName)];
});
}
/**
* 解析带有指定占位符的模板字符串
* 如:content = ${0}今年${1}岁
* values = {"xiaoming", "18"}
* result 小明今年18岁
*
* @param content 要解析的带有占位符的模板字符串
* @param values 按照模板占位符索引位置设置对应的值
* @return
*/
public String resolve(String content, Object[] values) {
return propertyPlaceholderHelper.replacePlaceholders(content, placeholderName -> {
return String.valueOf(values[Integer.valueOf(placeholderName)]);
});
}
/**
* 根据替换规则来替换指定模板中的占位符值
*
* @param content 要解析的字符串
* @param placeholderResolver 解析规则回调
* @return
*/
public String resolveByRule(String content, PropertyPlaceholderHelper.PlaceholderResolver placeholderResolver) {
return propertyPlaceholderHelper.replacePlaceholders(content, placeholderResolver);
}
/**
* 替换模板中占位符内容,占位符的内容即为map key对应的值,key为占位符中的内容。
* 如:content = ${name}今年${age}岁
* valueMap = name -> 小明; age -> 18
* result 小明今年18岁
*
* @param content 模板内容。
* @param valueMap 值映射
* @return 替换完成后的字符串。
*/
public String resolveByMap(String content, final Map<String, Object> valueMap) {
return propertyPlaceholderHelper.replacePlaceholders(content, placeholderName -> {
return String.valueOf(valueMap.get(placeholderName));
});
}
/**
* 根据对象中字段路径(即类似js访问对象属性值)替换模板中的占位符
* 如 content = product:${id}:detail:${detail.id}
* obj = Product.builder().id(1).detail(Detail.builder().id(2).build()).build();
* 经过解析返回 product:1:detail:2
*
* @param content 要解析的内容
* @param obj 填充解析内容的对象(如果是基本类型,则所有占位符都替换为当前基本类型)
* @return
*/
public String resolveByObject(String content, final Object obj) {
if (obj instanceof Map) {
return resolveByMap(content, (Map) obj);
}
return propertyPlaceholderHelper.replacePlaceholders(content, placeholderName -> {
return String.valueOf(getValueByFieldPath(obj, placeholderName));
});
}
/**
* 获取指定对象中指定字段路径的值
* $(user.name)
*
* @param obj 取值对象
* @param fieldPath 字段路径(形如 user.name)
* @return
*/
private Object getValueByFieldPath(Object obj, String fieldPath) {
String[] fieldNames = fieldPath.split("\\.");
Object result = null;
for (String fieldName : fieldNames) {
result = getFieldValue(obj, fieldName);
if (result == null) {
throw new RuntimeException(fieldName + "为空!");
}
obj = result;
}
return result;
}
private Object getFieldValue(Object obj, String fieldName) {
Class clazz = obj.getClass();
if (isBaseType(clazz)) {
return obj;
}
while (clazz != Object.class && clazz != null) {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
} catch (IllegalAccessException e) {
throw new RuntimeException("无法访问 " + fieldName);
}
}
throw new IllegalStateException(fieldName + "字段不存在!");
}
/**
* 判断class是否为常用类型
*
* @param clazz
* @return
*/
private boolean isBaseType(Class clazz) {
return Enum.class.isAssignableFrom(clazz) || CharSequence.class.isAssignableFrom(clazz)
|| Number.class.isAssignableFrom(clazz) || Date.class.isAssignableFrom(clazz);
}
/**
* 打码隐藏加*
*
* @param num 号码
* @param front 需要显示前几位
* @param end 需要显示末几位
* @return
*/
public static String mask(String num, int front, int end) {
// 传入的号码不能为空
if (num == null || num.length() <= 0) {
return null;
}
// 需要截取的长度不能大于号码长度
if ((front + end) > num.length()) {
return null;
}
//需要截取的不能小于0
if (front < 0 || end < 0) {
return null;
}
//计算*的数量
int asteriskCount = num.length() - (front + end);
StringBuffer asteriskStr = new StringBuffer();
for (int i = 0; i < asteriskCount; i++) {
asteriskStr.append("*");
}
String regex = "(\\w{" + front + "})(\\w+)(\\w{" + end + "})";
// $1、$2、……表示正则表达式里面第一个、第二个、……括号里面的匹配内容
return num.replaceAll(regex, "$1" + asteriskStr + "$3");
}
}
二、汉字转拼音
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.github.stuxuhai</groupId>
<artifactId>jpinyin</artifactId>
<version>1.1.7</version>
</dependency>
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
public class Pinyin4jUtil {
/**
* getFirstSpellPinYin:(多音字的时候获取第一个).
* @param src 传入的拼音字符串,以逗号隔开
* @param isFullSpell 是否全拼,true:全拼,false:第一个汉字全拼(其它汉字取首字母)
* @return 第一个拼音
*/
public static String getFirstSpellPinYin(String src, boolean isFullSpell) {
String targetStr = Pinyin4jUtil.makeStringByStringSet(Pinyin4jUtil.getPinyin(src, isFullSpell));
String[] split = targetStr.split(",");
if (split.length > 1) {
targetStr = split[0];
}
return targetStr;
}
/**
* makeStringByStringSet:(拼音字符串集合转换字符串(逗号分隔)).
* @param stringSet 拼音集合
* @return 带逗号字符串
*/
public static String makeStringByStringSet(Set<String> stringSet) {
StringBuilder str = new StringBuilder();
int i = 0;
if (stringSet.size() > 0) {
for (String s : stringSet) {
if (i == stringSet.size() - 1) {
str.append(s);
} else {
str.append(s + ",");
}
i++;
}
}
return str.toString().toLowerCase();
}
/**
* getPinyin:(获取汉字拼音).
* @param src 汉字
* @param isFullSpell 是否全拼,如果为true:全拼,false:首字全拼
* @return
*/
public static Set<String> getPinyin(String src, boolean isFullSpell) {
if (src != null && !src.trim().equalsIgnoreCase("")) {
char[] srcChar;
srcChar = src.toCharArray();
// 汉语拼音格式输出类
HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();
// 输出设置,大小写,音标方式等
hanYuPinOutputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
hanYuPinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
hanYuPinOutputFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
String[][] temp = new String[src.length()][];
for (int i = 0; i < srcChar.length; i++) {
char c = srcChar[i];
if (String.valueOf(c).matches("[\\u4E00-\\u9FA5]+")) {
//中文
try {
temp[i] = PinyinHelper.toHanyuPinyinStringArray(
srcChar[i], hanYuPinOutputFormat);
if (!isFullSpell) {
if (i == 0) {
temp[i] = temp[i];
} else {
String[] tTemps = new String[temp[i].length];
for (int j = 0; j < temp[i].length; j++) {
char t = temp[i][j].charAt(0);
tTemps[j] = Character.toString(t);
}
temp[i] = tTemps;
}
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace();
}
//英文
} else if (((int) c >= 65 && (int) c <= 90)
|| ((int) c >= 97 && (int) c <= 122)) {
temp[i] = new String[] { String.valueOf(srcChar[i]) };
} else {
temp[i] = new String[] { "" };
}
}
String[] pingyinArray = exchange(temp);
Set<String> pinyinSet = new HashSet<>();
for (int i = 0; i < pingyinArray.length; i++) {
pinyinSet.add(pingyinArray[i]);
}
return pinyinSet;
}
return null;
}
/**
* 递归
* @param strJaggedArray
* @return
*/
public static String[] exchange(String[][] strJaggedArray) {
String[][] temp = doExchange(strJaggedArray);
return temp[0];
}
/**
* 递归
* @param strJaggedArray
* @return
*/
private static String[][] doExchange(String[][] strJaggedArray) {
int len = strJaggedArray.length;
if (len >= 2) {
int len1 = strJaggedArray[0].length;
int len2 = strJaggedArray[1].length;
int newlen = len1 * len2;
String[] temp = new String[newlen];
int Index = 0;
for (int i = 0; i < len1; i++) {
for (int j = 0; j < len2; j++) {
temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j];
Index++;
}
}
String[][] newArray = new String[len - 1][];
for (int i = 2; i < len; i++) {
newArray[i - 1] = strJaggedArray[i];
}
newArray[0] = temp;
return doExchange(newArray);
} else {
return strJaggedArray;
}
}
/**
* 判断是否是中文字符串 还是拼音或者英文字符串
* @param str
* @return
*/
public static boolean isChinese(String str){
String regEx = "[\\u4e00-\\u9fa5]+";
Pattern p = Pattern.compile(regEx);
Matcher m = p.matcher(str);
return m.find();
}
/**
* 将字符串转换成拼音数组
*
* @param src
* @return
*/
public static String[] stringToPinyin(String src) {
return stringToPinyin(src, false, null);
}
/**
* 将字符串转换成拼音数组
*
* @param src
* @return
*/
public static String[] stringToPinyin(String src, String separator) {
return stringToPinyin(src, true, separator);
}
/**
* 将字符串转换成拼音数组
*
* @param src
* @param isPolyphone
* 是否查出多音字的所有拼音
* @param separator
* 多音字拼音之间的分隔符
* @return
*/
public static String[] stringToPinyin(String src, boolean isPolyphone,
String separator) {
// 判断字符串是否为空
if ("".equals(src) || null == src) {
return null;
}
char[] srcChar = src.toCharArray();
int srcCount = srcChar.length;
String[] srcStr = new String[srcCount];
for (int i = 0; i < srcCount; i++) {
srcStr[i] = charToPinyin(srcChar[i], isPolyphone, separator);
}
return srcStr;
}
/**
* 将单个字符转换成拼音
*
* @param src
* @return
*/
public static String charToPinyin(char src, boolean isPolyphone, String separator) {
// 创建汉语拼音处理类
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
// 输出设置,大小写,音标方式
defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
StringBuffer tempPinying = new StringBuffer();
// 如果是中文
if (src > 128) {
try {
// 转换得出结果
String[] strs = PinyinHelper.toHanyuPinyinStringArray(src, defaultFormat);
// 是否查出多音字,默认是查出多音字的第一个字符
if (isPolyphone && null != separator) {
for (int i = 0; i < strs.length; i++) {
tempPinying.append(strs[i]);
if (strs.length != (i + 1)) {
// 多音字之间用特殊符号间隔起来
tempPinying.append(separator);
}
}
} else {
tempPinying.append(strs[0]);
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
log.error("中文转拼音错误:{}",e);
}
} else {
tempPinying.append(src);
}
return tempPinying.toString();
}
public static void main(String[] args) {
System.out.println(isChinese("你好呀"));
System.out.println(JSON.toJSONString(stringToPinyin("你好呀")));
String string = Arrays.asList(stringToPinyin("你好呀")).stream().collect(Collectors.joining(" "));
System.out.println(string);
}
}
三、拼音转汉字
1、原理是viterbi算法、原理是词库+动态规划、搜狗语料库
参考:https://github.com/ranchlai/pinyin2hanzi
2、喵搜输入法
参考:https://github.com/crownpku/Somiao-Pinyin
3、隐马尔科夫模型(HMM)实现的拼音转汉字
参考:https://github.com/KHN190/pinyin