개요
해당 포스팅에서는 Rune 타입에 대해서 알아보고 왜 Golang에서는 해당 타입을 사용하게 되었는지에 대해서 정리합니다.
Rune 타입이란
rune
타입은 Golang에서 UTF-8
문자 코드를 나타내기 위해 사용되는 정수 타입입니다. 실제로 rune
은 int32
의 별칭(alias)으로, 유니코드 코드 포인트
를 담을 수 있습니다. 이를 통해서 문자들을 메모리에 저장하고 처리할 수 있는 방법을 제공합니다.
유니코드 코드포인트란?
우선 유니코드에 대해서 자세하게 알고 싶다면 기존에 썼던 블로그 글을 한번 참고해보면 좋습니다.
코드 포인트란 유니코드의 구성요소 중 하나이고 16진수로 표현되며 U+로 시작됩니다.
한글에 대해서 코드 포인트를 찾고 싶으면 해당 사이트 표에서 찾아보실 수 있습니다.
https://jjeong.tistory.com/696
Rune 타입의 도입배경
Go 언어가 처음 설계될 때, 개발자들은 다양한 언어와 문자 체계를 사용하는 전 세계의 프로그래머들을 염두에 두고 설계를 하였고 유니코드의 전 범위를 효과적으로 지원하기 위해서 Rune
타입이 도입되었습니다.
String과 Rune 타입의 관계
Golang에서 string
타입은 UTF-8 인코딩된 바이트 시퀀스로 구성됩니다. 이는 string
내의 각 문자가 고정된 길이를 가지지 않고, 1바이트에서 4바이트까지 다양할 수 있음을 의미합니다. 따라서, string
을 구성하는 실제 문자들에 접근하기 위해서는 UTF-8 인코딩을 디코딩 하여 각 문자의 유니코드 코드 포인트를 확인해야 합니다. 이 과정에서 rune
타입이 사용됩니다.
String의 Bytes 값을 출력
1func main() {
2 // UTF-8로 인코딩된 문자열
3 str := "안녕, World"
4
5 // 문자열의 바이트를 순회하며 출력
6 for i := 0; i < len(str); i++ {
7 fmt.Printf("%d번째 바이트: 0x%X\n", i, str[i])
8 }
9}
10
11// 0번째 바이트: 0xEC
12// 1번째 바이트: 0x95
13// 2번째 바이트: 0x88
14// 3번째 바이트: 0xEB
15// 4번째 바이트: 0x85
16// 5번째 바이트: 0x95
17// 6번째 바이트: 0x2C
18// 7번째 바이트: 0x20
19// 8번째 바이트: 0x57
20// 9번째 바이트: 0x6F
21// 10번째 바이트: 0x72
22// 11번째 바이트: 0x6C
23// 12번째 바이트: 0x64
위에 코드를 보면 문자열을 순회하면서 출력해 보면 16진수 바이트 값이 출력되는 걸 확인하실 수 있습니다. 해당 바이트를 분석해 보면 초반에 찍힌 0xEC 0x95 0x88
에 대해서 “안” 이라는 문자의 UTF-8 인코딩 값을 확인해 보면 동일하게 보이시는 것을 확인하실 수 있습니다.
https://www.compart.com/en/unicode/U+C548
String을 Rune으로 변환 후 출력
1package main
2
3import "fmt"
4
5func main() {
6 // UTF-8로 인코딩된 문자열
7 str := "안녕, World"
8
9 // 문자열을 rune 슬라이스로 변환
10 runes := []rune(str)
11
12 for i, r := range runes {
13 fmt.Printf("%d번째 rune: %c (유니코드: U+%04X)\n", i, r, r)
14 }
15}
16
17// 0번째 rune: 안 (유니코드: U+C548)
18// 1번째 rune: 녕 (유니코드: U+B155)
19// 2번째 rune: , (유니코드: U+002C)
20// 3번째 rune: (유니코드: U+0020)
21// 4번째 rune: W (유니코드: U+0057)
22// 5번째 rune: o (유니코드: U+006F)
23// 6번째 rune: r (유니코드: U+0072)
24// 7번째 rune: l (유니코드: U+006C)
25// 8번째 rune: d (유니코드: U+0064)
해당 코드는 string을 rune으로 변경한 뒤 for 문을 돌면서 해당 rune의 코드 포인트를 출력하는 예제입니다. UTF-8 기반의 string 값을 rune slice 값으로 변환하고 출력되는 값에서는 유니코드 음절 단위로 저장되고 출력되는 것을 확인하실 수 있습니다.
다국어 용어 조작 예시
Golang에서는 Rune을 통해서 다국어들에 대한 문자열 처리를 손쉽게 처리할 수 있습니다. 예를 들어서 다국어가 섞여있는 문자열을 역순으로 출력하는 예제를 작성해 보겠습니다.
1package main
2
3import "fmt"
4
5func main() {
6 // 다국어 문자열
7 str := "안녕, World"
8
9 // 문자열을 rune 슬라이스로 변환
10 runes := []rune(str)
11
12 // 문자열을 역순으로 출력
13 fmt.Print("역순 문자열: ")
14 for i := len(runes) - 1; i >= 0; i-- {
15 fmt.Print(string(runes[i]))
16 }
17}
18
19// dlroW ,녕안
문자열을 rune으로 변환했기 때문에 역순 출력할 때 바이트 관련 별도의 처리 없이 손쉽게 처리할 수 있습니다. 만약에 rune이 없다면 역순으로 정렬된 바이트들을 언어별로 하나씩 검증해가면서 역순으로 출력했어야 합니다.
정리
해당 포스팅을 통해서 Rune이란 무엇이고 Golang은 어떤 이유로 Rune을 도입하게 되었는지에 대해서 정리를 해보았습니다. Rune은 유니코드의 코드 포인트를 가리키는 int32 기반의 데이터 타입이고 UTF-8 문자열과 Rune 사이의 이러한 관계는 Go에서 다양한 언어로 된 문자열들을 다루는데 강력한 이점을 제공합니다.