1. Вступ
Памʼятайте, що рядки в C# — незмінні (immutable). Це означає: після створення рядок змінити не можна. Будь‑які операції, що нібито «змінюють» рядок, насправді створюють новий рядок у памʼяті.
Наприклад, коли ви пишете:
string hello = "Привіт";
hello += " світ!"; // Здається, hello змінилася, але насправді створено новий об'єкт!
Змінна hello тепер вказує на новий об’єкт, а старий (якщо його більше ніде не використовують) колись видалить garbage collector. Якщо ви робите такі дії у циклі багато разів, може виникнути «захаращення» оперативної памʼяті й різке падіння продуктивності. Це особливо відчутно, коли об’єднуєте тисячі або мільйони рядків: на кожному кроці створюється новий рядок, копіюються всі його символи, старі об’єкти висять до збирання сміття, а ваша програма раптом починає гальмувати.
Ось тут на сцену виходить герой цієї лекції — 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 sb1 = new StringBuilder(); // Порожній
StringBuilder sb2 = new StringBuilder("Старт"); // З початковим текстом
StringBuilder sb3 = new StringBuilder(100); // Із запасом під 100 символів
Основні методи
var sb = new StringBuilder("Початок");
sb.Append(" + додали новий текст"); // Додати у кінець
sb.AppendLine(" (а це з перенесенням рядка)"); // Додати з перенесенням рядка
sb.Insert(0, "Старт: "); // Вставити з позиції 0
sb.Remove(0, 7); // Видалити 7 символів із позиції 0
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); // Видаляє 4 символи, починаючи з позиції 3
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() == "Привіт") { ... }
Змінність
На відміну від string, StringBuilder — змінний (mutable)! Один об’єкт може змінювати вміст скільки завгодно разів — саме це й дає виграш у швидкості.
Не забувайте про ToString() наприкінці роботи з об’єктом, інакше ви отримаєте не рядок, а незрозумілий текст на кшталт System.Text.StringBuilder.
Розмір буфера та його перерозподіл
Усередині StringBuilder зберігає масив символів. Якщо ви заздалегідь знаєте, що створюватимете дуже довгий рядок, можна передати в конструктор очікувану довжину — це трохи пришвидшить роботу.
var bigBuilder = new StringBuilder(50000); // Очікуємо 50 тисяч символів
Але якщо ви помилилися — не біда! StringBuilder за потреби розширить буфер сам; просто це буде трохи повільніше.
Переповнення памʼяті?
Теоретично, якщо зовсім не знати міри й додавати мільярди символів, можна отримати OutOfMemoryException, але у реальних завданнях це трапляється вкрай рідко.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