go - string, rune
go - string - summary
string
type에 대해서 len()
함수를 적용하면 문자의 길이가 나오는 것이 아니라, 배정된 메모리의 크기가 나옵니다. 예를 들어, “한글”, “AB” 모두 우리는 2글자로 생각하지만 UTF-8로 문자를 표현했을 때 사용되는 메모리의 크기가 다릅니다. go의 기본 문자코드는 UTF-8 입니다.
[]rune
으로 변환하면 각 문자별로 읽는 것이 가능합니다. rune
은 int32
의 별칭으로 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에서는 메모리의 길이가 나오는 것이 조금 낯서네요. 뭐 이유가 있겠죠 호호.
댓글남기기