如何将String类型的字符串当成Java代码执行

该博客介绍了一种将前端传递的字符串表达式在后端执行的方法,使用Apache Commons JEXL库解析和执行JavaScript表达式。同时,提出了一个从字符串表达式中提取变量名的需求,给出了一段示例代码,用于从条件语句中提取变量,以避免因缺少变量导致的执行错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面

设想一个这样的问题:如果前端通过拼接生成了一个判断语句: age > 0,
那么传递到后端,肯定是用String类型来存储:

String test = "age > 0";

那么我想执行前端传递过来的判断条件该怎么办呢?

表达式语言引擎:Apache Commons JEXL

这里展示了一个工具类

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;


import java.util.Map;

/**
 * 这个工具类是为了能够把字符串当作java代码来执行
 */
public class ExecuteStringAsCodeUtils {
    /**
     * 这个方法能够将字符串当作java代码来执行
     * @param express
     * @return
     */
    public Object executeString(String express, Map<String,Object> parameter) {
        JexlEngine jexlEngine = new JexlEngine();
        Expression expression = jexlEngine.createExpression(express);//将参数中的字符串传进来
        JexlContext jexlContext = new MapContext();
        for(String key:parameter.keySet()) {//遍历传过来的参数
            jexlContext.set(key,parameter.get(key));//将传进来的参数替换到表达式中去
        }
        if(null == expression.evaluate(jexlContext)) {//执行表达式
            return "";//为空就返回空字符串
        }
        return expression.evaluate(jexlContext);//执行表达式,返回结果
    }


}

调用方式:

//创建工具类
ExecuteStringAsCodeUtils tool = new ExecuteStringAsCodeUtils();
String condition = "age > 0";
int age = 1;
Map<String,Object> map=new HashMap<String,Object>();
map.put("age",age);
boolean res = (boolean)tool.executeString(condition,map);
System.out.println(res);

提取字符串表达式的变量名

问题描述:
在字符串 "age > 3 || ‘zhangsan’.equals(name) "中,age,name是变量名,考虑将变量名提取出来
为什么有这个想法:
我们发现,如果HashMap中没有age或者name的变量名时,执行就会报错,因此设计一个方法,用来提取字符串表达式中包含的变量名
大致代码如下:

import java.util.*;

public class Test {
    public static void main(String[] args) {
        String exp = "(aa >= bb )|| (aa <= cc) ||(dd < ee) || (ff != gg) && (ff == ee) &&(!'Yes'.equals(STR))";
        parseKeysFromExpression(exp);
    }

    //获取表达式中的参数集合
    public static Set<String> parseKeysFromExpression(String args){
        Set<String> arg_set = new HashSet<>();
        //去掉args中多余的空格
        args = args.replaceAll(" ","");
        //第一道过滤,过滤表达式中的 &&
        String[] split1 = args.split("&&");
        //第二道过滤,过滤表达式中的 ||
        split1 = makeANewStrings(split1,"[||]");
        //第三道,过滤表达式中的比较运算符
        split1 = makeANewStrings(split1,"[!=><()]");
        //第四道,过滤字符串的等于
        split1 = makeANewStrings(split1,".equals");
        for(int i=0; i< split1.length; ++i){
        //排除掉空字符串,以及带单引号的字符串(这在表达式中是常量字符,而非变量)
            if(!"".equals(split1[i])&&!split1[i].contains("\'")) {
                arg_set.add(split1[i]);
                //System.out.println(split1[i]);
            }
        }
        //System.out.println("set:"+arg_set);
        return  arg_set;
    }

    //将字符数组中的每个字符分割后,组成一个新数组
    public static String[] makeANewStrings(String[] org,String exp){
        List<String> ans = new ArrayList<>();
        for(int i=0; i< org.length; ++i){//遍历字符串数组
            String[] split = org[i].split(exp);
            for (int j=0; j<split.length; ++j){
                ans.add(split[j]);
            }
        }
        String[] ans2 = new String[ans.size()];
        return  ans.toArray(ans2);
    }

}

