一、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本身的容器:ApplicationContextList<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方法设为parseInt2ctx.setVariable("parseInt2", parseInt);//创建ExpressionParser解析表达式ExpressionParser parsers = new SpelExpressionParser();//SpEL语法,比对两个方法执行完成后,结果是否相同String expressionString = "#parseInt('2') == #parseInt2('3')";//执行SpELExpression 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}岁<br/>* values = {"xiaoming", "18"}<br/>* result 小明今年18岁<br/>** @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}岁<br/>* values = {"xiaoming", "18"}<br/>* result 小明今年18岁<br/>** @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为占位符中的内容。<br/><br/>* 如:content = ${name}今年${age}岁<br/>* valueMap = name -> 小明; age -> 18<br/>* result 小明今年18岁<br/>** @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访问对象属性值)替换模板中的占位符 <br/><br/>* 如 content = product:${id}:detail:${detail.id} <br/>* obj = Product.builder().id(1).detail(Detail.builder().id(2).build()).build(); <br/>* 经过解析返回 product:1:detail:2 <br/>** @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;}//需要截取的不能小于0if (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:(多音字的时候获取第一个). <br/>* @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:(拼音字符串集合转换字符串(逗号分隔)). <br/>* @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:(获取汉字拼音). <br/>* @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