-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathVerbalExpression.scala
94 lines (66 loc) · 3.49 KB
/
VerbalExpression.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package com.github.verbalexpressions
import java.util.regex.Pattern
import com.github.verbalexpressions.VerbalExpression._
case class VerbalExpression(prefix: String = "", expression: String = "", suffix: String = "", modifiers: Int = 0) {
def add(value: String) = copy(expression = expression + value)
def andThen(value: StringOrVerbalExp) = add(s"($value)")
def `then` = andThen _
def find = andThen _
def maybe(value: StringOrVerbalExp) = add(s"($value)?")
def zeroOrMore(value: StringOrVerbalExp) = add(s"($value)*")
def oneOrMore(value: StringOrVerbalExp) = add(s"($value)+")
def multiple = oneOrMore _
def many = oneOrMore _
def anything = add("(.*)")
def anythingBut(value: StringOrVerbalExp) = add(s"([^$value]*)")
def something = add("(.+)")
def somethingBut(value: StringOrVerbalExp) = add(s"([^$value]+)")
def whitespaces(enable: Boolean = true) = add(if (enable) "\\s+" else "\\S+")
def words(enable: Boolean = true) = add(if (enable) "\\w+" else "\\W+")
def digits(enable: Boolean = true) = add(if (enable) "\\d+" else "\\D+")
def anyOf(value: StringOrVerbalExp) = add(s"[$value]")
def any = anyOf _
def lineBreak = add("(\\n|(\\r\\n))")
def startOfLine(enable: Boolean = true) = copy(prefix = if (enable) "^" else "")
def endOfLine(enable: Boolean = true) = copy(suffix = if (enable) "$" else "")
def or(value: StringOrVerbalExp) = copy("(" + prefix, expression + ")|(" + value, ")" + suffix)
def range(args: (Any, Any)*) = add(s"[${(args map {case (a, b) => s"$a-$b"}).mkString}]")
def addModifier(modifier: Modifier) = copy(modifiers = modifiers | modifier.mask)
def removeModifier(modifier: Modifier) = copy(modifiers = modifiers ^ modifier.mask)
def modify(modifier: Modifier, add: Boolean) = if (add) addModifier(modifier) else removeModifier(modifier)
def withAnyCase(enable: Boolean = true) = modify(CaseInsensitive, enable)
def searchOneLine(enable: Boolean = true) = modify(MultiLine, enable)
def repeat(n: Int) = add(s"{$n}")
def repeat(atleast: Int, atmost: Int) = add(s"{$atleast,$atmost}")
def repeatAtleast(n: Int) = add(s"{$n,}")
def beginCapture = add("(")
def endCapture = add(")")
def reluctant = add("?")
def possessive = add("+")
def replace(source: String, value: String) = source.replaceAll(toString, value)
lazy val compile = Pattern.compile(prefix + expression + suffix, modifiers)
def regexp = compile.pattern()
def test = Pattern.matches(toString, _: String)
def check = test
def notMatch(test: String) = !check(test)
override def toString = regexp
}
object VerbalExpression {
sealed trait StringOrVerbalExp
implicit def lift(s: String): StringOrVerbalExp = new StringOrVerbalExp {override def toString = Pattern.quote(s)}
implicit def lift(v: VerbalExpression): StringOrVerbalExp = new StringOrVerbalExp {override def toString = v.regexp}
sealed abstract class Modifier(val mask: Int)
object UnixLines extends Modifier(Pattern.UNIX_LINES)
object CaseInsensitive extends Modifier(Pattern.CASE_INSENSITIVE)
object Comments extends Modifier(Pattern.COMMENTS)
object MultiLine extends Modifier(Pattern.MULTILINE)
object Dotall extends Modifier(Pattern.DOTALL)
object UnixCase extends Modifier(Pattern.UNICODE_CASE)
//object UnicodeCharacterClass extends(Pattern.UNICODE_CHARACTER_CLASS)
implicit class StringMatchUtils(s: String) {
def is(expr: VerbalExpression) = expr check s
def matches = is _
def isNot(expr: VerbalExpression) = expr notMatch s
}
val $ = VerbalExpression()
}