Kotlin에서 정규표현식 사용하기

코틀린에서 정규표현식(Regex)을 사용하는 방법에 대해서 소개합니다. 코틀린의 Regex는 Java를 포함한 다른 언어들과 매우 유사합니다. 정규표현식의 기본 지식을 알고 있다는 가정 하에 샘플 코드를 소개합니다.

1. Regex

코틀린에서 정규표현식 Pattern은 Regex 클래스로 관리됩니다. 아래와 같이 Regex 객체를 생성할 때 패턴을 인자로 전달하고, 문자열이 해당 패턴과 일치하는지 검사할 수 있습니다.

fun main(args: Array<String>) {

    val str = "Welcome to codechacha"
    val regex = Regex(".*code")

    val result = regex.containsMatchIn(str)
    println("containsMatchIn: $result")
}

Output:

containsMatchIn: true

".*"는 문자 0개 이상을 의미합니다. 따라서 패턴 ".*code"는 code로 끝나는 문자열과 일치합니다. 패턴 ".code."는 code라는 문자 양 옆에 0개 이상의 문자들이 존재하는 문자열과 일치합니다.

1.1 Regex 객체 생성 방법

Regex 객체는

  1. Regex 생성자에 패턴을 인자로 전달하여 생성
  2. 패턴이 입력된 문자열 객체의 toRegex() 메소드로 생성

할 수 있습니다.

val regex1 = Regex(".*code")

val regex2 = ".*code".toRegex()

1.2 Regex Option

Regex의 생성자는 Regex(pattern, option)처럼 두번째 인자로 Option을 인자로 받습니다.

다음과 같이 Option이 적용된 Regex 객체를 생성할 수 있습니다. RegexOption.IGNORE_CASE는 대소문자를 구분하지 않고 패턴을 검사합니다.

fun main(args: Array<String>) {
    val str = "Welcome to codechacha"

    val regex1 = Regex(".*code")
    val regex2 = Regex(".*CODE")
    val regex3 = Regex(".*CODE", RegexOption.IGNORE_CASE)

    println("match(regex1): ${regex1.containsMatchIn(str)}")
    println("match(regex2): ${regex2.containsMatchIn(str)}")
    println("match(regex3): ${regex3.containsMatchIn(str)}")
}

Output:

match(regex1): true
match(regex2): false
match(regex3): true

더 다양한 RegexOption들은 Kotlinlang - RegexOption에서 확인하실 수 있습니다.

1.3 정규표현식 패턴

코틀린의 정규표현식에서 사용하는 패턴은 Java나 다른 언어와 동일합니다. 정규표현식의 의미에 대해서 잘 모르신다면 Java - 정규표현식(regex), 다양한 예제로 쉽게 이해하기를 참고해주세요.

2. 부분 패턴 매칭, 전체 패턴 매칭

아래 두개 함수는 패턴 일치 결과를 boolean 타입으로 리턴합니다.

  • Regex.containsMatchIn(): 부분적으로 패턴이 일치하면 true를 리턴합니다.
  • Regex.matches(): 모든 패턴이 일치하면 true를 리턴합니다.
fun main(args: Array<String>) {
    val str = "Welcome to codechacha"

    val regex1 = Regex(".*code")
    val regex2 = Regex(".*code.*")

    println("regex1(partial match): ${regex1.containsMatchIn(str)}")
    println("regex1(total match): ${regex1.matches(str)}")

    println("regex2(partial match): ${regex2.containsMatchIn(str)}")
    println("regex2(total match): ${regex2.matches(str)}")
}

Output:

regex1(partial match): true
regex1(total match): false
regex2(partial match): true
regex2(total match): true

3.1 전체 패턴 매칭 및 일치하는 문자열

Regex.matchEntire()는 문자열과 패턴이 일치하는지 검사하며, 그 결과를 MatchResult 객체로 리턴합니다. 패턴이 일치하지 않으면 null이 리턴됩니다.

MatchResult는 일치 여부만 boolean 타입으로 리턴하는 것이 아닙니다. 아래와 같이 일치하는 문자열에 대한 자세한 정보를 제공합니다.

  • MatchResult.value : 일치하는 문자열입니다.
  • MatchResult.groupValues : 그룹과 일치하는 문자열들에 대한 리스트입니다.
  • MatchResult.groupValues[index].value : 특정 그룹의 Index를 입력하여 일치하는 value에 접근할 수 있습니다. Index 0은 전체 패턴에 일치하는 문자열입니다. Index 1은 첫번째 그룹에 일치하는 문자열입니다.
