aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/edify/builder/__init__.py0
-rw-r--r--src/edify/builder/abc.py10
-rw-r--r--src/edify/builder/builder.py33
-rw-r--r--src/edify/builder/constants.py10
-rw-r--r--src/edify/builder/datatypes.py73
-rw-r--r--src/edify/builder/errors.py2
-rw-r--r--src/edify/builder/escaped.py9
-rw-r--r--src/edify/builder/part.py30
-rw-r--r--src/edify/builder/quantifier.py64
9 files changed, 147 insertions, 84 deletions
diff --git a/src/edify/builder/__init__.py b/src/edify/builder/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/edify/builder/__init__.py
diff --git a/src/edify/builder/abc.py b/src/edify/builder/abc.py
new file mode 100644
index 0000000..a918b5a
--- /dev/null
+++ b/src/edify/builder/abc.py
@@ -0,0 +1,10 @@
+from abc import ABC, abstractmethod
+
+
+class Builder(ABC):
+ @abstractmethod
+ def build(self):
+ pass
+
+ def __str__(self):
+ return self.build()
diff --git a/src/edify/builder/builder.py b/src/edify/builder/builder.py
index 2150314..e139ec1 100644
--- a/src/edify/builder/builder.py
+++ b/src/edify/builder/builder.py
@@ -1,14 +1,25 @@
-"""This is the main module for the edify builder. It is responsible for building
-Regular Expressions from simple function chains.
-"""
+from .abc import Builder
+from .part import Part
+from .errors import NotPart
+from re import match
-class RegexBuilder:
- """RegexBuilder helps build and use regular expressions using its methods.
- """
-
- regex = None
+class RegexBuilder(Builder):
def __init__(self):
- """Initialize the RegexBuilder.
- """
- self.regex = ""
+ self.parts = []
+
+ def build(self):
+ return "".join(map(str, self.parts))
+
+ def add(self, part):
+ self.parts.append(part)
+
+ def part(self, part):
+ if not (issubclass(type(part), Builder) or isinstance(part, str)):
+ raise NotPart(f"{part} is not a valid Part")
+
+ self.parts.append(part)
+ return self
+
+ def match(self, regex):
+ return match(self.build(), regex)
diff --git a/src/edify/builder/constants.py b/src/edify/builder/constants.py
new file mode 100644
index 0000000..c1e7f68
--- /dev/null
+++ b/src/edify/builder/constants.py
@@ -0,0 +1,10 @@
+ANY = "."
+WHITESPACE = "\\s"
+NON_WHITESPACE = "\\S"
+DIGIT = "\\d"
+NON_DIGIT = "\\D"
+WORD = "\\w"
+NON_WORD = "\\W"
+NEWLINE = "\\n"
+TAB = "\\t"
+NULL = "\\0"
diff --git a/src/edify/builder/datatypes.py b/src/edify/builder/datatypes.py
deleted file mode 100644
index cb3ea13..0000000
--- a/src/edify/builder/datatypes.py
+++ /dev/null
@@ -1,73 +0,0 @@
-"""
- This file contains the datatypes used by the edify regex builder.
-
- The datatypes are:
- - letter: A single upper or lowercase letter (a-z or A-Z)
- - digit: A single digit (0-9)
- - word: A single word (a-z, A-Z, 0-9, _)
- - space: A single space (\s)
- - any: Any character or special character
-"""
-
-
-def letter(type: str = "all") -> str:
- """Returns a regex that matches a single letter.
-
- Parameters:
- type (str): The type of letter to match.
- - "all" (default): Matches any letter (a-z or A-Z)
- - "upper": Matches any upper case letter (A-Z)
- - "lower": Matches any lower case letter (a-z)
-
- Returns:
- str: A regex that matches a single letter.
-
- Raises:
- ValueError: If any of the parameters are invalid.
- """
- letters = "abcdefghijklmnopqrstuvwxyz"
- if type == "upper":
- letters = letters.upper()
- elif type == "lower":
- letters = letters
- elif type == "all":
- letters = letters + letters.upper()
- else:
- raise ValueError("Invalid letter type: " + type)
- return "[" + letters + "]"
-
-
-def digit() -> str:
- """Returns a regex that matches a single digit.
-
- Returns:
- str: A regex that matches a single digit.
- """
- return "[1234567890]"
-
-
-def word() -> str:
- """Returns a regex that matches a single word.
-
- Returns:
- str: A regex that matches a single word.
- """
- return "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_]"
-
-
-def space() -> str:
- """Returns a regex that matches a single space.
-
- Returns:
- str: A regex that matches a single space.
- """
- return "[\s]"
-
-
-def any() -> str:
- """Returns a regex that matches any character.
-
- Returns:
- str: A regex that matches any character.
- """
- return "."
diff --git a/src/edify/builder/errors.py b/src/edify/builder/errors.py
new file mode 100644
index 0000000..6f880f8
--- /dev/null
+++ b/src/edify/builder/errors.py
@@ -0,0 +1,2 @@
+class NotPart(Exception):
+ pass
diff --git a/src/edify/builder/escaped.py b/src/edify/builder/escaped.py
new file mode 100644
index 0000000..b081706
--- /dev/null
+++ b/src/edify/builder/escaped.py
@@ -0,0 +1,9 @@
+from .abc import Builder
+
+
+class Escaped(Builder):
+ def __init__(self, target):
+ self.target = target
+
+ def build(self):
+ return f"\\{self.target}"
diff --git a/src/edify/builder/part.py b/src/edify/builder/part.py
new file mode 100644
index 0000000..e49ace2
--- /dev/null
+++ b/src/edify/builder/part.py
@@ -0,0 +1,30 @@
+from .abc import Builder
+from abc import abstractmethod
+
+
+class Part(Builder):
+ def __init__(self, target):
+ self.target = target
+
+ @abstractmethod
+ def build(self):
+ pass
+
+
+class Any(Part):
+ def __init__(self, *targets, capture = True, name = None):
+ if not capture and name:
+ raise ValueError("Cannot specify group name without capturing")
+
+ if name == "":
+ raise ValueError("Cannot specify empty group name")
+
+ super().__init__(targets)
+ self.capture = capture
+ self.name = name
+
+ def build(self):
+ targets = "|".join(map(str, self.target))
+ capture = "" if self.capture else "?: "
+ name = f"<{self.name}>" if self.name else ""
+ return f"{capture}{name}{targets}"
diff --git a/src/edify/builder/quantifier.py b/src/edify/builder/quantifier.py
new file mode 100644
index 0000000..c26fbad
--- /dev/null
+++ b/src/edify/builder/quantifier.py
@@ -0,0 +1,64 @@
+from .abc import Builder
+from abc import abstractmethod
+
+
+class Quantifier(Builder):
+ def __init__(self, target):
+ self.target = target
+
+ @abstractmethod
+ def build(self):
+ pass
+
+
+class Optional(Quantifier):
+ def build(self):
+ return f"{self.target}?"
+
+
+class ZeroOrMore(Quantifier):
+ def build(self):
+ return f"{self.target}*"
+
+
+class OneOrMore(Quantifier):
+ def build(self):
+ return f"{self.target}+"
+
+
+class Exact(Quantifier):
+ def __init__(self, target, count):
+ super().__init__(target)
+ self.count = count
+
+ def build(self):
+ return f"{self.target}{{self.count}}"
+
+
+class Range(Quantifier):
+ def __init__(self, target, min, max):
+ super().__init__(target)
+ self.min = min
+ self.max = max
+
+ def build(self):
+ return f"{self.target}{{self.min, self.max}}"
+
+
+class AtLeast(Quantifier):
+ def __init__(self, target, min):
+ super().__init__(target)
+ self.min = min
+
+ def build(self):
+ return f"{self.target}{{self.min,}}"
+
+
+class AtMost(Quantifier):
+ def __init__(self, target, max):
+ super().__init__(target)
+ self.max = max
+
+ def build(self):
+ return f"{self.target}{{,self.max}}"
+