Skip to content

Commit 49b9f83

Browse files
author
nat.pryce
committed
Added text pattern matchers
1 parent 9578cc8 commit 49b9f83

23 files changed

+902
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class AnyCharacter implements PatternComponent {
7+
public static final AnyCharacter INSTANCE = new AnyCharacter();
8+
9+
private AnyCharacter() {}
10+
11+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
12+
builder.append(".");
13+
}
14+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class CaptureGroup implements PatternComponent {
7+
private String name;
8+
private PatternComponent pattern;
9+
10+
public CaptureGroup(String name, PatternComponent pattern) {
11+
this.name = name;
12+
this.pattern = pattern;
13+
}
14+
15+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
16+
GroupNamespace subgroups = groups.create(name);
17+
builder.append("(");
18+
pattern.buildRegex(builder, subgroups);
19+
builder.append(")");
20+
}
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class CharacterInRange implements PatternComponent {
7+
private final String range;
8+
9+
public CharacterInRange(String range) {
10+
this.range = range;
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
builder.append("[").append(range).append("]");
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class CharacterInUnicodeCategory implements PatternComponent {
7+
private final String categoryName;
8+
9+
public CharacterInUnicodeCategory(String categoryName) {
10+
this.categoryName = categoryName;
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
builder.append("\\p{Is").append(categoryName).append("}");
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class CharacterNotInRange implements PatternComponent {
7+
private final String range;
8+
9+
public CharacterNotInRange(String range) {
10+
this.range = range;
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
builder.append("[^").append(range).append("]");
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class CharacterNotInUnicodeCategory implements PatternComponent {
7+
private final String categoryName;
8+
9+
public CharacterNotInUnicodeCategory(String categoryName) {
10+
this.categoryName = categoryName;
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
builder.append("\\P{Is").append(categoryName).append("}");
15+
}
16+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class Choice implements PatternComponent {
7+
private final PatternComponent[] alternatives;
8+
9+
public Choice(PatternComponent[] alternatives) {
10+
this.alternatives = alternatives.clone();
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
builder.append("(?:");
15+
boolean needsSeparator = false;
16+
for (PatternComponent alternative : alternatives) {
17+
if (needsSeparator) {
18+
builder.append("|");
19+
}
20+
else {
21+
needsSeparator = true;
22+
}
23+
24+
alternative.buildRegex(builder, groups);
25+
}
26+
builder.append(")");
27+
}
28+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class Exactly implements PatternComponent {
7+
private int requiredNumber;
8+
private PatternComponent repeatedPattern;
9+
10+
public Exactly(int requiredNumber, PatternComponent repeatedPattern) {
11+
this.requiredNumber = requiredNumber;
12+
this.repeatedPattern = repeatedPattern;
13+
}
14+
15+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
16+
repeatedPattern.buildRegex(builder, groups);
17+
builder.append("{");
18+
builder.append(requiredNumber);
19+
builder.append("}");
20+
21+
}
22+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
7+
public class GroupReference implements PatternComponent {
8+
private final String name;
9+
10+
public GroupReference(String name) {
11+
this.name = name;
12+
}
13+
14+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
15+
builder.append("\\").append(groups.resolve(name));
16+
}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.SeparatablePatternComponent;
5+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
6+
7+
import static org.hamcrest.text.pattern.Patterns.*;
8+
9+
public class ListOf implements SeparatablePatternComponent {
10+
private final PatternComponent element;
11+
private final PatternComponent separator;
12+
13+
public ListOf(PatternComponent element, PatternComponent separator) {
14+
this.element = element;
15+
this.separator = separator;
16+
}
17+
18+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
19+
optional(sequence(
20+
element,
21+
zeroOrMore(
22+
sequence(separator, element)))).buildRegex(builder, groups);
23+
}
24+
25+
public PatternComponent separatedBy(Object separator) {
26+
return new ListOf(element, toPattern(separator));
27+
}
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import java.util.regex.Pattern;
4+
5+
import org.hamcrest.text.pattern.PatternComponent;
6+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
7+
8+
9+
public class Literal implements PatternComponent {
10+
private String literal;
11+
12+
public Literal(String literal) {
13+
this.literal = literal;
14+
}
15+
16+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
17+
builder.append(Pattern.quote(literal));
18+
}
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class NullPatternComponent implements PatternComponent {
7+
public static final PatternComponent INSTANCE = new NullPatternComponent();
8+
9+
private NullPatternComponent() {
10+
// Private so you have to use the only INSTANCE
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
// Do nothing
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
5+
public class OneOrMore extends PatternModifier implements PatternComponent {
6+
public OneOrMore(PatternComponent pattern) {
7+
super(pattern);
8+
}
9+
10+
protected void appendModifier(StringBuilder builder) {
11+
builder.append("+");
12+
}
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
5+
public class Optional extends PatternModifier implements PatternComponent {
6+
public Optional(PatternComponent pattern) {
7+
super(pattern);
8+
}
9+
10+
protected void appendModifier(StringBuilder builder) {
11+
builder.append("?");
12+
}
13+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public abstract class PatternModifier implements PatternComponent {
7+
private PatternComponent pattern;
8+
9+
public PatternModifier(PatternComponent pattern) {
10+
this.pattern = pattern;
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
builder.append("(?:");
15+
pattern.buildRegex(builder, groups);
16+
builder.append(")");
17+
appendModifier(builder);
18+
}
19+
20+
protected abstract void appendModifier(StringBuilder builder);
21+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
import org.hamcrest.text.pattern.internal.naming.GroupNamespace;
5+
6+
public class Sequence implements PatternComponent {
7+
private final PatternComponent[] alternatives;
8+
9+
public Sequence(PatternComponent[] alternatives) {
10+
this.alternatives = alternatives.clone();
11+
}
12+
13+
public void buildRegex(StringBuilder builder, GroupNamespace groups) {
14+
for (PatternComponent alternative : alternatives) {
15+
alternative.buildRegex(builder, groups);
16+
}
17+
}
18+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.hamcrest.text.pattern.internal.ast;
2+
3+
import org.hamcrest.text.pattern.PatternComponent;
4+
5+
public class ZeroOrMore extends PatternModifier {
6+
public ZeroOrMore(PatternComponent pattern) {
7+
super(pattern);
8+
}
9+
10+
protected void appendModifier(StringBuilder builder) {
11+
builder.append("*");
12+
}
13+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.hamcrest.text.pattern.internal.naming;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
7+
public class GroupNamespace {
8+
private final GroupNamespace parent;
9+
private final Map<String, GroupNamespace> bindings = new HashMap<String,GroupNamespace>();
10+
private final IndexSequence nextGroupIndex;
11+
private final int groupIndex;
12+
13+
private GroupNamespace(GroupNamespace parent, IndexSequence nextGroupIndex) {
14+
this.parent = parent;
15+
this.nextGroupIndex = nextGroupIndex;
16+
this.groupIndex = nextGroupIndex.next();
17+
}
18+
19+
public GroupNamespace() {
20+
this(null, new IndexSequence());
21+
}
22+
23+
public int toIndex() {
24+
return groupIndex;
25+
}
26+
27+
public GroupNamespace create(String name) {
28+
if (bindings.containsKey(name)) {
29+
throw new IllegalArgumentException("duplicate name '"+name+"'");
30+
}
31+
32+
GroupNamespace child = new GroupNamespace(this, nextGroupIndex);
33+
bindings.put(name, child);
34+
return child;
35+
}
36+
37+
public int resolve(String pathAsString) {
38+
return resolve(Path.parse(pathAsString));
39+
}
40+
41+
public int resolve(Path path) {
42+
return environmentContaining(path.head()).resolveInternally(path.tail());
43+
}
44+
45+
public int resolveInternally(Path path) {
46+
if (path.size() == 0) {
47+
return groupIndex;
48+
}
49+
else if (bindings.containsKey(path.head())) {
50+
return bindings.get(path.head()).resolveInternally(path.tail());
51+
}
52+
else {
53+
throw new IllegalArgumentException("name '"+path.head()+"' not bound");
54+
}
55+
}
56+
57+
private GroupNamespace environmentContaining(String name) {
58+
if (bindings.containsKey(name)) {
59+
return bindings.get(name);
60+
}
61+
else if (parent != null) {
62+
return parent.environmentContaining(name);
63+
}
64+
else {
65+
throw new IllegalArgumentException("name '"+name+"' not bound");
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)