<think>嗯,用户的问题是关于如何用Java处理一个特定格式的字符串,提取日期部分并加上天数生成新日期。我需要仔细分析他的需求,然后一步步给出解决方案。 首先,用户提供的字符串是'2025-03-31-4',用'-'分割后,前三个部分是年、月、日,第四个是天数。需要把前三个部分转换成日期,然后加上4天,得到新的日期。 首先,我得考虑如何分割字符串Java中使用split方法应该可以,用"-"作为分隔符,得到一个数组。然后前三个元素是年、月、日,第四个是天数。需要注意的是,分割后的数组可能会有四个元素,所以要检查分割后的长度是否正确,避免数组越界。 接下来,日期转换部分。用户提到要转换为yyyy-MM-dd格式的日期,但这里可能需要将分割后的字符串组合成一个日期对象。Java中处理日期的话,应该使用LocalDate类,因为它更方便处理日期的加减操作。比如,用LocalDate.parse()来解析字符串,但需要确保格式正确。例如,年、月、日的各个部分可能需要补零,不过用户给的例子是'2025-03-31',这里月和日都是两位,所以没问题。如果分割后的月份或日是单数字,比如'5',可能需要格式化成两位,比如'05',否则解析会出错。不过根据用户的示例,可能输入已经是两位了,所以可以直接拼接成"yyyy-MM-dd"的字符串。 然后,将天数加上去。LocalDate有plusDays方法,可以直接添加天数,得到新的日期。最后将结果格式化成需要的字符串输出。 另外,用户提供的引用中有提到使用split方法分割字符串,比如引用[1]和[4],所以这一步是正确的。日期解析方面,引用[3]提到了DateTimeFormatter,这比旧的SimpleDateFormat更推荐使用,因为线程安全且API更友好。所以应该使用LocalDate和DateTimeFormatter来处理日期解析和格式化。 可能的异常处理需要考虑,比如输入的字符串不符合预期格式,或者日期不合法(比如2月30日),这时候程序应该抛出异常或者给出错误提示。但用户的问题中没有提到异常处理的需求,所以可能在代码中需要包含这部分,比如使用try-catch块,或者让方法抛出异常。 总结步骤: 1. 使用split('-')分割字符串,得到四个部分。 2. 将前三个部分拼接成"yyyy-MM-dd"格式的字符串。 3. 使用DateTimeFormatter解析这个字符串为LocalDate对象。 4. 将第四个部分转换为整数天数,加到LocalDate上。 5. 格式化新日期并输出。 现在要检查这些步骤是否正确。比如,分割后的数组是否正确,日期解析是否正确,天数添加是否正确。例如,用户给的例子是2025-03-31加上4天,应该是2025-04-04,对吗?03-31加4天,3月有31天,所以加4天的话,3月31日+1天是4月1日,再加3天就是4月4日。所以代码处理是否正确? 此外,分割后的第四个元素是字符串"4",需要转换为int。这部分需要用Integer.parseInt()来处理,可能会有NumberFormatException,需要处理吗?用户可能需要代码的健壮性,但问题中没有说明,所以可能暂时不处理,假设输入正确。 代码示例大致如下: String input = "2025-03-31-4"; String[] parts = input.split("-"); // 检查parts长度是否为4 String dateStr = parts[0] + "-" + parts[1] + "-" + parts[2]; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate date = LocalDate.parse(dateStr, formatter); int days = Integer.parseInt(parts[3]); LocalDate newDate = date.plusDays(days); String result = newDate.format(formatter); 这样应该可以得到正确的结果。用户提供的引用中,引用[1]和[4]都是关于split方法的使用,引用[3]提到了DateTimeFormatter,所以代码应该符合用户的需求。此外,需要确保日期格式正确,比如月份和日期是否为两位,如果输入是单数字的话,可能需要在拼接时补零。但用户例子中是03和31,所以没问题。如果输入是'2025-3-5-4',那么拼接后的字符串是"2025-3-5",解析会失败,因为格式应该是yyyy-MM-dd,即两位月份和日期。这时候可能需要处理,比如使用String.format("%02d", month)来补零,但用户的问题中没有提到这种情况,可能需要假设输入是正确格式的。 综上,给出代码示例,并解释每个步骤,同时提到可能的异常情况和格式要求。</think>### 分步实现步骤 1. **字符串分割** 使用 `split('-')` 将字符串分割为数组,提取前三个元素作为日期部分,第四个元素作为天数。 ```java String input = "2025-03-31-4"; String[] parts = input.split("-"); ``` 2. **日期解析** 将前三个元素拼接为 `yyyy-MM-dd` 格式的字符串,并通过 `LocalDate.parse()` 解析为日期对象。 ```java String dateStr = String.join("-", parts[0], parts[1], parts[2]); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate date = LocalDate.parse(dateStr, formatter); ``` 3. **天数添加** 将第四个元素转换为整数天数,并通过 `plusDays()` 方法生成新日期。 ```java int daysToAdd = Integer.parseInt(parts[3]); LocalDate newDate = date.plusDays(daysToAdd); ``` 4. **结果格式化** 将新日期格式化为字符串输出。 ```java String result = newDate.format(formatter); System.out.println("新日期: " + result); // 输出:2025-04-04 ``` ### 完整代码示例 ```java import java.time.LocalDate; import java.time.format.DateTimeFormatter; public class DateCalculator { public static void main(String[] args) { String input = "2025-03-31-4"; String[] parts = input.split("-"); // 解析日期部分 String dateStr = String.join("-", parts[0], parts[1], parts[2]); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate date = LocalDate.parse(dateStr, formatter); // 添加天数 int daysToAdd = Integer.parseInt(parts[3]); LocalDate newDate = date.plusDays(daysToAdd); // 输出结果 System.out.println("新日期: " + newDate.format(formatter)); } } ``` ### 关键注意事项 1. **输入格式验证** - 确保分割后的数组长度为4,避免 `ArrayIndexOutOfBoundsException`[^4]。 - 验证日期合法性(如月份为1-12,日期不超过当月天数),可使用 `DateTimeFormatter` 的严格模式[^3]。 2. **日期边界处理** 例如,`2024-02-29` 加1天会变为 `2024-03-01`,闰年逻辑由 `LocalDate` 自动处理。 3. **异常捕获** 建议添加 `try-catch` 块处理可能的 `DateTimeParseException` 或 `NumberFormatException`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值