表达式中中文替换的问题(一)

在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;
}


这个问题之前一直没很好的解决,今天总算圆满了主要是通过正则表达式中的\G解决的,之前不太懂这个\G的意思,所以一直没用

其实这儿问题还有其他的很多办法:
1.写个算法替换边界运算符中间的文字
2.给中文字符用字母进行编码,中文变量就那么几个

不过正则表达式的办法还是最好的,通过这个办法还可以解决其他的很多问题,这里列出全部,以及测试代码:


//ExpressionRegex.java

package 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.java

package 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);
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值