feat: implement matchAll function in RegexItem and update tests for match results

This commit is contained in:
monoid 2025-06-29 15:28:30 +09:00
parent fb1cf96fed
commit 34052d1ea2
2 changed files with 48 additions and 24 deletions

View file

@ -17,22 +17,6 @@ data class AvailableState(val seq: Sequence<State> = emptySequence()) : Sequence
get() = seq.none() get() = seq.none()
} }
class MatchResult(val available: AvailableState) {
val isSuccess: Boolean
get() = !this.available.isEmpty
val isFailure: Boolean
get() = this.available.isEmpty
override fun toString(): String {
return if (isSuccess) {
"MatchResult(success)"
} else {
"MatchResult(failure)"
}
}
}
// 재귀 하향 분석기. // 재귀 하향 분석기.
interface RegexItem { interface RegexItem {
@ -40,14 +24,41 @@ interface RegexItem {
fun findMatch(str: String, position: Int = 0): AvailableState fun findMatch(str: String, position: Int = 0): AvailableState
} }
fun RegexItem.match(item: String): MatchResult { fun RegexItem.matchAll(item: String): Sequence<State> {
// 기본 매칭 함수. AvailableState를 MatchResult로 변환 return sequence {
return MatchResult(this.findMatch(item, 0)) var position = 0;
// 문자열의 끝까지 반복합니다. 비어있어도 한번은 시도합니다.
while (position <= item.length) {
// findMatch 메서드를 호출하여 매칭을 시도합니다.
val matchResult = findMatch(item, position)
if (matchResult.isEmpty) {
// 매칭이 실패하면 position을 증가시키고 다시 시도합니다.
if (position < item.length) {
position++
continue
} else {
// position이 문자열의 끝에 도달했지만 매칭이 실패한 경우 종료
break
}
} else {
// 매칭이 성공하면 MatchResult를 생성하여 반환합니다.
val state = matchResult.seq.first()
yield(state)
// 다음 위치로 이동합니다.
position = state.endIndex
}
}
}
}
fun RegexItem.match(item: String): State? {
// matchAll 에서 첫 번째 매칭 결과를 반환합니다.
return this.matchAll(item).firstOrNull()
} }
fun RegexItem.test(item: String): Boolean { fun RegexItem.test(item: String): Boolean {
// 매칭 결과가 성공인지 확인하는 헬퍼 함수 // 매칭 결과가 성공인지 확인하는 헬퍼 함수
return this.match(item).isSuccess return this.match(item) != null
} }
class AndThenItem(val left: RegexItem, val right: RegexItem) : RegexItem { class AndThenItem(val left: RegexItem, val right: RegexItem) : RegexItem {

View file

@ -151,9 +151,22 @@ class ParserTest {
val result = compileRegex(input) val result = compileRegex(input)
assertEquals("(a)(b)", result.toString()) assertEquals("(a)(b)", result.toString())
val matchResult = result.match("ab") val matchResult = result.match("ab")
assert(matchResult.isSuccess) assert(matchResult != null) { "Expected match result to be non-null" }
val captures = matchResult.available.first(); if (matchResult == null) return
assertEquals("a", captures.captures.get("0")) assertEquals("ab", matchResult.matched)
assertEquals("b", captures.captures.get("1")) assertEquals(2, matchResult.captures.size)
assertEquals("a", matchResult.captures.get("0"))
assertEquals("b", matchResult.captures.get("1"))
}
@Test
fun testMatchAll() {
val input = "a+"
val regex = compileRegex(input)
val matches = regex.matchAll("aaabaaa")
val results = matches.toList()
println("Matches found: ${results}")
// assertEquals(2, results.size)
assertEquals("aaa", results[0].matched)
assertEquals("aaa", results[1].matched)
} }
} }