Підрозділ 11.3
Форматування та інтерполяція рядків
Пояснює форматування та інтерполяцію рядків: плейсхолдери, string.Format, специфікатори валюти, чисел, відсотків, настроювані формати, ToString і вирівнювання.
11.3. Форматування та інтерполяція рядків
Виведення числових, датових та складних рядкових значень вимагає контролю над форматом: кількість знаків після коми, вирівнювання колонок у звіті, символ валюти. C# надає три підходи до вставки значень у рядки, кожен зі своїми сценаріями застосування.

Конкатенація (+)
Найпростіший спосіб — об'єднання через +. Числові та інші типи автоматично перетворюються через ToString():
string name = "Петренко";
int age = 67;
double bp = 140.5;
string s = "Пацієнт: " + name + ", вік: " + age + ", АТ: " + bp.ToString("F2") + " мм рт.ст.";Недоліки: кожен + породжує новий об'єкт у heap; при більш ніж трьох значеннях код стає важкочитаним; числові специфікатори потрібно задавати через ToString() окремо, що розриває читабельний потік рядка. Конкатенація + доцільна лише для об'єднання двох-трьох частин без специфікаторів.
Важливий нюанс компілятора: якщо всі операнди є рядковими літералами ("a" + "b" + "c"), Roslyn розраховує результат ще під час компіляції і поміщає в IL єдиний рядок "abc" — жодної алокації під час виконання. Проте як тільки з'являється змінна або вираз — рядок будується динамічно.
string.Format()
Метод string.Format приймає рядок-шаблон із плейсхолдерами {0}, {1}, ... і набір аргументів:
string s = string.Format(
"Пацієнт: {0}, вік: {1}, АТ: {2:F2} мм рт.ст.",
name, age, bp);Переваги string.Format:
- Шаблон відокремлено від даних — зручно для локалізації (зберігати шаблони в ресурсних файлах).
- Один аргумент можна повторити кілька разів:
"{0}...{0}". - Плейсхолдер
{index:specifier}поєднує позицію і формат в одному місці.
Метод string.Format (і клас StringBuilder.AppendFormat) також приймає необов'язковий перший параметр типу IFormatProvider — зазвичай CultureInfo. Він визначає культурно-залежне форматування: який символ використовується як десятковий роздільник, розділювач тисяч, символ валюти. За замовчуванням використовується культура поточного потоку (CultureInfo.CurrentCulture):
using System.Globalization;
double bp = 140.5;
// В українській культурі десятковий роздільник — кома
string ua = string.Format(CultureInfo.GetCultureInfo("uk-UA"), "{0:F2}", bp); // "140,50"
// В американській — крапка
string us = string.Format(CultureInfo.InvariantCulture, "{0:F2}", bp); // "140.50"Це критично важливо при записі числових даних у файли або передачі між сервісами: якщо на сервері культура uk-UA, а клієнт очікує InvariantCulture — парсинг поверне помилку. Для серіалізації даних завжди слід явно передавати CultureInfo.InvariantCulture.
Інтерполяція рядків ($"...")
Інтерполяція — найчитабельніший і найчастіше вживаний підхід. Рядок починається зі знака $; всередині фігурних дужок — будь-який вираз C#:
string s = $"Пацієнт: {name}, вік: {age}, АТ: {bp:F2} мм рт.ст.";Компілятор перетворює $"..." у виклик string.Format() — тобто на рівні IL обидва підходи ідентичні. Переваги $"...": імена змінних замість номерів, компілятор перевіряє типи на етапі компіляції, будь-які вирази прямо у {}:
int systolic = 140;
int diastolic = 90;
Console.WriteLine($"АТ: {systolic}/{diastolic} — {(systolic > 130 ? "підвищений" : "норма")}");
// АТ: 140/90 — підвищенийПочинаючи з C# 10, компілятор застосовує додаткову оптимізацію: замість виклику string.Format він використовує DefaultInterpolatedStringHandler — структуру, яка будує рядок через Span<char> на стеку без зайвих алокацій. Ця оптимізація вмикається автоматично і не потребує змін у коді.
Інтерполяцію можна поєднати з verbatim-рядком (@) для тексту з зворотними слешами або переносами рядків без \n:
// @$ або $@ — обидва порядки допустимі з C# 8
string path = $@"C:\Patients\{lastName}\record.txt";Специфікатори форматування
Специфікатори використовуються однаково у string.Format та $"..." через двокрапку після виразу: {value:specifier}.
Числові специфікатори
| Специфікатор | Назва | Приклад |
|---|---|---|
C2 |
Валюта | {23.7:C2} → 23,70 грн. |
D4 |
Ціле (з нулями) | {23:D4} → 0023 |
F2 |
Дробове | {140.567:F2} → 140,57 |
N0 |
Тисячний роздільник | {12345:N0} → 12 345 |
P1 |
Відсоток | {0.153:P1} → 15,3% |
E2 |
Науковий формат | {12345.6:E2} → 1,23E+004 |
Число після літери специфікатора задає кількість знаків після коми (або мінімальну кількість цифр для D).
Детальніше про кожен:
C(Currency) — додає символ валюти поточної культури. Кількість знаків після коми визначається культурою за замовчуванням (зазвичай 2). Для медичного застосунку в Україні дасть₴абогрн.залежно від версії .NET і культури ОС.D(Decimal) — тільки для цілочисельних типів (int,long). Заповнює нулями зліва до мінімальної кількості цифр.{42:D6}→"000042". Ідеальний для номерів медичних карток і ідентифікаторів пацієнтів.F(Fixed-point) — дробове число з фіксованою кількістю знаків після коми. Використовується для медичних показників: артеріальний тиск, глюкоза, температура.N(Number) — додає тисячний роздільник.{12345678:N0}→"12 345 678". Зручний для сум у фінансових звітах лікарні.P(Percent) — множить значення на 100 і додає знак%. Значення0.847дасть"84,7%". Корисний для статистики успішності лікування.E(Exponential) — науковий запис. Використовується рідко — лише для дуже великих або малих чисел у лабораторних дослідженнях.
Довільний формат через
Символ # дозволяє задати довільний шаблон. Наприклад, телефон пацієнта:
long phone = 380671234567;
Console.WriteLine($"{phone:+## (###) ###-##-##}"); // +38 (067) 123-45-67У шаблонах # означає «необов'язкова цифра» (нічого не виводиться якщо цифри немає), а 0 — «обов'язкова цифра» (виводиться 0). Шаблон обробляється справа наліво від десяткової крапки — тому цифри з кінця числа розподіляються по позиціях шаблону.
Вирівнювання
Після виразу і специфікатора можна вказати ширину поля через кому. Від'ємне значення — вирівнювання ліворуч, додатне — праворуч:
string name = "Петренко";
double value = 140.5;
Console.WriteLine($"|{"Ім'я",15}|{"АТ",8}|");
Console.WriteLine($"|{name,15}|{value,8:F1}|");
Console.WriteLine($"|{name,-15}|{value,-8:F1}|");Вивід:
| Ім'я| АТ|
| Петренко| 140,5|
|Петренко |140,5 |Механізм вирівнювання є надзвичайно зручним для побудови текстових таблиць: кожна колонка має фіксовану ширину, а значення автоматично вирівнюються. Правостороннє вирівнювання ({value,8}) стандартне для чисел; лівостороннє ({name,-20}) — для текстових полів.
Raw string literals (C# 11)
Починаючи з C# 11, рядки можна записувати у потрійних лапках """...""". Такий рядок може містити лапки та переноси рядків без екранування:
string template = """
Виписка з лікарні
Пацієнт: Петренко І.С.
Діагноз: "Гіпертензія артеріальна"
Рекомендації: прийом "Лізиноприл" 10 мг
""";
Console.WriteLine(template);Raw string literals особливо зручні для JSON-шаблонів, SQL-запитів або HTML-фрагментів у медичних застосунках. Відступ, що збігається з відступом закриваючих """, автоматично видаляється компілятором — рядок зберігатиме відносні відступи правильно.
Крім того, raw string literals можна поєднувати з $ для інтерполяції: $"""...""". Якщо всередині потрібна фігурна дужка як літерал, вона записується подвоєно: {{ і }}.
Метод ToString() зі специфікатором
Будь-який числовий тип підтримує ToString(specifier) — ті самі специфікатори, що й у Format:
double bp = 140.567;
int patId = 42;
long phone = 380671234567;
Console.WriteLine(bp.ToString("F1")); // 140,6
Console.WriteLine(patId.ToString("D6")); // 000042
Console.WriteLine(phone.ToString("+## (###) ###-##-##")); // +38 (067) 123-45-67ToString(specifier) також приймає другий параметр IFormatProvider: bp.ToString("F2", CultureInfo.InvariantCulture). Це той самий механізм, що й у string.Format — реалізується через інтерфейс IFormattable, який реалізований усіма числовими типами .NET.
Форматований звіт пацієнта — runnable приклад
Демонстрація специфікаторів C/F/N/P у клінічному звіті:
Таблиця відділення з вирівнюванням — runnable приклад
Форматована таблиця через вирівнювання у $"...":