表达式中中文替换的问题(一)
在EAS HR模块的薪酬部分,用户可以自定义薪酬的公式,公式中变量名就是薪酬项目的名称,在运算中应该将其转换为响应的编码。一般以为直接使用字符串替换的方法就可以了,但是会遇到如下问题:
公式“ 薪酬总额 = 项目工资+绩效工资(其他)+绩效工资”
经过替换后可能会变成“f1=f2+f3(其他)+f3”,即当薪酬项目名称中包含其他薪酬项目名称的时候可能会出现错误的替换,这个问题其实用一个简单的办法就可以避免,先替换名称较长的薪酬项目再替换名称较短的薪酬项目就可以了,但是有没有更好的办法呢?
用正则表达式可以解决这个问题。
以下就是我的第一个实现:
public class ExpressionRegex { private final static String operators = "+-*/()&|=! ";//运算符 public static String replace(String express,Map<String,String> replaceMap) { Iterator iter = replaceMap.entrySet().iterator(); StringBuilder sb = new StringBuilder(); String tail = ""; while(iter.hasNext()) { Map.Entry<String,String> entry = (Map.Entry<String,String>)iter.next(); String key = entry.getKey(); String value = entry.getValue(); sb.append(tail); sb.append(operators); tail = "|"; } Pattern p = Pattern.compile(sb.toString()); Matcher m = p.matcher(express); StringBuffer result = new StringBuffer(); while (m.find()) { String reg = m.group(); int start = m.start(); int end = m.end(); if(start != 0 && operators.indexOf(express.substring(start-1, start)) == -1) { continue; } if(end != express.length() && operators.indexOf(express.substring(end, end+1)) == -1) { continue; } m.appendReplacement(result, replaceMap.get(reg)); } m.appendTail(result); return result.toString(); }} public class ExpressionRegex { private String operators = null; public ExpressionRegex() { this.operators = "+\\-*/()&|=! "; } public ExpressionRegex(String regex) { this.operators = regex; } public String replace(String express, Map<String, String> replaceMap) { Iterator iter = replaceMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String, String> entry = (Map.Entry<String, String>) iter .next(); String key = entry.getKey(); String value = entry.getValue(); StringBuilder sb = new StringBuilder(); sb.append("(["); sb.append(operators); sb.append("]+|^)("); sb.append(key); sb.append(")(["); sb.append(operators); sb.append("]+|$)"); Pattern p = Pattern.compile(sb.toString()); Matcher m = p.matcher(express); StringBuffer result = new StringBuffer(); while (m.find()) { int index = 2; // int groupCount = m.groupCount(); // while(m.group(index) == null && index < groupCount)index+=3; String reg = m.group(index); m.appendReplacement(result, m.group(index - 1) + replaceMap.get(reg) + m.group(index + 1)); } m.appendTail(result); express = result.toString(); } return express; } //ExpressionRegex.javapackage com.ztianyi.regex;import java.util.Iterator;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * @author tianji_zhou * * <p>表达式中文替换 */public class ExpressionRegex { private String operators = null; public ExpressionRegex() { this.operators = "+\\-*/()&|=! "; } public ExpressionRegex(String regex) { this.operators = regex; } /** * * @param express * @param replaceMap * @return * * 一次只能匹配一个词,需要循环多次 */ public String replace(String express, Map<String, String> replaceMap) { Iterator iter = replaceMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next(); String key = entry.getKey(); String value = entry.getValue(); StringBuilder sb = new StringBuilder(); sb.append("(["); sb.append(operators); sb.append("]+|^)("); sb.append(key); sb.append(")(["); sb.append(operators); sb.append("]+|$)"); Pattern p = Pattern.compile(sb.toString()); Matcher m = p.matcher(express); StringBuffer result = new StringBuffer(); while (m.find()) { int index = 2; // int groupCount = m.groupCount(); // while(m.group(index) == null && index < groupCount)index+=3; String reg = m.group(index); m.appendReplacement(result, m.group(index - 1) + replaceMap.get(reg) + m.group(index + 1)); } m.appendTail(result); express = result.toString(); } return express; } /** * * @param express * @param replaceMap * @return * * 此方法还有问题,还是不能很好的解决变量名子串的问题,而且需要重新匹配的问题 */ public String replace2(String express, Map<String, String> replaceMap) { Iterator iter = replaceMap.entrySet().iterator(); StringBuilder sb = new StringBuilder(); String tail = ""; while (iter.hasNext()) { Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next(); String key = entry.getKey(); String value = entry.getValue(); sb.append(tail); sb.append(key); tail = "|"; } Pattern p = Pattern.compile(sb.toString()); Matcher m = p.matcher(express); StringBuffer result = new StringBuffer(); while (m.find()) { String reg = m.group(); int start = m.start(); int end = m.end(); if (start != 0 && operators.indexOf(express.substring(start - 1, start)) == -1) { m.reset(); m.region(start, express.length() - 1); continue; } if (end != express.length() && operators.indexOf(express.substring(end, end + 1)) == -1) { m.reset(); m.region(start, express.length() - 1); continue; } m.appendReplacement(result, replaceMap.get(reg)); } m.appendTail(result); return result.toString(); } /** * * @param express * @param replaceMap * @return * * ^ 行的开头 * $ 行的结尾 * \b 单词边界 * \B 非单词边界 * \A 输入的开头 * \G 上一个匹配的结尾 * * 比较好的解决方法,一次遍历替换全部的变量名 */ public String replace3(String express, Map<String, String> replaceMap) { Iterator iter = replaceMap.entrySet().iterator(); StringBuilder sb = new StringBuilder(); sb.append("(["); sb.append(operators); sb.append("]+|\\G)("); String tail = ""; while (iter.hasNext()) { Map.Entry<String, String> entry = (Map.Entry<String, String>) iter.next(); String key = entry.getKey(); String value = entry.getValue(); sb.append(tail); sb.append(key); tail = "|"; } sb.append(")(["); sb.append(operators); sb.append("]+|$)"); Pattern p = Pattern.compile(sb.toString()); Matcher m = p.matcher(express); StringBuffer result = new StringBuffer(); while (m.find()) { String reg = m.group(2); m.appendReplacement(result, m.group(1) + replaceMap.get(reg) + m.group(3)); } m.appendTail(result); express = result.toString(); return express; }}//ExpressionRegexTest.javapackage com.ztianyi.regex;import static org.junit.Assert.*;import java.util.HashMap;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.junit.After;import org.junit.Before;import org.junit.Test;import com.ztianyi.test.JavaCodeTest;public class ExpressionRegexTest { private static final Log log = LogFactory.getLog(ExpressionRegexTest.class); @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } @Test public void testReplace() { Map replaceMap = new HashMap(); replaceMap.put("薪酬总额", "f1"); replaceMap.put("项目工资", "f2"); replaceMap.put("绩效工资(其他)", "f4"); replaceMap.put("绩效工资", "f3"); ExpressionRegex rm = new ExpressionRegex(); String result = rm.replace("薪酬总额 =项目工资+绩效工资(其他)-(绩效工资 ", replaceMap); log.info(result); boolean b= Pattern.matches("([+\\-*/()&|=! ]+|^)(绩效工资)([+\\-*/()&|=! ]+|$)", "-绩效工资"); log.info(b); Pattern p = Pattern.compile("([+\\-*/()&|=! ]+|^)(项目工资)([+\\-*/()&|=! ]+|$)|(([+\\-*/()&|=! ]+|^)(绩效工资)([+\\-*/()&|=! ]+|$))"); Matcher m = p.matcher("薪酬总额 =项目工资+绩效工资(其他)+绩效工资+绩效工资"); m.find(); if(m.find()) { log.info(m.groupCount()); log.info(m.group(0)); log.info(m.group(1)); log.info(m.group(2)); log.info(m.group(3)); log.info(m.group(4)); log.info(m.group(5)); log.info(m.group(6)); } p = Pattern.compile("([+\\-*/()&|=! ]+|^)(薪酬总额|项目工资|绩效工资)([+\\-*/()&|=! ]+|$)"); m = p.matcher("薪酬总额 =项目工资+绩效工资(其他)+绩效工资+绩效工资"); while(m.find()) { log.info(m.groupCount()); for(int i=0; i<=m.groupCount(); i++) { log.info(m.group(i)); } } } @Test public void testMatch() { boolean b= Pattern.matches("([+\\-*/()&|=! ]+|^)(项目工资|绩效工资)([+\\-*/()&|=! ]+|$)", "绩效工资"); log.info(b); } //@Test public void testReplace2() { Map replaceMap = new HashMap(); replaceMap.put("薪酬总额", "f1"); replaceMap.put("项目工资", "f2"); replaceMap.put("绩效工资", "f3"); //replaceMap.put("绩效工资(其他)", "f4"); ExpressionRegex rm = new ExpressionRegex(); String result = rm.replace2("薪酬总额 =项目工资+绩效工资(其他)-(绩效工资 ", replaceMap); log.info(result); } @Test public void testReplace3() { Map replaceMap = new HashMap(); replaceMap.put("薪酬总额", "f1"); replaceMap.put("项目工资", "f2"); replaceMap.put("绩效工资", "f3"); //replaceMap.put("(其他)绩效工资", "f4"); ExpressionRegex rm = new ExpressionRegex(); String result = rm.replace3("薪酬总额 =项目工资+(其他)绩效工资-(绩效工资 ", replaceMap); log.info(result); }}