Go 문자열은 불변인 바이트의 나열이며, 보통 UTF-8 텍스트입니다. 연산자(+, ==, <, 인덱싱, 슬라이싱)는 문자열 자체에 동작하고, 나머지는 모두 표준 strings 패키지에 있습니다.
문자열 나누기
| 함수 | 나누는 기준 | 참고 |
|---|---|---|
Split(s, sep) | 모든 sep | 빈 부분 유지, Split("", ",")는 빈 문자열 하나인 [""] 반환 |
SplitN(s, sep, n) | 최대 n개 부분 | 마지막 부분에 나머지가 담김 |
SplitAfter(s, sep) | 모든 sep | 각 부분에 구분자를 남김 |
Fields(s) | 연속된 공백 | 빈 부분을 반환하지 않음 |
FieldsFunc(s, f) | f가 참인 문자 | 사용자 정의 구분자 |
Cut(s, sep) | 첫 번째 sep만 | 앞부분, 뒷부분, 찾았는지 여부를 반환(Go 1.18) |
Split("", ",")의 경우에서 많은 사람이 걸립니다. 빈 입력은 길이 0이 아니라 길이 1인 슬라이스를 줍니다. 사용자 입력을 나눌 때는 Fields를 쓰거나 먼저 s == ""를 확인하면 유령 같은 빈 요소를 피할 수 있습니다.
strings.Cut은 key=value, user@host 같은 쌍을 나누는 가장 깔끔한 방법입니다. Go 1.24에는 슬라이스를 만들지 않고 부분을 하나씩 내놓는 이터레이터 버전 strings.SplitSeq와 strings.FieldsSeq도 추가되었습니다.
검색
| 함수 | 반환 |
|---|---|
Contains(s, sub) | s에 sub가 있으면 true |
ContainsAny(s, chars) | chars의 문자 중 하나라도 있으면 true |
HasPrefix(s, p) / HasSuffix(s, p) | s가 p로 시작하거나 끝나면 true |
Index(s, sub) | 첫 일치의 바이트 위치, 없으면 -1 |
LastIndex(s, sub) | 마지막 일치의 바이트 위치, 없으면 -1 |
Count(s, sub) | 겹치지 않는 일치 개수 |
EqualFold(a, b) | 대소문자를 무시한 동등 비교 |
EqualFold를 빼면 모든 검색은 대소문자를 구분합니다. 대소문자를 무시하고 검색하려면 양쪽을 소문자로 바꾸거나, 문자열 전체를 비교할 때는 EqualFold를 쓰세요.
변환
함정이 하나 있습니다. Trim, TrimLeft, TrimRight는 접두사가 아니라 문자 집합을 받습니다. strings.TrimLeft("abcab", "ab")는 앞쪽의 a와 b를 모두 제거해서 "cab"를 반환합니다. 정확한 접두사나 접미사를 제거하려면 TrimPrefix와 TrimSuffix를 쓰세요.
이어 붙이기와 strings.Builder
+는 문자열을 잇고, fmt.Sprintf는 값들을 하나의 문자열로 형식화합니다. 문자열은 불변이므로 둘 다 매번 새 문자열을 할당합니다. 연산이 몇 번뿐이면 괜찮지만 반복문에서는 느립니다. +=를 할 때마다 지금까지 만든 것 전체를 복사하기 때문입니다. 대신 strings.Builder를 쓰세요:
제로 값 strings.Builder는 바로 쓸 수 있습니다. io.Writer를 구현하므로 fmt.Fprintf로 직접 쓸 수 있습니다. 결과의 대략적인 크기를 안다면 먼저 b.Grow(n)을 호출하세요. 쓰기 시작한 Builder는 복사하지 말고 포인터로 넘기세요.
여러 줄 문자열과 원시 문자열
Go에는 두 종류의 문자열 리터럴이 있습니다:
큰따옴표 문자열은 이스케이프(\n, \t, \", \\, \u00e9)를 처리하고 한 줄에 들어가야 합니다. 백쿼트로 감싼 원시 문자열은 줄바꿈을 포함해 모든 것을 글자 그대로 받아들이므로, 여러 줄 문자열, 정규 표현식, JSON, Windows 경로를 쓰는 방법이 됩니다. 원시 문자열에는 백쿼트를 넣을 수 없고, 그 안의 캐리지 리턴은 제거됩니다. 위의 쿼리는 여는 백쿼트 바로 다음부터 리터럴이 시작되므로 줄바꿈으로 시작한다는 점에 주의하세요.
길이, 인덱싱, 부분 문자열
len(s)는 바이트 수입니다. s[i]는 바이트이고, s[i:j]는 바이트 위치로 자른 부분 문자열입니다:
ï와 é는 각각 2바이트를 차지하므로 이 문자열은 12바이트이고 10글자입니다. 위치가 strings.Index 같은 함수에서 나왔다면 바이트로 잘라도 안전합니다. 이런 함수는 문자 경계에 놓인 바이트 오프셋을 반환하기 때문입니다. "앞의 n글자"를 가져오려면 먼저 []rune으로 변환하세요. UTF-8은 rune과 byte 페이지에서 깊이 설명합니다.
문자열은 불변이다
바이트를 제자리에서 바꿀 수 없습니다. s[0] = 'H'는 컴파일 오류입니다(cannot assign to s[0] (neither addressable nor a map index expression)). strings의 모든 함수는 새 문자열을 반환합니다. 편집하려면 []byte나 []rune으로 변환해서 슬라이스를 바꾼 뒤 다시 변환하세요:
b := []byte("hello")
b[0] = 'H'
s := string(b) // "Hello"
부분 문자열이 저렴한 이유도 불변성입니다. s[2:5]는 복사하지 않고 s와 메모리를 공유합니다. 반대로 거대한 문자열의 작은 부분 문자열이 거대한 문자열 전체를 살려 둔다는 단점도 있습니다. 큰 입력의 짧은 조각을 보관할 때는 strings.Clone(Go 1.20)을 쓰세요.
문자열 비교
==와 !=는 내용을 비교하고, <, >는 바이트 단위로 비교하며 ASCII라면 알파벳순입니다. strings.Compare도 있지만 필요한 경우는 드뭅니다. []string에 대한 slices.Sort는 <를 씁니다. 영어가 아닌 텍스트를 로캘에 맞게 정렬하려면 golang.org/x/text/collate를 쓰세요.
다른 타입에서 변환하기
숫자는 strconv.Itoa, strconv.FormatFloat, fmt.Sprintf로 문자열이 되고, 문자열은 strconv.Atoi와 strconv.ParseFloat로 숫자가 됩니다. string(42)라고 쓰지 마세요. 코드 포인트 42인 문자 "*"가 만들어집니다. 전체 표는 타입 변환 페이지에 있습니다.
자주 묻는 질문
Go에서 문자열은 어떻게 나누나요?
strings.Split(s, sep)를 씁니다: strings.Split("a,b,c", ",")는 ["a" "b" "c"]를 반환합니다. 연속된 공백 기준으로 나누고 빈 부분을 버리려면 strings.Fields(s)를 쓰세요. strings.SplitN은 부분 개수를 제한하고, strings.Cut은 첫 번째 구분자를 기준으로 한 번 나눕니다.
Go에서 여러 줄 문자열은 어떻게 쓰나요?
백쿼트로 감싼 원시 문자열 리터럴을 씁니다:
query := `SELECT id, name
FROM users
WHERE active = true`
백쿼트 사이의 모든 것은 줄바꿈과 백슬래시를 포함해 글자 그대로 받아들여집니다. 원시 문자열에는 백쿼트를 넣을 수 없습니다.
Go에서 문자열에 부분 문자열이 포함되어 있는지 어떻게 확인하나요?
strings.Contains(s, substr)가 bool을 반환합니다. 관련 함수로는 strings.HasPrefix, strings.HasSuffix, strings.Index(위치 또는 -1), strings.ContainsAny(문자 집합 중 하나라도 있는지), 대소문자를 무시한 비교를 위한 strings.EqualFold가 있습니다.
Go에서 문자열을 이어 붙이는 가장 빠른 방법은 무엇인가요?
문자열 몇 개라면 +로 충분합니다. 반복문에서 문자열을 만든다면 strings.Builder를 쓰세요. WriteString을 반복해서 호출하고 마지막에 String()을 한 번 호출합니다. 반복문 안의 +=는 매번 문자열 전체를 복사하므로 문자열이 커질수록 느려집니다. 슬라이스를 구분자로 이을 때는 strings.Join을 쓰세요.
len이 내 문자열의 길이를 잘못 반환하는 이유는 무엇인가요?
len(s)는 문자가 아니라 바이트 수를 반환합니다. Go 문자열은 UTF-8이고 ASCII 밖의 문자는 2에서 4바이트를 차지하므로 len("héllo")는 6입니다(한글은 한 글자에 3바이트). 유니코드 코드 포인트 개수는 utf8.RuneCountInString(s)로 구하세요.