Regex: implement * and + operators

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin 2013-11-10 10:02:18 -06:00
parent d753edafcd
commit f979505b3d
2 changed files with 44 additions and 9 deletions

View File

@ -24,7 +24,11 @@ public class Regex {
expect(matcher.matches());
expect(matcher.groupCount() == groups.length);
for (int i = 1; i <= groups.length; ++i) {
expect(groups[i - 1].equals(matcher.group(i)));
if (groups[i - 1] == null) {
expect(matcher.group(i) == null);
} else {
expect(groups[i - 1].equals(matcher.group(i)));
}
}
}
@ -35,5 +39,7 @@ public class Regex {
expectGroups("a(a*?)(a?)(a??)(a+)(a*)a", "aaaaaa", "", "a", "", "aaa", "");
expectMatch("...", "abc");
expectNoMatch(".", "\n");
expectGroups("a(bb)*a", "abbbba", "bb");
expectGroups("a(bb)?(bb)+a", "abba", null, "bb");
}
}

View File

@ -63,18 +63,44 @@ class Compiler implements PikeVMOpcodes {
protected abstract void writeCode(Output output);
}
private class QuestionMark extends Expression {
private class Repeat extends Expression {
private Expression expr;
private int minCount, maxCount;
public QuestionMark(Expression expr) {
public Repeat(Expression expr, int minCount, int maxCount) {
if (minCount != 0 && minCount != 1) {
throw new RuntimeException("Unexpected min count: " + minCount);
}
if (maxCount != 1 && maxCount != -1) {
throw new RuntimeException("Unexpected max count: " + maxCount);
}
this.expr = expr;
this.minCount = minCount;
this.maxCount = maxCount;
}
protected void writeCode(Output output) {
output.add(SPLIT);
int jump = output.markJump();
expr.writeCode(output);
output.setJump(jump);
int start = output.offset;
if (minCount == 1 && maxCount == -1) {
expr.writeCode(output);
output.add(SPLIT_JMP);
output.add(start);
} else if (minCount == 0 && maxCount == -1) {
output.add(SPLIT);
int jump = output.markJump();
expr.writeCode(output);
output.add(SPLIT_JMP);
output.add(start + 2);
output.setJump(jump);
} else if (minCount == 0 && maxCount == 1) {
output.add(SPLIT);
int jump = output.markJump();
expr.writeCode(output);
output.setJump(jump);
} else {
throw new RuntimeException("Unexpected range: "
+ minCount + ", " + maxCount);
}
}
}
@ -145,8 +171,11 @@ class Compiler implements PikeVMOpcodes {
current.push(DOT);
continue;
case '?':
current.push(new QuestionMark(current.pop()));
break;
case '*':
case '+':
current.push(new Repeat(current.pop(),
c == '+' ? 1 : 0, c == '?' ? 1 : -1));
continue;
case '(':
if (index + 1 < array.length && array[index + 1] == '?') {
throw new UnsupportedOperationException("Not yet supported: "