소개
이전 섹션에서는 자주 사용되는 숫자 타입에 대해 알아보았습니다. 이번 섹션에서는 Go 언어의 문자 타입에 대해 학습하겠습니다.
학습 포인트:
- ASCII 인코딩
- UTF-8 인코딩
- Unicode 문자 집합
byterune
이전 섹션에서는 자주 사용되는 숫자 타입에 대해 알아보았습니다. 이번 섹션에서는 Go 언어의 문자 타입에 대해 학습하겠습니다.
학습 포인트:
byterune컴퓨터 초기 시절에는 ASCII(American Standard Code for Information Interchange) 인코딩 형식이 사용되었습니다. 이는 7 비트를 사용하여 문자를 표현하며, 총 128(2^7) 개의 문자를 나타낼 수 있었습니다. 0 번부터 31 번, 그리고 127 번 비트는 화면에 표시되지 않는 제어 문자를 나타내고, 32 번부터 126 번까지는 일상적인 대소문자, 숫자, 문장 부호를 나타냅니다. 자세한 내용은 ASCII 코드 표를 참고하세요.
컴퓨터가 발전함에 따라 다양한 언어를 지원해야 할 필요성이 생겼습니다. ASCII 인코딩만으로는 이를 충족하기에 부족했습니다. 이에 따라 각 언어별로 고유한 인코딩 형식이 개발되었는데, 예를 들어 한국어의 EUC-KR, 간체 중국어의 GB2312, 러시아어의 KOI8-R 등이 있습니다.
하지만 전 세계에 수많은 언어군이 존재하다 보니, 모든 언어를 하나로 통합할 수 있는 단일 인코딩 형식이 필요해졌습니다. 이러한 요구를 충족하기 위해 탄생한 것이 바로 유니코드 (Unicode) 입니다.
1991 년, 유니코드 컨소시엄은 유니코드 문자 집합의 첫 번째 버전을 발표했습니다. 유니코드의 목표는 모든 언어를 하나의 인코딩 형식으로 통합하여 전 세계 컴퓨터가 텍스트를 더 쉽게 표시하고 처리할 수 있도록 하며, 다국어 환경에서의 호환성 문제를 해결하는 것이었습니다.
그러나 유니코드는 문자 집합일 뿐이었습니다. 즉, 문자에 코드를 부여했을 뿐 이를 실제로 어떻게 저장할지는 정의하지 않았습니다. 이로 인해 인터넷이 보급되기 전까지 오랫동안 널리 사용되는 데 어려움을 겪었습니다.
인터넷이 지속적으로 발전하면서 유니코드의 구현 방식 중 하나인 UTF-8 인코딩이 대중화되었습니다. UTF-8 은 가변 길이 인코딩 방식으로, 기호에 따라 바이트 길이가 달라질 수 있습니다.
예를 들어, ASCII 범위에 속하는 영문자의 경우 1 바이트로 표현됩니다. 문자 'y'(유니코드 값 121) 는 1 바이트를 차지합니다.
일상적으로 사용되는 대부분의 한글이나 한자는 3 바이트를 차지합니다. 예를 들어 '实'(유니코드 값 23454) 이라는 문자는 3 바이트를 사용합니다.
하지만 일부 문자는 4 바이트를 차지하기도 합니다. 이는 표현해야 할 문자가 매우 많기 때문인데, 3 바이트로는 약 6 만여 개의 문자만 표현할 수 있어 그 범위를 넘어가는 희귀 문자 등은 4 바이트를 사용하여 표현합니다.
UTF-8 인코딩의 또 다른 장점은 ASCII 인코딩과 하위 호환이 된다는 점입니다. 사실상 ASCII 는 UTF-8 의 부분 집합입니다. UTF-8 의 처음 128 개 문자는 ASCII 문자와 일대일로 대응합니다. 이는 기존에 ASCII 를 사용하던 소프트웨어를 수정 없이 또는 최소한의 수정만으로 계속 사용할 수 있음을 의미합니다. 이러한 장점 덕분에 UTF-8 은 점차 표준 인코딩 형식으로 자리 잡았습니다.
Go 언어의 창시자인 롭 파이크 (Rob Pike) 와 켄 톰슨 (Ken Thompson) 은 UTF-8 의 설계자이기도 합니다. 따라서 Go 언어는 UTF-8 과 매우 밀접한 관계가 있습니다. Go 는 소스 코드 파일을 반드시 UTF-8 인코딩으로 저장하도록 요구하며, 텍스트 문자를 다룰 때 UTF-8 을 기본으로 사용합니다. 또한 표준 라이브러리에서 UTF-8 인코딩 및 디코딩과 관련된 다양한 함수를 제공합니다.
byte는 uint8의 별칭 (alias) 이며 1 바이트 (8 비트) 를 차지합니다. ASCII 표에 있는 모든 문자를 표현하는 데 사용할 수 있습니다. 하지만 byte가 표현할 수 있는 값의 범위는 256 개 (2^8) 로 제한되어 있어, 한글이나 한자 같은 복합 문자를 처리할 때는 rune 타입을 사용해야 합니다.
byte.go라는 새 파일을 생성하고 다음 코드를 입력해 보세요.
cd ~/project
touch byte.go
package main
import "fmt"
func main() {
var a byte = 76
fmt.Printf("Value of a: %c\n", a)
var b uint8 = 76
fmt.Printf("Value of b: %c\n", b)
var c byte = 'L'
fmt.Printf("Value of c: %c\n", c)
}
프로그램을 실행하면 다음과 같은 결과가 출력됩니다.
go run byte.go
Value of a: L
Value of b: L
Value of c: L
%c 서식 지정자는 문자를 출력할 때 사용합니다. 값이 같을 경우 byte 타입과 uint8 타입이 동일한 결과를 출력하는 것을 볼 수 있습니다. ASCII 표를 확인해 보면 문자 'A'의 ASCII 값은 65 입니다. 정수 서식 지정자인 %d를 사용하여 출력해도 65 가 나옵니다.
따라서 Go 에서 byte는 정수 타입의 uint8과 동일하다는 것을 알 수 있습니다. rune 역시 마찬가지지만, 표현하는 정수 값의 범위가 다릅니다.
rune은 int32의 별칭이며 4 바이트 (32 비트) 를 차지합니다. 이모지 (Emoji) 와 같은 복합 문자를 표현하는 데 사용됩니다.
byte.go 파일을 다음 코드로 업데이트하세요.
package main
import "fmt"
func main() {
var a rune = '😊' // 미소 짓는 이모지
fmt.Printf("Value of a: %c\n", a)
var b int32 = 9829 // 유니코드 문자의 10 진수 표현 (하트 기호)
fmt.Printf("Value of b: %c\n", b)
var c rune = 0x1F496 // 유니코드 문자의 16 진수 표현 (반짝이는 하트 이모지)
fmt.Printf("Value of c: %c\n", c)
var d rune = '\u0041' // 코드 포인트를 사용한 유니코드 문자 (대문자 'A')
fmt.Printf("Value of d: %c\n", d)
var e rune = '\U0001F609' // 코드 포인트를 사용한 유니코드 문자 (윙크하는 얼굴 이모지)
fmt.Printf("Value of e: %c\n", e)
}
프로그램을 실행하면 다음과 같은 결과가 표시됩니다.
go run byte.go
주의: 프로그램은 Desktop 또는 WebIDE 터미널에서 실행하세요. LabEx VM 상단의 Terminal 탭에서는 정상적으로 출력되지 않을 수 있습니다.
Value of a: 😊
Value of b: ♥
Value of c: 💖
Value of d: A
Value of e: 😉
\u0041 형식을 사용하여 대문자 'A'를 나타냅니다.\U 형식과 코드 포인트 0001F609를 사용하여 윙크 이모지 '😉'를 나타냅니다.참고: Go 에서 홑따옴표 (') 와 쌍따옴표 (") 는 서로 다릅니다. 홑따옴표는 문자를 나타낼 때 사용하고, 쌍따옴표는 문자열을 선언할 때 사용합니다. 따라서 byte나 rune 타입을 선언할 때는 반드시 홑따옴표를 사용해야 하며, 그렇지 않으면 오류가 발생합니다.
이제 학습한 내용을 복습해 봅시다. rune.go라는 새 파일을 만들고 다음 코드를 입력하세요. 16 진수 0x1F648을 변수 a에 할당하고 프로그램이 그 값을 올바르게 출력하도록 코드를 완성해 보세요.
rune.go 파일은 ~/project 디렉토리에 위치해야 합니다.package main
import "fmt"
func main() {
var a rune = 0x1F648
fmt.Printf("The value of a is: %c\n", a)
}
이번 섹션에서 배운 내용을 정리해 보겠습니다.
byte 데이터 타입은 ASCII 문자를 표현하는 데 사용되며, rune 데이터 타입은 유니코드 문자를 표현하는 데 사용됩니다.byte는 uint8과, rune은 int32와 내부적으로 동일한 정수 타입입니다.이번 섹션에서는 먼저 ASCII, UTF-8, 유니코드의 개념을 살펴보았습니다. 그 다음 문자 데이터 타입인 byte와 rune이 정수 데이터 타입과 어떤 관계를 맺고 있는지 학습했습니다.