go - string, rune

2 분 소요

go - string, rune

go - string - summary

  • string type에 대해서 len() 함수를 적용하면 문자의 길이가 나오는 것이 아니라, 배정된 메모리의 크기가 나옵니다. 예를 들어, “한글”, “AB” 모두 우리는 2글자로 생각하지만 UTF-8로 문자를 표현했을 때 사용되는 메모리의 크기가 다릅니다. go의 기본 문자코드는 UTF-8 입니다.
  • []rune으로 변환하면 각 문자별로 읽는 것이 가능합니다. runeint32의 별칭으로 4 byte를 차지합니다. c 언어에서 char[]와 동일하다고 생각하면 됩니다 대신 한 문자의 크기가 훨씬 크고 UTF-8을 기본으로 하는.
  • +, >, < 과 같은 기본연산이 지원됩니다.
  • 문자열은 immutable하기 때문에, 문자열 간 연산을 실행하는 경우 새로운 메모리를 확보하고 해당 값을 넣는 형태로 진행되기 때문에 연산 비용이 큽니다. 따라서, 반복적으로 연산이 필요한 경우에는 []rune를 사용하건 Builder를 사용하는 것이 좋아 보입니다.

go - string - code

  • go 에서 string을 어떻게 다루는지에 대해서 간략하게 정리해 봅니다.
  • golang에서는 표준 문자 코드로 UTF-8을 사용합니다. 따라서, 각 문자별로 배정되는 메모리의 크기가 달라지죠.
  • 한글의 경우는 2 ~ 3 byte, 영문의 경우는 1 byte가 사용되기에 우리가 생각하는 음절과 다르게 카운트 됩니다.
  • string에 대해서 index 형태로 접근하게 되면 각 byte에 존재하는 값을 그대로 출력하기 때문에, 한글에 대해서는 우리가 원하는 대로 문자가 출력되지 않습니다.
package main

import "fmt"

func main() {

    var s_en string = "Hello, Go"
    var s_ko string = "안녕하세요, Go"

    /*
    golang에서 len 함수를 String에 사용하면
    해당 문자열에 배정된 메모리의 크기가 리턴됩니다.
    golang에서는 표준 문자 코드로 UTF-8을 사용합니다.
    UTF-8에서는 다음으로 바이트를 사용하죠.
    영문, 숫자, 특수문자: 1 byte
    한글: 2 ~ 3 bytes
    */
    fmt.Println("== Output")
    fmt.Println(s_en, len(s_en));
    fmt.Println(s_ko, len(s_ko));
    /*
    == Output
    Hello, Go 9
    안녕하세요, Go 19
    */

    fmt.Println("== Output")
    for i := 0; i < len(s_ko); i++ {
        fmt.Printf("i: %d - %d  - %c\n", i, s_ko[i], s_ko[i])
    }
    fmt.Println()

    /*
    == Output
    i: 0 - 236  - ì
    i: 1 - 149  - •
    i: 2 - 136  - ˆ
    i: 3 - 235  - ë
    i: 4 - 133
    i: 5 - 149  - •
    i: 6 - 237  - í
    i: 7 - 149  - •
    i: 8 - 152  - ˜
    i: 9 - 236  - ì
    i: 10 - 132  - „
    i: 11 - 184  - ¸
    i: 12 - 236  - ì
    i: 13 - 154  - š
    i: 14 - 148  - ”
    i: 15 - 44  - ,
    i: 16 - 32  -
    i: 17 - 71  - G
    i: 18 - 111  - o
    */



    /*
    메모리 크기가 아닌 길이를 알고 싶다면
    []rune type으로 변환한 다음 확인해야 합니다.
    rune은 1 type당 4 byte를 차지합니다.
    */

    var rune_en []rune = []rune(s_en)
    var rune_ko []rune = []rune(s_ko)

    fmt.Println(rune_en, "len: ", len(rune_en))
    fmt.Println(rune_ko, "len: ", len(rune_ko))

    /*
    [72 101 108 108 111 44 32 71 111] len:  9
    [50504 45397 54616 49464 50836 44 32 71 111] len:  9
    */
}
  • 따라서, 이 경우에는 []rune로 변환(casting)한 다음 처리해주면 됩니다.
  • rune은 c에서의 char과 동일하다고 생각하면 됩니다. 단, char의 경우 1byte인데 반해 rune의 경우 4 byte를 차지하기 때문에 훨씬 많은 문자를 표현할 수 있습니다.
package main

import "fmt"

func main() {

    var s_ko string = "안녕하세요, Go"
    /*
    메모리 크기가 아닌 길이를 알고 싶다면
    []rune type으로 변환한 다음 확인해야 합니다.
    rune은 1 type당 4 byte를 차지합니다.
    */
    var rune_ko []rune = []rune(s_ko)

    fmt.Println("== Output")
    for i := 0; i < len(rune_ko); i++ {
        fmt.Printf("i: %d - %c \n", i, rune_ko[i])
    }
    /*
    == Output
    i: 0 - 안
    i: 1 - 녕
    i: 2 - 하
    i: 3 - 세
    i: 4 - 요
    i: 5 - ,
    i: 6 -
    i: 7 - G
    i: 8 - o
    */
}

Wrap-up

  • python의 경우 len을 사용하면 바로 길이가 나오는데, golang에서는 메모리의 길이가 나오는 것이 조금 낯서네요. 뭐 이유가 있겠죠 호호.

댓글남기기