Avatar ·

Форматирование строк в JavaScript: аналог printf или String.Format

Привет, коллеги! Я новичок в JavaScript, перешёл с Python и C#. Там я привык к удобному форматированию строк: в Python — f"Hello, {name}", в C# — String.Format("Hello, {0}", name). А в JavaScript я вижу только конкатенацию через плюсы: "Hello, " + name + "! You have " + count + " messages." — это выглядит ужасно, особенно когда много переменных. Я знаю про шаблонные строки (template literals) с обратными кавычками: `Hello, ${name}!` Но есть ли в JavaScript встроенная функция, похожая на printf из C или String.Format из .NET? Например, чтобы можно было писать что-то вроде: let result = sprintf("Привет, %s! У тебя %d новых сообщений.", name, count); Или: let result = String.Format("Значение PI = {0:F2}", Math.PI); Я пробовал искать, но в документации не нашёл ничего подобного. Может, я что-то упускаю? Или нужно использовать сторонние библиотеки? Буду благодарен за примеры кода и объяснения. <<>>

Краткий ответ

В JavaScript нет встроенной функции, полностью аналогичной printf или String.Format. Однако есть несколько элегантных способов решить эту задачу: от использования шаблонных строк (самый современный и рекомендуемый способ) до написания собственной функции или подключения лёгкой библиотеки.

1. Шаблонные строки (Template Literals) — лучший вариант

Стандарт ES6 (2015) ввёл шаблонные строки. Они решают 90% задач форматирования:

const name = "Алексей";
const count = 42;
const pi = Math.PI;

// Базовая интерполяция
const result = `Привет, ${name}! У тебя ${count} новых сообщений.`;
console.log(result); // "Привет, Алексей! У тебя 42 новых сообщения."

// Можно использовать выражения
const formattedPi = `PI с двумя знаками: ${pi.toFixed(2)}`;
console.log(formattedPi); // "PI с двумя знаками: 3.14"

// Многострочные строки без \n
const multiline = `
  Строка 1: ${name}
  Строка 2: ${count}
`;

Плюсы: нативный синтаксис, безопасность (экранирование), поддержка любых выражений. Минусы: нет встроенного форматирования чисел (например, %02d), но это решается методами .toFixed(), .padStart() и т.д.

2. Собственная функция sprintf (легковесная)

Если вам нужен точный аналог printf, напишите простую функцию:

function sprintf(format, ...args) {
  return format.replace(/%([sd])/g, (match, type) => {
    const value = args.shift();
    switch (type) {
      case 's': return String(value);
      case 'd': return parseInt(value, 10).toString();
      default: return match;
    }
  });
}

// Пример:
console.log(sprintf("Привет, %s! У тебя %d сообщений.", "Мир", 42));
// "Привет, Мир! У тебя 42 сообщений."

Этот код можно расширить для поддержки %f, %x, ширины поля и т.д.

3. Использование библиотек

Для сложного форматирования (даты, валюты, локализация) лучше взять готовое решение:

  • sprintf-js — лёгкая библиотека (2KB), точная копия C-шного sprintf. Установка: npm install sprintf-js.
  • Intl.NumberFormat и Intl.DateTimeFormat — встроенные объекты для локализованного форматирования чисел и дат.
// Пример с sprintf-js
const sprintf = require('sprintf-js').sprintf;
console.log(sprintf("PI = %.2f, HEX = %X", Math.PI, 255));
// "PI = 3.14, HEX = FF"

// Пример с Intl
const formatter = new Intl.NumberFormat('ru-RU', {
  style: 'currency',
  currency: 'RUB'
});
console.log(formatter.format(12345.67)); // "12 345,67 ₽"

4. Альтернатива: метод replace с регулярным выражением

Можно имитировать String.Format из C#:

String.prototype.format = function(...args) {
  return this.replace(/{(\d+)}/g, (match, index) => {
    return args[index] !== undefined ? args[index] : match;
  });
};

console.log("Привет, {0}! У тебя {1} сообщений.".format("Мир", 42));
// "Привет, Мир! У тебя 42 сообщений."

Итоговый совет

Для большинства повседневных задач используйте шаблонные строки — они читаемы, безопасны и не требуют дополнительных зависимостей. Если вам нужен точный printf (например, для форматирования чисел с ведущими нулями), добавьте библиотеку sprintf-js или напишите свою мини-функцию.

<<>>

Дополнительный подход: форматирование чисел с помощью Intl и padStart

Если вам не нужна полноценная библиотека, а только форматирование чисел (добавление ведущих нулей, фиксированное количество знаков после запятой), можно комбинировать шаблонные строки со встроенными методами:

function formatNumber(num, width = 2) {
  return String(num).padStart(width, '0');
}

function formatCurrency(amount) {
  return new Intl.NumberFormat('ru-RU', {
    style: 'currency',
    currency: 'RUB',
    minimumFractionDigits: 2
  }).format(amount);
}

// Пример использования:
const id = 7;
const price = 12345.5;
console.log(`Заказ №${formatNumber(id, 4)} на сумму ${formatCurrency(price)}`);
// "Заказ №0007 на сумму 12 345,50 ₽"

Этот подход не требует сторонних библиотек, полностью контролируется разработчиком и легко расширяется. Для дат используйте Intl.DateTimeFormat:

const date = new Date();
const formatter = new Intl.DateTimeFormat('ru-RU', {
  year: 'numeric',
  month: 'long',
  day: 'numeric'
});
console.log(`Сегодня: ${formatter.format(date)}`);
// "Сегодня: 15 марта 2025 г."

Таким образом, вы получаете гибкость printf без потери производительности и читаемости.