author | Christian Urban <christian.urban@kcl.ac.uk> |
Sun, 04 Oct 2020 12:30:24 +0100 | |
changeset 771 | 3a12e096f9a0 |
parent 742 | b5b5583a3a08 |
permissions | -rw-r--r-- |
90
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
1 |
trait RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
2 |
def nullable: Boolean |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
3 |
def derive(c: Char): RegExp |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
4 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
5 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
6 |
case object Empty extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
7 |
def nullable = false |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
8 |
def derive(c: Char) = Empty |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
9 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
10 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
11 |
case object Eps extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
12 |
def nullable = true |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
13 |
def derive(c: Char) = Empty |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
14 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
15 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
16 |
case class Str(s: String) extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
17 |
def nullable = s.isEmpty |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
18 |
def derive(c: Char) = |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
19 |
if (s.isEmpty || s.head != c) Empty |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
20 |
else Str(s.tail) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
21 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
22 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
23 |
case class Cat(r: RegExp, s: RegExp) extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
24 |
def nullable = r.nullable && s.nullable |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
25 |
def derive(c: Char) = |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
26 |
if (r.nullable) Or(Cat(r.derive(c), s), s.derive(c)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
27 |
else Cat(r.derive(c), s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
28 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
29 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
30 |
case class Star(r: RegExp) extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
31 |
def nullable = true |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
32 |
def derive(c: Char) = Cat(r.derive(c), this) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
33 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
34 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
35 |
case class Or(r: RegExp, s: RegExp) extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
36 |
def nullable = r.nullable || s.nullable |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
37 |
def derive(c: Char) = Or(r.derive(c), s.derive(c)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
38 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
39 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
40 |
case class And(r: RegExp, s: RegExp) extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
41 |
def nullable = r.nullable && s.nullable |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
42 |
def derive(c: Char) = And(r.derive(c), s.derive(c)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
43 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
44 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
45 |
case class Not(r: RegExp) extends RegExp { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
46 |
def nullable = !r.nullable |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
47 |
def derive(c: Char) = Not(r.derive(c)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
48 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
49 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
50 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
51 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
52 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
53 |
object Matcher { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
54 |
def matches(r: RegExp, s: String): Boolean = { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
55 |
if (s.isEmpty) r.nullable |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
56 |
else matches(r.derive(s.head), s.tail) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
57 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
58 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
59 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
60 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
61 |
object Pimps { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
62 |
implicit def string2RegExp(s: String) = Str(s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
63 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
64 |
implicit def regExpOps(r: RegExp) = new { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
65 |
def | (s: RegExp) = Or(r, s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
66 |
def & (s: RegExp) = And(r, s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
67 |
def % = Star(r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
68 |
def %(n: Int) = rep(r, n) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
69 |
def ? = Or(Eps, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
70 |
def ! = Not(r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
71 |
def ++ (s: RegExp) = Cat(r, s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
72 |
def ~ (s: String) = Matcher.matches(r, s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
73 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
74 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
75 |
implicit def stringOps(s: String) = new { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
76 |
def | (r: RegExp) = Or(s, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
77 |
def | (r: String) = Or(s, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
78 |
def & (r: RegExp) = And(s, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
79 |
def & (r: String) = And(s, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
80 |
def % = Star(s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
81 |
def % (n: Int) = rep(Str(s), n) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
82 |
def ? = Or(Eps, s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
83 |
def ! = Not(s) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
84 |
def ++ (r: RegExp) = Cat(s, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
85 |
def ++ (r: String) = Cat(s, r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
86 |
def ~ (t: String) = Matcher.matches(s, t) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
87 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
88 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
89 |
def rep(r: RegExp, n: Int): RegExp = |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
90 |
if (n <= 0) Star(r) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
91 |
else Cat(r, rep(r, n - 1)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
92 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
93 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
94 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
95 |
object Test { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
96 |
import Pimps._ |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
97 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
98 |
val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
99 |
val int = ("+" | "-").? ++ digit.%(1) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
100 |
val real = ("+" | "-").? ++ digit.%(1) ++ ("." ++ digit.%(1)).? ++ (("e" | "E") ++ ("+" | "-").? ++ digit.%(1)).? |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
101 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
102 |
def main(args: Array[String]) { |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
103 |
val ints = List("0", "-4534", "+049", "99") |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
104 |
val reals = List("0.9", "-12.8", "+91.0", "9e12", "+9.21E-12", "-512E+01") |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
105 |
val errs = List("", "-", "+", "+-1", "-+2", "2-") |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
106 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
107 |
ints.foreach(s => assert(int ~ s)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
108 |
reals.foreach(s => assert(!(int ~ s))) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
109 |
errs.foreach(s => assert(!(int ~ s))) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
110 |
|
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
111 |
ints.foreach(s => assert(real ~ s)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
112 |
reals.foreach(s => assert(real ~ s)) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
113 |
errs.foreach(s => assert(!(real ~ s))) |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
114 |
} |
e1f94216f39d
added
Christian Urban <christian dot urban at kcl dot ac dot uk>
parents:
diff
changeset
|
115 |
} |