com.reactific.helpers.Patterns.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2015-2017 Reactific Software LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reactific.helpers
import scala.util.matching.Regex
/** One line sentence description here.
* Further description here.
*/
object Patterns {
/** Join a sequence of patterns together */
def join(r: Regex*): Regex = {
val initialBufferSize = 1024
val result: StringBuffer = new StringBuffer(initialBufferSize)
r.foldLeft(result) {
case (result: StringBuffer, regex: Regex) ⇒
result.append(regex.unanchored.pattern.pattern); result
}
.toString
.r
}
private def serialize(r: Seq[Regex]): String = r.foldLeft("") {
case ((x, y)) ⇒ x + y.pattern.pattern
}
/** Make a pattern into various repeating forms of itself */
def anchored(r: Regex*): Regex = ("^" + serialize(r) + "$").r
def group(r: Regex*): Regex = ("(?:" + serialize(r) + ")").r
def capture(r: Regex, name: String = ""): Regex = {
if (name.isEmpty) {
s"(${r.pattern.pattern})".r
} else {
s"(?<$name>${r.pattern.pattern})".r
}
}
def optional(r: Regex): Regex = ("(?:" + r.pattern.pattern + ")?").r
def atLeastOne(r: Regex): Regex = ("(?:" + r.pattern.pattern + ")+").r
def oneOrMore(r: Regex): Regex = atLeastOne(r)
def zeroOrMore(r: Regex): Regex = ("(?:" + r.pattern.pattern + ")*").r
def between(min: Int, max: Int, r: Regex): Regex =
("(?:" + r.pattern.pattern + s"){$min,$max}").r
def alternate(r1: Regex, r2: Regex): Regex =
("(?:" + r1.pattern.pattern + ")|(?:" + r2.pattern.pattern + ")").r
// From RFC 2822. The pattern names below match the grammar production
// names and definitions from the RFC
lazy val atext: Regex = "[-A-Za-z0-9!#$%&'*+/=?^_`|~]".r
lazy val atom: Regex = atLeastOne(atext)
lazy val dot_atom: Regex = join(atom, zeroOrMore(join("[.]".r, atom)))
lazy val no_ws_ctl: Regex =
"[\\u0001-\\u0008\\u000B-\\u000C\\u000E-\\u001F\\u007F]".r
lazy val qtext: Regex =
alternate(no_ws_ctl, "[!\\u0023-\\u005B\\u005D-\\u007E]".r)
lazy val quoted_string: Regex = join("\"".r, zeroOrMore(qtext), "\"".r)
lazy val local_part: Regex = alternate(dot_atom, quoted_string)
lazy val quoted_pair: Regex = "\\\\.".r
lazy val dtext: Regex = join(no_ws_ctl, "[!-Z^-~]".r)
lazy val dcontent: Regex = alternate(dtext, quoted_pair)
lazy val domain_literal: Regex = join("\\[]".r, zeroOrMore(dcontent), "]".r)
lazy val domain_part: Regex = alternate(dot_atom, domain_literal)
lazy val addr_spec: Regex = join(group(local_part), "@".r, group(domain_part))
lazy val EmailAddress: Regex = addr_spec
lazy val Identifier: Regex = "[-\\w_+=|!.^@#%*?]+".r
lazy val Markdown: Regex =
"[-\\s\\w~`!@#$%^&*()_+={}\\[]|\\\\:;\"'<>,.?/ ]*".r
lazy val Password: Regex = between(6, 64, Markdown)
lazy val LegalName: Regex =
join(Identifier, zeroOrMore(join(" ".r, Identifier)))
// TODO: convert these patterns to use the constructors so we
// can comprehend them!
lazy val DomainName: Regex =
("(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*[a-zA-Z0-9])\\.){0,126}" +
"(?:[A-Za-z0-9][-A-Za-z0-9]*[A-Za-z0-9])").r
lazy val TcpPort: Regex =
"\\d{1,4}|[0-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5]".r
lazy val IPv4Address: Regex =
("(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" +
"(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])").r
lazy val UniformResourceLocator: Regex =
("^(https?|ftp|file)://" +
"[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]$").r
lazy val URLPathable: Regex = "[-A-Za-z0-9_.~]{1,64}".r
lazy val Title: Regex = between(4, 70, "[-\\s\\w\\d+:%!_{}|;<>,.?]".r)
lazy val NotAllowedInUrl: Regex = "[^-\\w\\d._+|]".r
}