我可以使用以下代码ABC(10,5)
替换(10)%(5)
:
replaceAll("ABC\\(([^,]*)\\,([^,]*)\\)", "($1)%($2)")
但是我无法弄清楚如何为ABC(ABC(20,2),5)
或ABC(ABC(30,2),3+2)
做到这一点。
如果我能够转换为((20)%(2))%5
,我该如何转换回ABC(ABC(20,2),5)
?
谢谢, Ĵ
答案 0 :(得分:1)
我将回答第一个问题。我无法在一个replaceAll
中完成任务。我认为它甚至无法实现。但是,如果我使用循环,那么这应该为你工作:
String termString = "([0-9+\\-*/()%]*)";
String pattern = "ABC\\(" + termString + "\\," + termString + "\\)";
String [] strings = {"ABC(10,5)", "ABC(ABC(20,2),5)", "ABC(ABC(30,2),3+2)"};
for (String str : strings) {
while (true) {
String replaced = str.replaceAll(pattern, "($1)%($2)");
if (replaced.equals(str)) {
break;
}
str = replaced;
}
System.out.println(str);
}
我假设您正在为数字表达式编写解析器,因此定义了术语termString = "([0-9+\\-*/()%]*)"
。它输出:
(10)%(5)
((20)%(2))%(5)
((30)%(2))%(3+2)
编辑根据OP请求,我添加了解码字符串的代码。它比前进的场景更加苛刻:
String [] encoded = {"(10)%(5)", "((20)%(2))%(5)", "((30)%(2))%(3+2)"};
String decodeTerm = "([0-9+\\-*ABC\\[\\],]*)";
String decodePattern = "\\(" + decodeTerm + "\\)%\\(" + decodeTerm + "\\)";
for (String str : encoded) {
while (true) {
String replaced = str.replaceAll(decodePattern, "ABC[$1,$2]");
if (replaced.equals(str)) {
break;
}
str = replaced;
}
str = str.replaceAll("\\[", "(");
str = str.replaceAll("\\]", ")");
System.out.println(str);
}
输出是:
ABC(10,5)
ABC(ABC(20,2),5)
ABC(ABC(30,2),3+2)
答案 1 :(得分:1)
您可以先开始评估最可重复的内部表达式,直到不再存在redux。但是,您必须照顾其他,
,(
和)
。 @BorisStrandjev的解决方案更好,更具防弹性。
String infix(String expr) {
// Use place holders for '(' and ')' to use regex [^,()].
expr = expr.replaceAll("(?!ABC)\\(", "<<");
expr = expr.replaceAll("(?!ABC)\\)", ">>");
for (;;) {
String expr2 = expr.replaceAll("ABC\\(([^,()]*)\\,([^,()]*)\\)",
"<<$1>>%<<$2>>");
if (expr2 == expr)
break;
expr = expr2;
}
expr = expr.replaceAll("<<", ")");
expr = expr.replaceAll(">>", ")");
return expr;
}
答案 2 :(得分:1)
您可以使用此正则表达式库https://github.com/florianingerl/com.florianingerl.util.regex,它也支持递归正则表达式。
将ABC(ABC(20,2),5)转换为((20)%(2))%(5)如下所示:
Pattern pattern = Pattern.compile("(?<abc>ABC\\((?<arg1>(?:(?'abc')|[^,])+)\\,(?<arg2>(?:(?'abc')|[^)])+)\\))");
Matcher matcher = pattern.matcher("ABC(ABC(20,2),5)");
String replacement = matcher.replaceAll(new DefaultCaptureReplacer() {
@Override
public String replace(CaptureTreeNode node) {
if ("abc".equals(node.getGroupName())) {
return "(" + replace(node.getChildren().get(0)) + ")%(" + replace(node.getChildren().get(1)) + ")";
} else
return super.replace(node);
}
});
System.out.println(replacement);
assertEquals("((20)%(2))%(5)", replacement);
再次转换,即从((20)%(2))%(5)转换回ABC(ABC(20,2),5),如下所示:
Pattern pattern = Pattern.compile("(?<fraction>(?<arg>\\(((?:(?'fraction')|[^)])+)\\))%(?'arg'))");
Matcher matcher = pattern.matcher("((20)%(2))%(5)");
String replacement = matcher.replaceAll(new DefaultCaptureReplacer() {
@Override
public String replace(CaptureTreeNode node) {
if ("fraction".equals(node.getGroupName())) {
return "ABC(" + replace(node.getChildren().get(0)) + "," + replace(node.getChildren().get(1)) + ")";
} else if ("arg".equals(node.getGroupName())) {
return replace(node.getChildren().get(0));
} else
return super.replace(node);
}
});
System.out.println(replacement);
assertEquals("ABC(ABC(20,2),5)", replacement);
答案 3 :(得分:0)
您可以尝试使用波兰表示法重写字符串,然后将%X Y 替换为 ABC(X,Y)。
Here是波兰表示法的维基链接。
问题是当你在字符串中递归替换它们时,你需要找出首先发生了哪些 ABC(X,Y)的重写。波兰表示法对于解密&#34;这些重写的顺序发生并广泛用于表达式评估。
您可以通过使用堆栈并记录首先发生的替换来执行此操作:找到最内部的括号集,仅将该表达式推送到堆栈中,然后从字符串中删除它。当您想要重建表达式原始表达式时,只需从堆栈顶部开始并应用反向转换(X)%(Y) - &gt;的 ABC(X,Y)强>
这有点是波兰表示法的一种形式,唯一的区别是你不将整个表达式存储为字符串,而是将其存储在堆栈中以便于处理。
简而言之,在替换时,从最内层的术语(其中没有括号的术语)开始并应用反向替换。
使用(X)%(Y) - &gt;可能会有所帮助 ABC {X,Y} 作为中间重写规则,然后将大括号重写为圆括号。这样就可以更容易地确定哪个是最内部的术语,因为新术语不会使用圆括号。它也更容易实现,但不是那么优雅。