fun main(args: Array<String>) {
    val str = "abcd"
    val regex = Regex("abc([de]+)")

    val matchResult: MatchResult? = regex.matchEntire(str)
    println("match value: ${matchResult?.value}")
    println("match groupValues: ${matchResult?.groupValues}")
    println("match group[1].value: ${matchResult!!.groups[1]!!.value}")
}

Output:

match value: abcd
match groupValues: [abcd, d]
match group[1].value: d

3.2 부분 패턴 매칭 및 일치하는 문자열

Regex.find()는 문자열과 패턴이 완전히 일치하지 않는, 부분적으로만 일치하는 문자열을 찾아줍니다. 일치하는 문자열이 있으면 MatchResult를 리턴하고 그렇지 않으면 null을 리턴합니다.

fun main(args: Array<String>) {
    val str = "abcda"
    val regex = Regex("abc[de]+")

    val matchResult: MatchResult? = regex.find(str)
    println("match value: ${matchResult?.value}")
}

Output:

match value: abcd

3.3 Group 패턴 예제

그룹은 (pattern) 형태를 의미합니다. 관심있는 영역을 그룹으로 지정할 수 있으며, MatchResult는 그룹과 일치하는 문자열에 대한 정보를 제공합니다.

MatchResult.groupValues는 일치하는 문자열들에 대한 정보입니다.

  • index 0: 전체 패턴과 일치하는 문자열입니다.
  • index 1: 첫번째 그룹 (apple|kiwi)와 일치하는 문자열입니다.
  • index 2: 두번째 그룹 (banana|blueberry)와 일치하는 문자열입니다.
fun main(args: Array<String>) {
    val str1 = "apple likes banana"
    val str2 = "kiwi likes blueberry"
    val regex = Regex("(apple|kiwi) likes (banana|blueberry)")

    val matchResult1: MatchResult? = regex.matchEntire(str1)
    println("matchResult1: ${matchResult1?.groupValues}")

    val matchResult2: MatchResult? = regex.matchEntire(str2)
    println("matchResult2: ${matchResult2?.groupValues}")
}

Output:

matchResult1: [apple likes banana, apple, banana]
matchResult2: [kiwi likes blueberry, kiwi, blueberry]

4. 부분적으로 일치하는 모든 패턴 찾기

문자열에서 어떤 패턴과 부분적으로 일치하는 모든 문자열들을 찾을 때는 Regex.findAll() 함수를 사용합니다.

아래 처럼, 문자열에서 패턴과 부분적으로 일치하는 문자열들에 대한 정보를 Sequence<MatchResult>로 리턴합니다. Iteration을 통해 접근할 수 있습니다.

fun main(args: Array<String>){
    val str = "abcd abce"
    val regex = Regex("abc([de]+)")

    val matchResults: Sequence<MatchResult> = regex.findAll(str)
    matchResults?.forEach {
        println("match value: ${it.value}")
    }
}

Output:

match value: abcd
match value: abce

5. Replace

다음 함수들은 패턴과 일치하는 문자열을 다른 문자열로 교체합니다.

  • replace() : 패턴과 일치하는 모든 문자열을 교체
  • replaceFirst() : 패턴과 일치하는 첫번째 문자열만 교체
fun main(args: Array<String>) {
    val str = "abcda abcef"
    val regex = Regex("abc([de]+)")

    val replaceAll = regex.replace(str, "ABC")
    println(replaceAll)

    val replaceFirst = regex.replaceFirst(str, "ABC")
    println(replaceFirst)
}

Output:

ABCa ABCf
ABCa abcef

6. Split

Regex.split()은 패턴과 일치하는 문자열을 기준으로 분리하여 리스트로 리턴합니다.

fun main(args: Array<String>) {
    val str = "a b c d e f"
    val regex = Regex("\\s")

    val splitList = regex.split(str)
    println(splitList)
}

Output:

[a, b, c, d, e, f]

References

Loading script...
codechachaCopyright ©2019 codechacha