refactor: more kotlin style
This commit is contained in:
parent
fe8dc05937
commit
ac1d5da01b
1 changed files with 71 additions and 56 deletions
|
@ -30,7 +30,7 @@ class MatchResult(val available: AvailableState) {
|
||||||
// 재귀 하향 분석기.
|
// 재귀 하향 분석기.
|
||||||
interface RegexItem {
|
interface RegexItem {
|
||||||
override fun toString(): String
|
override fun toString(): String
|
||||||
fun findMatch(item: String): AvailableState
|
fun findMatch(str: String): AvailableState
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RegexItem.match(item: String): MatchResult {
|
fun RegexItem.match(item: String): MatchResult {
|
||||||
|
@ -40,8 +40,8 @@ fun RegexItem.match(item: String): MatchResult {
|
||||||
|
|
||||||
class AndThenItem(val left: RegexItem, val right: RegexItem) : RegexItem {
|
class AndThenItem(val left: RegexItem, val right: RegexItem) : RegexItem {
|
||||||
override fun toString(): String = "${left}${right}"
|
override fun toString(): String = "${left}${right}"
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState {
|
||||||
val leftMatch = left.findMatch(item)
|
val leftMatch = left.findMatch(str)
|
||||||
if (leftMatch.isEmpty) {
|
if (leftMatch.isEmpty) {
|
||||||
return AvailableState() // If left match fails, return empty sequence
|
return AvailableState() // If left match fails, return empty sequence
|
||||||
}
|
}
|
||||||
|
@ -67,67 +67,83 @@ class AndThenItem(val left: RegexItem, val right: RegexItem) : RegexItem {
|
||||||
|
|
||||||
class CharItem(val value: String) : RegexItem {
|
class CharItem(val value: String) : RegexItem {
|
||||||
override fun toString(): String = value
|
override fun toString(): String = value
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState {
|
||||||
return if (item.isNotEmpty() && item[0].toString() == value) {
|
return when {
|
||||||
// If the first character matches, return a successful match
|
// 첫번째 문자가 value와 일치하는지 확인
|
||||||
AvailableState(sequenceOf(State(value, item.substring(1))))
|
str.isNotEmpty() && str[0].toString() == value -> {
|
||||||
} else {
|
AvailableState(sequenceOf(State(value, str.substring(1))))
|
||||||
// If it doesn't match, return an empty sequence
|
}
|
||||||
AvailableState()
|
else -> AvailableState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun matchMany(
|
||||||
|
str: String,
|
||||||
|
item: RegexItem,
|
||||||
|
): Sequence<State> {
|
||||||
|
// 욕심쟁이 매칭을 위한 헬퍼 함수
|
||||||
|
return item.findMatch(str).seq.flatMap { state ->
|
||||||
|
if (state.remaining.isEmpty()) {
|
||||||
|
sequenceOf(state) // If remaining is empty, return the matched state
|
||||||
|
} else {
|
||||||
|
// Otherwise, continue matching with the remaining string
|
||||||
|
matchMany(state.remaining, item).map { nextState ->
|
||||||
|
State(state.matched + nextState.matched, nextState.remaining)
|
||||||
|
} + sequenceOf(state) // Include the current state as well
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fun matchMany(str: String, item: RegexItem): Sequence<State> = sequence {
|
||||||
|
// val stack = mutableListOf(item.findMatch(str).seq)
|
||||||
|
// while (stack.isNotEmpty()) {
|
||||||
|
// val current = stack.removeAt(stack.lastIndex)
|
||||||
|
// for (state in current) {
|
||||||
|
// yield(state) // Yield the current state
|
||||||
|
// if (state.remaining.isNotEmpty()) {
|
||||||
|
// // If there is remaining string, continue matching
|
||||||
|
// stack.add(item.findMatch(state.remaining).seq.map { nextState ->
|
||||||
|
// State(state.matched + nextState.matched, nextState.remaining)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
class PlusItem(val item: RegexItem) : RegexItem {
|
class PlusItem(val item: RegexItem) : RegexItem {
|
||||||
override fun toString(): String = "${item}+"
|
override fun toString(): String = "${item}+"
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState {
|
||||||
// 욕심쟁이 매칭해야 함. 그래서 가능한 한 많이 매칭해야 함.
|
return AvailableState(matchMany(str, item))
|
||||||
val results = mutableListOf<State>()
|
|
||||||
var remaining = item
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
val matchResult = this.item.findMatch(remaining)
|
|
||||||
if (matchResult.isEmpty) {
|
|
||||||
break // No more matches possible
|
|
||||||
}
|
|
||||||
matchResult.forEach { state -> results.add(State(state.matched, state.remaining)) }
|
|
||||||
remaining = matchResult.first().remaining // Update remaining string
|
|
||||||
}
|
|
||||||
|
|
||||||
return AvailableState(results.reversed().asSequence()) // Return all successful matches
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StarItem(val item: RegexItem) : RegexItem {
|
class StarItem(val item: RegexItem) : RegexItem {
|
||||||
override fun toString(): String = "${item}*"
|
override fun toString(): String = "${item}*"
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState {
|
||||||
// 욕심쟁이 매칭해야 함. 그래서 가능한 한 많이 매칭해야 함.
|
// *는 0개 이상의 매칭을 의미하므로, 먼저 시도해보고 실패하면 빈 시퀀스를 반환
|
||||||
val results = mutableListOf<State>(State("", item)) // Start with an empty match
|
val matchResult = this.item.findMatch(str)
|
||||||
var remaining = item
|
|
||||||
while (true) {
|
|
||||||
val matchResult = this.item.findMatch(remaining)
|
|
||||||
if (matchResult.isEmpty) {
|
if (matchResult.isEmpty) {
|
||||||
break // No more matches possible
|
// If the item does not match, return an empty sequence
|
||||||
|
return AvailableState(sequenceOf(State("", str)))
|
||||||
}
|
}
|
||||||
matchResult.forEach { state -> results.add(State(state.matched, state.remaining)) }
|
// If it matches, return the successful match and continue matching with the remaining string
|
||||||
remaining = matchResult.first().remaining // Update remaining string
|
return AvailableState(
|
||||||
if (remaining.isEmpty()) {
|
matchResult.flatMap { state ->
|
||||||
break // If remaining string is empty, stop matching
|
sequenceOf(state) + matchMany(state.remaining, this.item)
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
// 반드시 reverse해서 가장 긴 매칭부터 시작해야 함.
|
|
||||||
return AvailableState(results.reversed().asSequence()) // Return all successful matches
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class QuestionItem(val item: RegexItem) : RegexItem {
|
class QuestionItem(val item: RegexItem) : RegexItem {
|
||||||
override fun toString(): String = "${item}?"
|
override fun toString(): String = "${item}?"
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState {
|
||||||
// ?는 0개 또는 1개 매칭을 의미하므로, 먼저 시도해보고 실패하면 빈 시퀀스를 반환
|
// ?는 0개 또는 1개 매칭을 의미하므로, 먼저 시도해보고 실패하면 빈 시퀀스를 반환
|
||||||
val matchResult = this.item.findMatch(item)
|
val matchResult = this.item.findMatch(str)
|
||||||
if (matchResult.isEmpty) {
|
if (matchResult.isEmpty) {
|
||||||
// If the item does not match, return an empty sequence
|
// If the item does not match, return an empty sequence
|
||||||
return AvailableState(sequenceOf(State("", item)))
|
return AvailableState(sequenceOf(State("", str)))
|
||||||
}
|
}
|
||||||
// If it matches, return the successful match
|
// If it matches, return the successful match
|
||||||
return AvailableState(matchResult.map { State(it.matched, it.remaining) })
|
return AvailableState(matchResult.map { State(it.matched, it.remaining) })
|
||||||
|
@ -136,25 +152,24 @@ class QuestionItem(val item: RegexItem) : RegexItem {
|
||||||
|
|
||||||
class DotItem : RegexItem {
|
class DotItem : RegexItem {
|
||||||
override fun toString(): String = "."
|
override fun toString(): String = "."
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState =
|
||||||
// .은 임의의 한 문자와 매칭되므로, 첫 문자가 존재하면 매칭 성공
|
// .은 임의의 한 문자와 매칭되므로, 첫 문자가 존재하면 매칭 성공
|
||||||
return if (item.isNotEmpty()) {
|
when {
|
||||||
AvailableState(sequenceOf(State(item[0].toString(), item.substring(1))))
|
str.isNotEmpty() ->
|
||||||
} else {
|
AvailableState(sequenceOf(State(str[0].toString(), str.substring(1))))
|
||||||
AvailableState() // 빈 문자열에 대해서는 매칭 실패
|
else -> AvailableState() // 빈 문자열에 대해서는 매칭 실패
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlternationItem(val left: RegexItem, val right: RegexItem) : RegexItem {
|
class AlternationItem(val left: RegexItem, val right: RegexItem) : RegexItem {
|
||||||
override fun toString(): String = "(${left}|${right})"
|
override fun toString(): String = "(${left}|${right})"
|
||||||
override fun findMatch(item: String): AvailableState {
|
override fun findMatch(str: String): AvailableState {
|
||||||
// Alternation은 왼쪽 또는 오른쪽 항목 중 하나와 매칭되므로, 각각 시도해보고 성공하는 경우를 반환
|
// Alternation은 왼쪽 또는 오른쪽 항목 중 하나와 매칭되므로, 각각 시도해보고 성공하는 경우를 반환
|
||||||
val leftMatch = left.findMatch(item)
|
val leftMatch = left.findMatch(str)
|
||||||
val rightMatch = right.findMatch(item)
|
val rightMatch = right.findMatch(str)
|
||||||
|
|
||||||
return AvailableState(
|
return AvailableState(
|
||||||
(leftMatch + rightMatch).asSequence() // 두 매칭 결과를 합쳐서 반환
|
(leftMatch + rightMatch) // 두 매칭 결과를 합쳐서 반환
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue