summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/parserutils/pattern
diff options
context:
space:
mode:
authorBen Culkin <scorpress@gmail.com>2022-09-16 18:58:48 -0400
committerBen Culkin <scorpress@gmail.com>2022-09-16 18:58:48 -0400
commita3d2728f84375566da3da560b3faad018d34005d (patch)
treed50829207b8b4418c11d6385f49386259bb2cc8a /base/src/main/java/bjc/utils/parserutils/pattern
parent6186f1d87c5e170fa89aa327001706b0692526fc (diff)
Cleanup
Diffstat (limited to 'base/src/main/java/bjc/utils/parserutils/pattern')
-rw-r--r--base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java23
-rw-r--r--base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java28
-rw-r--r--base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java191
3 files changed, 194 insertions, 48 deletions
diff --git a/base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java b/base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java
new file mode 100644
index 0000000..535825e
--- /dev/null
+++ b/base/src/main/java/bjc/utils/parserutils/pattern/FunctionalPatternPart.java
@@ -0,0 +1,23 @@
+package bjc.utils.parserutils.pattern;
+
+import java.util.function.Supplier;
+
+final class FunctionalPatternPart implements PatternPart {
+ private final Supplier<String> func;
+ private final boolean canOptimize;
+
+ FunctionalPatternPart(Supplier<String> func, boolean canOptimize) {
+ this.func = func;
+ this.canOptimize = canOptimize;
+ }
+
+ @Override
+ public String toRegex() {
+ return func.get();
+ }
+
+ @Override
+ public boolean canOptimize() {
+ return canOptimize;
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java b/base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java
new file mode 100644
index 0000000..2f3b16d
--- /dev/null
+++ b/base/src/main/java/bjc/utils/parserutils/pattern/JoinerPatternPart.java
@@ -0,0 +1,28 @@
+package bjc.utils.parserutils.pattern;
+
+import java.util.StringJoiner;
+
+final class JoinerPatternPart implements PatternPart {
+ private final PatternPart[] parts;
+ private final String joiner;
+
+ JoinerPatternPart(PatternPart[] parts, String joiner) {
+ this.parts = parts;
+ this.joiner = joiner;
+ }
+
+ @Override
+ public String toRegex() {
+ StringJoiner sj = new StringJoiner(joiner);
+ for (PatternPart part : parts) sj.add(part.toRegex());
+ return sj.toString();
+ }
+
+ @Override
+ public boolean canOptimize() {
+ for (PatternPart part : parts)
+ if (!part.canOptimize()) return false;
+
+ return true;
+ }
+} \ No newline at end of file
diff --git a/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java b/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java
index 6661072..2fd59ca 100644
--- a/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java
+++ b/base/src/main/java/bjc/utils/parserutils/pattern/PatternPart.java
@@ -1,12 +1,14 @@
package bjc.utils.parserutils.pattern;
-import java.util.StringJoiner;
import java.util.function.Supplier;
import java.util.regex.*;
/**
* Builder interface for regex patterns.
*
+ * Note that you may need to add explicit non-grouping to get things to work
+ * right, based on the precedence of your regex operators.
+ *
* @author bjculkin
*
*/
@@ -17,27 +19,37 @@ public interface PatternPart {
* @return The regex this part represents.
*/
public String toRegex();
-
+
+ /**
+ * Can this regex be optimized?
+ *
+ * @return Whether or not this regex can be optimized to a string
+ */
public boolean canOptimize();
-
+
+ /**
+ * Create a new pattern part from component bits.
+ *
+ * @param canOptimize Whether this part can be optimized
+ * @param func The function that provides the regex text
+ *
+ * @return A pattern part w/ the given body
+ */
static PatternPart part(boolean canOptimize, Supplier<String> func) {
- return new PatternPart() {
-
- @Override
- public String toRegex() {
- return func.get();
- }
-
- @Override
- public boolean canOptimize() {
- return canOptimize;
- }
- };
- }
-
+ return new FunctionalPatternPart(func, canOptimize);
+ }
+
+ /**
+ * Create a new variable pattern part.
+ *
+ * @param source The function which supplies the text.
+ *
+ * @return A part that retrieves its bits from the given source
+ */
static PatternPart var(Supplier<String> source) {
return part(false, source);
}
+
/**
* Create a 'raw' pattern part, which just echoes the given string.
*
@@ -48,26 +60,20 @@ public interface PatternPart {
static PatternPart raw(String str) {
return part(true, () -> str);
}
-
+
+ /**
+ * Create a pattern composed of other patterns, interspersed with the given
+ * string.
+ *
+ * @param joiner The string to use as a joiner.
+ * @param parts The composed pattern parts.
+ *
+ * @return The given patterns composed by the parts, joined by `joiner`.
+ */
static PatternPart joining(String joiner, PatternPart... parts) {
- return new PatternPart() {
-
- @Override
- public String toRegex() {
- StringJoiner sj = new StringJoiner(joiner);
- for (PatternPart part : parts) sj.add(part.toRegex());
- return sj.toString();
- }
-
- @Override
- public boolean canOptimize() {
- for (PatternPart part : parts)
- if (!part.canOptimize()) return false;
-
- return true;
- }
- };
+ return new JoinerPatternPart(parts, joiner);
}
+
/**
* Create a pattern part which matches the given string.
*
@@ -78,7 +84,7 @@ public interface PatternPart {
static PatternPart literal(String str) {
return part(true, () -> Pattern.quote(str));
}
-
+
/**
* Create a pattern part which matches a single digit.
*
@@ -87,60 +93,149 @@ public interface PatternPart {
static PatternPart digit() {
return raw("\\d");
}
-
+
+ /**
+ * Create a character class pattern
+ *
+ * @param chars The characters that make up the class.
+ *
+ * @return A pattern representing the character class.
+ */
static PatternPart cclass(char... chars) {
return part(true, () -> {
StringBuilder sb = new StringBuilder("[");
- for (char ch : chars) sb.append(ch);
+ for (char ch : chars)
+ sb.append(ch);
sb.append("]");
return sb.toString();
});
}
-
+
+ /**
+ * Represents an inverted character class.
+ *
+ * @param chars The characters for the class not to include.
+ *
+ * @return A pattern representing a class that doesn't match the characters.
+ */
static PatternPart notCClass(char... chars) {
return part(true, () -> {
StringBuilder sb = new StringBuilder("[^");
- for (char ch : chars) sb.append(ch);
+ for (char ch : chars)
+ sb.append(ch);
sb.append("]");
return sb.toString();
});
}
-
+
+ /**
+ * Represents a pattern that matches any non-space character.
+ *
+ * @return A pattern that matches any non-space character.
+ */
static PatternPart nonspace() {
return raw("\\S");
}
-
+
+ /**
+ * Concatenate a series of pattern parts with whitespace.
+ *
+ * @param parts The parts to join
+ *
+ * @return A pattern that matches each of the given parts, separated by
+ * whitespace.
+ */
static PatternPart concat(PatternPart... parts) {
return joining(" ", parts);
}
-
+
+ /**
+ * Create a pattern which matches one of the given patterns.
+ *
+ * @param parts The possible patterns to match.
+ *
+ * @return A pattern which matches one of the given patterns.
+ */
static PatternPart alternate(PatternPart... parts) {
return joining("|", parts);
}
-
+
+ /**
+ * Create a pattern which matches the given pattern zero or more times.
+ *
+ * @param part The pattern to repeat
+ *
+ * @return A pattern which matches the given one zero or more times.
+ */
static PatternPart repeat(PatternPart part) {
return part(part.canOptimize(), () -> part.toRegex() + "*");
}
-
+
+ /**
+ * Create a pattern which matches the given one zero or more times.
+ *
+ * @param part The pattern to be optional.
+ *
+ * @return A pattern where the part is optional
+ */
static PatternPart optional(PatternPart part) {
return part(part.canOptimize(), () -> part.toRegex() + "?");
}
-
+
+ /**
+ * Create a pattern which matches the given pattern one or more times.
+ *
+ * @param part The pattern to repeat.
+ *
+ * @return A pattern which matches the given one one or more times.
+ */
static PatternPart repeatAtLeastOnce(PatternPart part) {
return part(part.canOptimize(), () -> part.toRegex() + "*");
}
-
+
+ /**
+ * Surround the given pattern with strings.
+ *
+ * @param lhs The left-hand side of the pattern.
+ * @param rhs The right-hand side of the pattern.
+ * @param part The pattern to match.
+ *
+ * @return A pattern surrounded by the given strings.
+ */
static PatternPart surround(String lhs, String rhs, PatternPart part) {
return part(part.canOptimize(), () -> lhs + part.toRegex() + rhs);
}
+
+ /**
+ * Wrap the given pattern in a capturing group.
+ *
+ * @param part The pattern to wrap.
+ *
+ * @return The pattern, wrapped in a capturing group
+ */
static PatternPart group(PatternPart part) {
return surround("(", ")", part);
}
+ /**
+ * Wrap the given pattern in a named-capturing group.
+ *
+ * @param groupName The name of the group
+ * @param part The pattern to wrap.
+ *
+ * @return A pattern wrap in a named-capturing group.
+ */
static PatternPart namedGroup(String groupName, PatternPart part) {
return surround("(<" + groupName + ">", ")", part);
}
-
+
+ /**
+ * Wrap the given pattern in a non-capturing group.
+ *
+ * @param part The pattern to wrap.
+ *
+ * @return A pattern wrap in a non-capturing group.
+ */
static PatternPart nonCaptureGroup(PatternPart part) {
return surround("(?:", ")", part);
}