You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

骰子公式求值器扩展需求:支持含骰子表达式的数学运算

当然可以用正则来提取所有骰子表达式!这其实是扩展你现有骰子计算功能最直接的思路之一,完全可行。我来一步步给你拆解实现方案:

核心思路

先通过正则匹配出表达式中所有的骰子模式(比如3d8、2d4,甚至支持省略数量的d20),把每个骰子表达式替换为实际投掷后的总和,得到纯数学表达式后,再用JS或者Java的表达式引擎求值,自动处理运算优先级。

步骤1:用正则匹配骰子模式

你需要的正则表达式可以写成(\d*)d(\d+),它能匹配两种情况:

  • 带数量的骰子:比如3d8,捕获组1是3(骰子数量),捕获组2是8(面数)
  • 省略数量的骰子:比如d20,捕获组1为空字符串(默认1个骰子),捕获组2是20

如果要支持负数数量(比如-2d6),可以调整为(-?\d*)d(\d+),后续处理时判断数量的正负即可。

步骤2:替换骰子表达式为计算值

用Java的Matcher类遍历所有匹配结果,对每个骰子表达式调用你现有的投掷逻辑计算总和,然后替换掉原表达式中的骰子部分。这里要注意复用Random实例,避免频繁创建影响性能和随机性。

步骤3:求值处理后的纯数学表达式

你提到的用JS求值是个简单的方案,Java自带了ScriptEngine可以直接执行JS代码。需要注意把表达式中的×替换成JS支持的*符号,否则会报错。如果担心脚本注入风险(比如不可控的用户输入),可以用更安全的Java表达式求值库,比如Apache Commons Math的ExpressionEvaluator。

完整示例代码

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DiceCalculator {
    // 复用Random实例,提升性能和随机性一致性
    private static final Random random = new Random();
    // 匹配骰子表达式,支持可选数量、负数数量
    private static final Pattern DICE_PATTERN = Pattern.compile("(-?\\d*)d(\\d+)");

    public static void main(String[] args) throws Exception {
        String inputExpr = "((3d8)+1)×(2d4)×3";
        System.out.println("原始表达式:" + inputExpr);

        // 第一步:统一数学符号,把×替换为JS支持的*
        String normalizedExpr = inputExpr.replace('×', '*');

        // 第二步:替换所有骰子表达式为实际投掷总和
        String mathExpr = replaceDiceWithValues(normalizedExpr);
        System.out.println("替换后表达式:" + mathExpr);

        // 第三步:求值并输出结果
        int finalResult = evaluateMathExpression(mathExpr);
        System.out.println("最终结果:" + finalResult);
    }

    private static String replaceDiceWithValues(String expr) {
        Matcher matcher = DICE_PATTERN.matcher(expr);
        StringBuilder resultBuilder = new StringBuilder();

        while (matcher.find()) {
            String countStr = matcher.group(1);
            int diceCount = countStr.isEmpty() ? 1 : Integer.parseInt(countStr);
            int diceSize = Math.abs(Integer.parseInt(matcher.group(2))); // 确保面数为正

            int sum = 0;
            // 处理负数数量:比如-2d6表示投掷2个6面骰后取负数
            int sign = diceCount < 0 ? -1 : 1;
            diceCount = Math.abs(diceCount);

            for (int i = 0; i < diceCount; i++) {
                sum += throwDice(diceSize);
            }
            sum *= sign;

            // 替换当前匹配的骰子表达式为计算结果
            matcher.appendReplacement(resultBuilder, String.valueOf(sum));
        }
        matcher.appendTail(resultBuilder);
        return resultBuilder.toString();
    }

    private static int throwDice(int diceSize) {
        // 生成1到diceSize的随机整数
        return random.nextInt(diceSize) + 1;
    }

    private static int evaluateMathExpression(String expr) throws Exception {
        ScriptEngineManager engineManager = new ScriptEngineManager();
        ScriptEngine jsEngine = engineManager.getEngineByName("JavaScript");
        // 因为所有运算都是整数,转成int返回
        return ((Number) jsEngine.eval(expr)).intValue();
    }
}

关键细节说明

  1. 正则扩展:新增了对负数数量的支持,比如-2d6会计算为-(2d6的总和),符合常见的骰子规则场景。
  2. Random复用:避免每次投掷都创建新的Random实例,既提升性能,也保证随机性的稳定性。
  3. 安全提示:如果你的表达式来自不可信的用户输入,不建议直接用ScriptEngine执行JS,因为存在脚本注入风险。这种情况下可以选择Apache Commons Math或者自己实现一个简单的整数表达式解析器,只支持加减乘除和括号运算。

内容的提问来源于stack exchange,提问作者Gino Marin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 15:17:48