1. 소개
다시 말하지만, C#에서 문자열은 변경 불가능해 (immutable). 즉, 한 번 만들면 문자열을 바꿀 수 없어. 뭔가 "문자열을 바꾼다"는 연산을 해도 실제로는 새로운 문자열이 메모리에 만들어지는 거야.
예를 들어, 이렇게 쓴다고 해보자:
string hello = "안녕";
hello += " 세상!"; // 보기엔 hello가 바뀐 것 같지만, 실제로는 새로운 객체가 만들어진 거야!
hello 변수는 이제 새로운 객체를 가리키고, 예전 객체는 (아무도 안 쓰면) 언젠가 가비지 컬렉터가 지워버려. 이런 걸 반복문에서 여러 번 하면, 메모리가 "꽉 차서" 성능이 확 떨어질 수 있어. 특히 수천, 수만 개의 문자열을 합칠 때 심각하지. 매번 새 문자열이 만들어지고, 모든 문자가 복사되고, 예전 객체는 가비지 컬렉션까지 남아있고, 프로그램이 갑자기 느려질 수 있어.
이럴 때 등장하는 게 바로 오늘의 주인공 StringBuilder야.
using System.Text; // ← 꼭 필요해!
StringBuilder sb = new StringBuilder("안녕");
sb.Append(" 세상!"); // 이제 문자열이 빠르고 효율적으로 바뀌어<
StringBuilder와 친해지기
StringBuilder는 System.Text 네임스페이스에 있는 클래스야. 이 클래스의 목적은 새 객체를 계속 만들지 않고, 내용만 바꿔가면서 큰 문자열을 효율적으로 만들고 합치는 거지.
비유하자면:
string(문자열)은 모자이크 조각 한 덩어리야. 바꾸려면 전체를 새로 만들어야 해. StringBuilder는 자석 칠판 같은 거야. 조각을 붙였다 뗐다, 계속 추가하거나 빼도 칠판은 그대로고, 새 칠판을 만들 필요가 없어.
언제 StringBuilder를 써야 할까?
- 문자열을 여러 번(특히 반복문에서) 바꿔야 할 때
- 작은 조각들을 많이 합쳐서 텍스트를 만들어야 할 때
- 속도나 메모리 사용이 신경 쓰일 때
언제 안 써도 될까?
- 딱 1~2번만 간단히 문자열을 다룰 때는 그냥 string이 더 쉽고 읽기 좋아.
- 문자열의 모든 상태를 따로따로 저장하고 싶을 때(이런 경우는 거의 없겠지만)
2. StringBuilder 만들기와 기본 사용법
네임스페이스 추가하기
시작은 간단해: 네임스페이스를 꼭 추가해야 해.
using System.Text;// ← 꼭 필요해!
새 StringBuilder 만드는 방법
StringBuilder sb1 = new StringBuilder(); // 비어 있음
StringBuilder sb2 = new StringBuilder("시작"); // 처음에 텍스트 넣기
StringBuilder sb3 = new StringBuilder(100); // 100글자까지 미리 공간 확보
주요 메서드
var sb = new StringBuilder("처음");
sb.Append(" + 새 텍스트 추가"); // 끝에 추가
sb.AppendLine(" (이건 줄바꿈 포함)"); // \n과 함께 추가
sb.Insert(0, "시작: "); // 0번 위치에 삽입
sb.Remove(0, 7); // 0번부터 7글자 삭제
sb.Replace("텍스트", "STRING"); // 모든 "텍스트"를 "STRING"으로 바꿈
string result = sb.ToString(); // 최종 문자열 얻기
3. StringBuilder의 효율성
예시: 성능 비교
예를 들어 10 000개의 숫자를 쭉 이어서 문자열로 만들어야 한다고 해보자(예를 들어, 네 친구들 학번을 다 출력해야 한다고 치자):
순진한 방법 (string)
string text = "";
for (int i = 0; i < 10000; i++)
{
text += i + " "; // 매번 새 문자열이 만들어져!
}
Console.WriteLine(text.Substring(0, 100) + "..."); // 출력 줄이려고 일부만
최적화된 방법 (StringBuilder)
var sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
sb.Append(i).Append(' '); // 체인처럼 붙일 수 있어!
}
Console.WriteLine(sb.ToString().Substring(0, 100) + "...");
차이가 뭐냐면?
첫 번째 방법은 훨씬 느리고, 메모리도 훨씬 많이 먹어. 두 번째는 빠르고 메모리도 적게 써.
4. StringBuilder에서 제일 많이 쓰는 메서드
Append — 문자열이나 다른 타입(자동으로 문자열로 바꿔줌)을 추가해:
sb.Append("텍스트");
sb.Append(123); // 123이 "123"으로 바뀜
sb.Append('!'); // 문자 하나
AppendLine — 문자열 + 줄바꿈 문자 추가:
sb.AppendLine("문자열"); // "문자열\n"이 추가됨
Insert — 특정 위치에 문자열 삽입:
sb.Insert(0, "Hello, "); // 맨 앞에 삽입
Remove — 몇 글자 삭제:
sb.Remove(3, 4); // 3번 위치부터 4글자 삭제
Replace — 모든 부분 문자열이나 문자를 바꿈:
sb.Replace("old", "new");
sb.Replace('a', 'A');
ToString — 완성된 문자열을 반환해.
문자열 자르기
string과 달리, StringBuilder 객체는 길이를 새로 지정할 수 있어. 그러면 문자열이 그 길이로 잘려.
sb.Length = 10; // 10글자 이후는 다 사라져!
5. 사용 팁과 흔한 실수
왜 ToString()이 중요할까
StringBuilder로 작업하는 동안 네 "손"에 들려 있는 건 문자열이 아니라 특별한 객체야. 많은 메서드(예: Console.WriteLine)는 이 객체도 자동으로 문자열로 바꿔주니까 괜찮지만, 가끔은 이런 식으로 실수할 수 있어:
if (sb == "안녕") { ... } // 이런! sb에 "안녕"이 들어있어도 이건 안 돼
결과는 false야: 서로 다른 타입의 객체를 비교하는 거라서 그래.
정답은:
if (sb.ToString() == "안녕") { ... }
변경 가능성(mutable)
string과 달리, StringBuilder는 변경 가능해 (mutable)! 한 객체로 내용을 계속 바꿀 수 있어서 속도가 훨씬 빨라지는 거지.
작업 끝나면 ToString()을 꼭 써서 문자열로 바꿔줘. 안 그러면 System.Text.StringBuilder 같은 이상한 텍스트만 나올 거야.
버퍼 크기와 재할당
StringBuilder 내부에는 문자 배열이 있어. 만약 "엄청 긴" 문자열을 만들 거라면, 생성자에 예상 길이를 넣어주면 조금 더 빨라질 수 있어.
var bigBuilder = new StringBuilder(50000); // 5만 글자 예상
근데 혹시 예상이 틀려도 괜찮아! StringBuilder가 필요하면 버퍼를 자동으로 늘려주니까, 다만 약간 느려질 뿐이야.
메모리 초과?
이론적으로, 진짜 끝도 없이 수십억 글자를 추가하면 OutOfMemoryException이 날 수도 있지만, 현실에서는 거의 그런 일 없어.
GO TO FULL VERSION