on
rune ?
Go에서 String은 byte 들의 읽기전용 배열이라고 할 수 있다. 유니코드 표준은 값 하나에 의해 표현되는 항목에 대해 “코드포인트” 라는 용어를 사용한다. 16진수 2318값을 가진 코드 포인트 U+2318은 ⌘ 를 나타낸다. 좀 더 무난한 예제로, 유니코드 코드 포인트 U+0061은 소문자 ‘a’를 나타낸다.
일반적으로 글자는 여러 개 코드포인트의 조합으로 나타낼 수 있고, 따라서 이를 utf-8 인코딩한 바이트 배열로 나타낼 수 있다. 코드 포인트는 살짝 길기 때문에, Go에서는 rune이라는 용어를 사용한다. rune은 코드 포인트와 정확히 같은 개념이다. Go는 rune을 int32의 alias로 사용하여 프로그램이 이 integer 값이 특정 code point를 나타내는것이 명확하도록 하였다. 보통 character 상수라고 생각되는 것은 go 에서 rune 상수라고 불린다.
‘⌘’
이 symbol의 타입과 값도 0x2318 integer 값을 가진 rune 타입이다.
package main
import (
"fmt"
)
func main() {
var test string
test = ""
fmt.Println("first test example:", len(test))
test = "a"
fmt.Println("second test example:", len(test))
test = "가"
fmt.Println("third test example:", len(test))
// first test example: 3
// second test example: 1
// third test example: 3
}
string 타입의 변수 test가 있다고 했을때, 1 바이트로 표현할 수 있는 알파벳과 다르게 나머지 글자 들은 len을 출력했을때 일반적으로 예상하는 그 길이가 출력되지 않는다. 이는 각 character(알파벳 이외의 문자)가 1바이트 이상의 바이트로 표현되고, 이에 len을 출력했을때 바이트수가 출력되기 때문이다.
대신, 모든 글자(character)는 unicode의 특정 code point로 나타낼 수 있다. 이를 이용해서 한 글자당 한 rune 타입으로 바꿔서 string을 rune slice로 변환한다고 생각해보면, len을 출력했을때 원하는 출력을 얻을 수 있다. 즉, 아래와 같이 하면
runeTest := []rune(test)
fmt.Println("rune test example:", len(runeTest))
// rune test example: 1
생각한 결과를 얻을 수 있다.
Update!!
추가!
utf8 라이브러리의 아래 함수를 이용하면 utf8로 인코딩된 문자열 값의 길이를 알수있다. 예를 들어 한글은 1글자당 3바이트를 이용해 저장하므로, 그냥 len을 이용해 출력하면 3이지만 RuneCountInString함수를 이용하면 실제길이인 1을 구할수있다.
var han string = "한"
fmt.Println(len(han)) // 3
utf8.RuneCountInString(han) // 1