[英]How to parse dice notation with a Java regular expression?
标准RPG骰子表示法是这样的:“ AdB [x /] C [+-D]”,其中A,B,C,D是自然数:A是掷骰子的数目,B是每个骰子的边数D,C是后面的乘数或除数,D是加法或减法。
一些例子:
我想要一个Java方法,该方法以这种格式输入字符串并解析出A,B,C和D的正确整数值。(说:如果C表示除数,则存储一个负整数;同样如果我将D表示为减法,请执行相同的操作。)实际上,我已经通过一些循环来实现了这一点,该循环可以查看String中的各个字符值,但作为sin很难看。
我的直觉是,使用正则表达式可以更简洁地解决此问题,但是坦率地说,我对该主题一无所知。 关于如何做到的任何建议? 而且,如果对该问题有一个更优雅的抽象(例如,任意数量的单独的x / +-修饰符;或者需要将x转换为*),我也可以接受。
这个问题给出了一个紧密相关的正则表达式,但没有说明如何从中提取参数: Java Regex重复(骰子符号解析)
这个命名组示例从您的样本输入中产生了一些有希望的结果。
注意 :命名正则表达式组需要Java 7。
String pattern = "(?<A>\\d*)d((?<B>\\d+)(?<math>(?<mult>[x\\/](?<C>\\d+))?(?<add>[+-](?<D>\\d+))?)?)?";
Pattern p = Pattern.compile(pattern);
String[] tests = new String[] {
"d6", "3d6", "4d6+1", "3d6x10", "d6/2", "3d4/2-7", "12d4-", "d-8", "4dx"
};
for (String test : tests) {
System.out.printf("Testing \"%s\"\n", test);
Matcher m = p.matcher(test);
if (m.matches()) {
String groupA = m.group("A");
if (groupA == null) {
groupA = "1"; // default one roll
}
String groupB = m.group("B");
if (groupB == null) {
groupB = "6"; // default six-sided die
}
String groupC = m.group("C");
if (groupC == null) {
groupC = "1"; // default multiply or divide by 1
}
String groupD = m.group("D");
if (groupD == null) {
groupD = "0"; // default add or subtract 0
}
int a = Integer.parseInt(groupA);
int b = Integer.parseInt(groupB);
int c = Integer.parseInt(groupC);
int d = Integer.parseInt(groupD);
String groupMath = m.group("math");
if (groupMath != null && groupMath.isEmpty()) {
groupMath = null;
}
String groupAdd = m.group("add");
String groupMult = m.group("mult");
System.out.printf("A: %d\n", a);
System.out.printf("B: %d\n", b);
System.out.printf("C: %d\n", c);
System.out.printf("D: %d\n", d);
System.out.println("------");
System.out.printf("math: %s\n", groupMath);
System.out.printf("mult: %s\n", groupMult);
System.out.printf("add: %s\n", groupAdd);
} else {
System.out.println("No Match!");
}
System.out.println();
}
Testing "d6"
A: 1
B: 6
C: 1
D: 0
------
math: null
mult: null
add: null
Testing "3d6"
A: 3
B: 6
C: 1
D: 0
------
math: null
mult: null
add: null
Testing "4d6+1"
A: 4
B: 6
C: 1
D: 1
------
math: +1
mult: null
add: +1
Testing "3d6x10"
A: 3
B: 6
C: 10
D: 0
------
math: x10
mult: x10
add: null
Testing "d6/2"
A: 1
B: 6
C: 2
D: 0
------
math: /2
mult: /2
add: null
Testing "3d4/2-7"
A: 3
B: 4
C: 2
D: 7
------
math: /2-7
mult: /2
add: -7
Testing "12d4-"
No Match!
Testing "d-8"
No Match!
Testing "4dx"
No Match!
这不是最聪明或最优雅的方法,但是它简短,易读且功能强大。 由于我不确定您打算如何使用它,因此没有为输出或将其添加到API /库中添加任何花式:
public class DieRegex {
public static void main(String[] args) {
int amount, die, mult = 1, add = 0;
Pattern p = Pattern.compile("([1-9]\\d*)?d([1-9]\\d*)([/x][1-9]\\d*)?([+-]\\d+)?");
Matcher m = p.matcher("d20");
if (m.matches()) {
amount = (m.group(1) != null) ? Integer.parseInt(m.group(1)) : 1;
die = Integer.parseInt(m.group(2));
if (m.group(3) != null) {
boolean positive = m.group(3).startsWith("x");
int val = Integer.parseInt(m.group(3).substring(1));
mult = positive ? val : -val;
}
if (m.group(4) != null) {
boolean positive = m.group(4).startsWith("+");
int val = Integer.parseInt(m.group(4).substring(1));
add = positive ? val : -val;
}
}
else
System.out.println("No match"); // Do whatever you need
}
}
注意 :根据有关检查输入的注释:
amount
(A) die
(B)和mult
(C)必须大于0。然而,正数与前导零不准( 02d20
是无效的, 2d20
是正确的形式)。 可以提前解决此问题,但会使正则表达式更加复杂。 add
(D)可以是任何数字(即使有前导零)。 mult
(C) add
(d)分别为1和0,如果在字符串中不存在它们。 它只是一个默认值,表示“无值”。 d
/
或x
后跟一个非负数(默认为1) +
或-
后跟一个非负数(默认为0) 我没有对其进行广泛的测试,但是根据您的解释,以下代码有效。 如果发现有问题,可能需要对正则表达式进行一些细微调整。 此版本与其他版本最大的不同是,它在名为RPGDice的类中进行了模块化,您可以使用RPGDice.parse(expr)实例化该类,并获得一个包含不同属性(滚动,面,乘数,加法)的RPGDice实例。
public class RPGDice {
private static final Pattern DICE_PATTERN = Pattern.compile("(?<A>\\d*)d(?<B>\\d+)(?>(?<MULT>[x/])(?<C>\\d+))?(?>(?<ADD>[+-])(?<D>\\d+))?");
private int rolls = 0;
private int faces = 0;
private int multiplier = 0;
private int additive = 0;
public RPGDice(int rolls, int faces, int multiplier, int additive) {
this.rolls = rolls;
this.faces = faces;
this.multiplier = multiplier;
this.additive = additive;
}
public int getRolls() {
return rolls;
}
public int getFaces() {
return faces;
}
public int getMultiplier() {
return multiplier;
}
public int getAdditive() {
return additive;
}
@Override
public String toString() {
return String.format("{\"rolls\": %s, \"faces\": %s, \"multiplier\": %s, \"additive\": %s}", rolls, faces, multiplier, additive);
}
private static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
private static Integer getInt(Matcher matcher, String group, int defaultValue) {
String groupValue = matcher.group(group);
return isEmpty(groupValue) ? defaultValue : Integer.valueOf(groupValue);
}
private static Integer getSign(Matcher matcher, String group, String positiveValue) {
String groupValue = matcher.group(group);
return isEmpty(groupValue) || groupValue.equals(positiveValue) ? 1 : -1;
}
public static RPGDice parse(String str) {
Matcher matcher = DICE_PATTERN.matcher(str);
if(matcher.matches()) {
int rolls = getInt(matcher, "A", 1);
int faces = getInt(matcher, "B", -1);
int multiplier = getInt(matcher, "C", 1);
int additive = getInt(matcher, "D", 0);
int multiplierSign = getSign(matcher, "MULT", "x");
int additiveSign = getSign(matcher, "ADD", "+");
return new RPGDice(rolls, faces, multiplier * multiplierSign, additive * additiveSign);
}
return null;
// OR
// throw new IllegalArgumentException("Invalid Expression");
}
public static void main(String[] args) {
System.out.println(RPGDice.parse("d6"));
System.out.println(RPGDice.parse("d6x"));
System.out.println(RPGDice.parse("33d6x10"));
System.out.println(RPGDice.parse("336x10"));
System.out.println(RPGDice.parse("d6/"));
System.out.println(RPGDice.parse("d6/5"));
System.out.println(RPGDice.parse("d6/5+2"));
System.out.println(RPGDice.parse("2d6/5-32"));
System.out.println(RPGDice.parse("2d6/5+-32"));
}
}
输出:
{"rolls": 1, "faces": 6, "multiplier": 1, "additive": 0}
null
{"rolls": 33, "faces": 6, "multiplier": 10, "additive": 0}
null
null
{"rolls": 1, "faces": 6, "multiplier": -5, "additive": 0}
{"rolls": 1, "faces": 6, "multiplier": -5, "additive": 2}
{"rolls": 2, "faces": 6, "multiplier": -5, "additive": -32}
null
下面的代码示例的输出显示了使用正则表达式解析骰子符号时需要了解的内容。
public class RegEx
{
private static final int EXPECTED_GROUP_COUNT = 7;
private static final Pattern pattern = Pattern.compile("(\\d+)?[Dd](\\d+)([Xx/](\\d+))?(([+-])(\\d+))?");
private static void matchit(final String value)
{
final Matcher matcher = pattern.matcher(value);
if (matcher.matches())
{
final int groupCount;
final MatchResult matchResult = matcher.toMatchResult();
groupCount = matchResult.groupCount();
System.out.println("kapow: " + value + ", groups: " + groupCount);
if (groupCount == EXPECTED_GROUP_COUNT)
{
for (int index = 0; index <= groupCount; ++index)
{
final String currentGroup = matchResult.group(index);
System.out.println("\tgroup[" + index + "]: " + currentGroup);
}
}
else
{
System.out.println("match error; wrong group count");
}
}
else
{
System.out.println("Format not recognized: " + value);
}
}
public static void main(
String[] args)
{
final String[] thingArray =
{
"3d6",
"d7",
"4D6+4",
"3d6x10",
"d6/2"
};
for (final String thing : thingArray)
{
matchit(thing);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.