class RegexSyntaxException(message: String) extends Exception(message)
case class Group(matching: String, startPositionMatching: Int, indexGroup: Int)
case class Full(matching: String, startPositionMatching: Int)
case class MatchResult(isMatching: Boolean, regexHasGroup: Boolean, isGroupMatching: Boolean, groups: Seq[Group], fulls: Seq[Full])
class StringModifierWithRegex(regex: String) {
private val regexCompiled = compile()
def test(text: String) : MatchResult = {
val matcher = regexCompiled.matcher(text)
fillResult(matcher)
}
def replaceAllFullMatches(text: String, replacement: String) : String = {
var newText = text
var nextMatch: Option[(Full, Option[Group])] = None
var startIndex = 0
do {
val matcher = regexCompiled.matcher(newText)
nextMatch = findNextMatch(matcher, startIndex)
if (nextMatch != None) {
newText = replaceText(newText, nextMatch.get._1.startPositionMatching, nextMatch.get._1.matching.length, replacement)
startIndex = nextMatch.get._1.startPositionMatching + replacement.length
}
} while (nextMatch != None)
newText
}
def replaceAllGroupMatches(text: String, replacement: String) : String = {
var newText = text
var nextMatch: Option[(Full, Option[Group])] = None
var startIndex = 0
do {
val matcher = regexCompiled.matcher(newText)
nextMatch = findNextMatch(matcher, startIndex)
if (nextMatch != None && nextMatch.get._2 != None) {
newText = replaceText(newText, nextMatch.get._2.get.startPositionMatching, nextMatch.get._2.get.matching.length, replacement)
startIndex = nextMatch.get._2.get.startPositionMatching + replacement.length
}
} while (nextMatch != None)
newText
}
private def compile() : Pattern = {
var result = Pattern.compile("")
try {
result = Pattern.compile(regex)
}
catch {
case ex: PatternSyntaxException => throw new RegexSyntaxException(ex.getMessage)
}
result
}
private def replaceText(text: String, startPosition: Int, length: Int, replacement: String) : String = {
val before = text.substring(0, startPosition)
val after = text.substring(startPosition + length)
before + replacement + after
}
private def fillResult(matcher: Matcher) : MatchResult = {
var fulls = Seq[Full]()
var groups = Seq[Group]()
val regexHasGroup = if (matcher.groupCount() == 0) false else true
def findNextAndFillResultRec(matcher: Matcher, matchN: Int) : MatchResult = {
val findNext = matcher.find()
if (matchN == 1 && ! findNext) {
MatchResult(isMatching = false, regexHasGroup, isGroupMatching = false, Seq[Group](), Seq[Full]())
}
else if (findNext) {
// calculate result
val fullStartPosition = matcher.start()
val fullMatch = matcher.group()
fulls = fulls:+Full(fullMatch, fullStartPosition)
var groupStartPosition = 0
breakable {
for (i <- 1 to matcher.groupCount()) {
groupStartPosition = matcher.start(i)
if (groupStartPosition != -1) {
groups = groups:+Group(matcher.group(i), groupStartPosition, i)
break
}
}
}
findNextAndFillResultRec(matcher, matchN + 1)
}
// NOT (matcher.find())
else {
val isMatching = if (fulls.size > 0) true else false
val isGroupMatching = if (groups.size > 0) true else false
MatchResult(isMatching, regexHasGroup, isGroupMatching, groups, fulls)
}
}
findNextAndFillResultRec(matcher, 1)
}
def findNextMatch(matcher: Matcher, startIndex: Int) : Option[(Full, Option[Group])] = {
var resultFull = Full("", 0)
var resultGroup: Option[Group] = None
val findNext = matcher.find(startIndex)
if (! findNext) {
None
}
else {
// calculate result
val fullStartPosition = matcher.start()
val fullMatch = matcher.group()
resultFull = Full(fullMatch, fullStartPosition)
var groupStartPosition = 0
breakable {
for (i <- 1 to matcher.groupCount()) {
groupStartPosition = matcher.start(i)
if (groupStartPosition != -1) {
resultGroup = Some(Group(matcher.group(i), groupStartPosition, i))
break
}
}
}
Some(resultFull, resultGroup)
}
}
}