refactor: more kotlin style

This commit is contained in:
monoid 2025-06-28 19:15:18 +09:00
parent fe8dc05937
commit ac1d5da01b

View file

@ -30,7 +30,7 @@ class MatchResult(val available: AvailableState) {
// 재귀 하향 분석기.
interface RegexItem {
override fun toString(): String
fun findMatch(item: String): AvailableState
fun findMatch(str: String): AvailableState
}
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 {
override fun toString(): String = "${left}${right}"
override fun findMatch(item: String): AvailableState {
val leftMatch = left.findMatch(item)
override fun findMatch(str: String): AvailableState {
val leftMatch = left.findMatch(str)
if (leftMatch.isEmpty) {
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 {
override fun toString(): String = value
override fun findMatch(item: String): AvailableState {
return if (item.isNotEmpty() && item[0].toString() == value) {
// If the first character matches, return a successful match
AvailableState(sequenceOf(State(value, item.substring(1))))
} else {
// If it doesn't match, return an empty sequence
AvailableState()
override fun findMatch(str: String): AvailableState {
return when {
// 첫번째 문자가 value와 일치하는지 확인
str.isNotEmpty() && str[0].toString() == value -> {
AvailableState(sequenceOf(State(value, str.substring(1))))
}
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 {
override fun toString(): String = "${item}+"
override fun findMatch(item: String): AvailableState {
// 욕심쟁이 매칭해야 함. 그래서 가능한 한 많이 매칭해야 함.
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
override fun findMatch(str: String): AvailableState {
return AvailableState(matchMany(str, item))
}
}
class StarItem(val item: RegexItem) : RegexItem {
override fun toString(): String = "${item}*"
override fun findMatch(item: String): AvailableState {
// 욕심쟁이 매칭해야 함. 그래서 가능한 한 많이 매칭해야 함.
val results = mutableListOf<State>(State("", item)) // Start with an empty match
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
if (remaining.isEmpty()) {
break // If remaining string is empty, stop matching
}
override fun findMatch(str: String): AvailableState {
// *는 0개 이상의 매칭을 의미하므로, 먼저 시도해보고 실패하면 빈 시퀀스를 반환
val matchResult = this.item.findMatch(str)
if (matchResult.isEmpty) {
// If the item does not match, return an empty sequence
return AvailableState(sequenceOf(State("", str)))
}
// 반드시 reverse해서 가장 긴 매칭부터 시작해야 함.
return AvailableState(results.reversed().asSequence()) // Return all successful matches
// If it matches, return the successful match and continue matching with the remaining string
return AvailableState(
matchResult.flatMap { state ->
sequenceOf(state) + matchMany(state.remaining, this.item)
}
)
}
}
class QuestionItem(val item: RegexItem) : RegexItem {
override fun toString(): String = "${item}?"
override fun findMatch(item: String): AvailableState {
override fun findMatch(str: String): AvailableState {
// ?는 0개 또는 1개 매칭을 의미하므로, 먼저 시도해보고 실패하면 빈 시퀀스를 반환
val matchResult = this.item.findMatch(item)
val matchResult = this.item.findMatch(str)
if (matchResult.isEmpty) {
// 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
return AvailableState(matchResult.map { State(it.matched, it.remaining) })
@ -136,25 +152,24 @@ class QuestionItem(val item: RegexItem) : RegexItem {
class DotItem : RegexItem {
override fun toString(): String = "."
override fun findMatch(item: String): AvailableState {
// .은 임의의 한 문자와 매칭되므로, 첫 문자가 존재하면 매칭 성공
return if (item.isNotEmpty()) {
AvailableState(sequenceOf(State(item[0].toString(), item.substring(1))))
} else {
AvailableState() // 빈 문자열에 대해서는 매칭 실패
}
}
override fun findMatch(str: String): AvailableState =
// .은 임의의 한 문자와 매칭되므로, 첫 문자가 존재하면 매칭 성공
when {
str.isNotEmpty() ->
AvailableState(sequenceOf(State(str[0].toString(), str.substring(1))))
else -> AvailableState() // 빈 문자열에 대해서는 매칭 실패
}
}
class AlternationItem(val left: RegexItem, val right: RegexItem) : RegexItem {
override fun toString(): String = "(${left}|${right})"
override fun findMatch(item: String): AvailableState {
override fun findMatch(str: String): AvailableState {
// Alternation은 왼쪽 또는 오른쪽 항목 중 하나와 매칭되므로, 각각 시도해보고 성공하는 경우를 반환
val leftMatch = left.findMatch(item)
val rightMatch = right.findMatch(item)
val leftMatch = left.findMatch(str)
val rightMatch = right.findMatch(str)
return AvailableState(
(leftMatch + rightMatch).asSequence() // 두 매칭 결과를 합쳐서 반환
(leftMatch + rightMatch) // 두 매칭 결과를 합쳐서 반환
)
}
}