Форматирование и интерполяция строк. Форматирующие строки

String.Format("{0}", "formatting string"};

One of the painful things about good old ASP was string formatting; VBScript simply didn"t have anything useful. C# (and VB.Net) do, but MSDN doesn"t provide a quick reference to the formatting options. So here"s a quick reference.

To compare string formatting in C# to those in C lets have an example,

char szOutput;
sprintf(szOutput, "At loop position %d.\n", i);

sprintf takes an output buffer, a format string and any number of arguments to substitute into the format string.

The C# equivalent for sprintf is String.Format, which takes a format string and the arguments. It returns a string, and because you"re not passing in a buffer there"s no chance of a buffer overflow.

string outputString = String.Format("At loop position {0}.\n", i);

So why doesn"t have the format argument have parameters specifying what data type you"re formatting? The CLR objects have metadata which informs the CLR what the objects are, and each object has a standard ToString() method which returns a string representation of that object. Much nicer than C where if you passed the wrong type of variable into sprintf everything could come crashing down.

The ToString method can accept a string parameter which tells the object how to format itself. In the call to String.Format , the formatting string is passed after the position, for example, "{0:##}". The text inside the curly braces is {argumentIndex[,alignment][:formatString]}. If alignment is positive, the text is right-padding to fill the specified field length, if it"s negative, it"s left-padded.

Formatting strings

There"s not much formatting that can be applied to a string. Only the padding / alignment formatting options can be applied. These options are also available to every argument, regardless of type.

example

output

String.Format("--{0,10}--", "test");

Test--

String.Format("--{0,-10}--", "test");

Test --

Formatting numbers

Number formatting is culture dependant . For example, formatting a currency string on my laptop will return a result like £9.99, formatting a currency on a machine set for the US region would return $9.99.

specifier

type

format

output
(double 1.2345)

output
(int -12345)

c

currency

{0:c}

£1.23

-£12,345.00

d

decimal
(whole number)

{0:d}

System.FormatException

12345

e

exponent / scientific

{0:e}

1.234500e+000

1.234500e+004

f

fixed point

{0:f}

1.23

12345.00

g

general

{0:g}

1.2345

12345

n

number

{0:n}

1.23

12,345.00

r

round trippable

{0:r}

1.23

System.FormatException

x

hexadecimal

{0:x4}

System.FormatException

ffffcfc7

Custom number formatting

specifier

type

format

output
(double 1234.56)

0

zero placeholder

{0:00.000}

1234.560

#

digit placeholder

{0:#.##}

1234.56

.

decimal point placeholder

{0:0.0}

1234.6

,

thousand separator

{0:0,0}

1,235

%

percentage

{0:0%}

123456%

In addition there is the group separator; this is useful for varying the format, depending on the value of the parameter passed. For example

String.Format("{0:£#,##0.00;(£#,##0.00);Nothing}", value);

This will output "£1,240.00" if passed 1243.56. It will output the same format bracketed if the value is negative "(£1,240.00)", and will output the string "Nothing" if the number is zero.

Date formatting

Date formats are very dependant on the culture information passed. The examples below are shown using the UK culture.

specifier

type

output
(June 8, 1970 12:30:59)

d

Short Date

08/06/1970

D

Long Date

08 June 1970

t

Short Time

12:30

T

Long Time

12:30:59

f

Full date and time

08 June 1970 12:30

F

Full date and time (long)

08 June 1970 12:30:59

g

Default date and time

08/06/1970 12:30

G

Default date and time (long)

08/06/1970 12:30:59

M

Day / Month

8 June

r

RFC1123 date string

Mon, 08 Jun 1970 12:30:59 GMT

s

Sortable date/time

1970-06-08T12:30:59

u

Universal time, local timezone

1970-06-08 12:30:59Z

Y

Month / Year

June 1970

custom date formatting

specifier

type

output
(June 8, 1970 12:30:59)

dd

Day

08

ddd

Short Day Name

Mon

dddd

Full Day Name

Monday

hh

2 digit hour

12

HH

2 digit hour (24 hour)

12

mm

2 digit minute

30

MM

Month

06

MMM

Short Month name

Jun

MMMM

Month name

June

ss

seconds

59

tt

AM/PM

PM

yy

2 digit year

70

yyyy

4 digit year

1970

:

seperator, e.g. {0:hh:mm:ss}

12:30:59

/

seperator, e.g. {0:dd/MM/yyyy}

08/06/1970

There are others, including time zone formatting and so on, but the ones above are the most commonly used.

Culture information

string.format also provides a method which accepts a CultureInfo argument, as an IFormatProvider. This is important when trying to write portable and localisable code, as, for example, month names will change according to the local culture of the machine you are running on. Rather than simply call the standard String.Format you should consider always calling the overloaded culture method. If you don"t need to specify a culture you can use the System.Globalization.CultureInfo.InvariantCulture. This will then default your formatting to English, as opposed to the culture of the current thread.

This example formats double to string with fixed number of decimal places . For two decimal places use pattern „0.00 “. If a float number has less decimal places, the rest digits on the right will be zeroes. If it has more decimal places, the number will be rounded.


// just two decimal places String .Format("{0:0.00}" , 123.4567); // "123.46" String .Format("{0:0.00}" , 123.4); // "123.40" String .Format("{0:0.00}" , 123.0); // "123.00"

Next example formats double to string with floating number of decimal places . E.g. for maximal two decimal places use pattern „0.## “.


// max. two decimal places String .Format("{0:0.##}" , 123.4567); // "123.46" String .Format("{0:0.##}" , 123.4); // "123.4" String .Format("{0:0.##}" , 123.0); // "123"

Digits before decimal point

If you want a float number to have any minimal number of digits before decimal point use N-times zero before decimal point. E.g. pattern „00.0 “ formats a float number to string with at least two digits before decimal point and one digit after that.


// at least two digits before decimal point String .Format("{0:00.0}" , 123.4567); // "123.5" String .Format("{0:00.0}" , 23.4567); // "23.5" String .Format("{0:00.0}" , 3.4567); // "03.5" String .Format("{0:00.0}" , -3.4567); // "-03.5"

Thousands separator

To format double to string with use of thousands separator use zero and comma separator before an usual float formatting pattern, e.g. pattern „0,0.0 “ formats the number to use thousands separators and to have one decimal place.


String .Format("{0:0,0.0}" , 12345.67); // "12,345.7" String .Format("{0:0,0}" , 12345.67); // "12,346"

Zero

Float numbers between zero and one can be formatted in two ways, with or without leading zero before decimal point. To format number without a leading zero use # before point. For example „#.0 “ formats number to have one decimal place and zero to N digits before decimal point (e.g. „.5“ or „123.5“).

Following code shows how can be formatted a zero (of double type).


String .Format("{0:0.0}" , 0.0); // "0.0" String .Format("{0:0.#}" , 0.0); // "0" String .Format("{0:#.0}" , 0.0); // ".0" String .Format("{0:#.#}" , 0.0); // ""

Align numbers with spaces

To align float number to the right use comma „, “ option before the colon. Type comma followed by a number of spaces, e.g. „0,10:0.0 “ (this can be used only in String.Format method, not in double.ToString method). To align numbers to the left use negative number of spaces.


String .Format("{0,10:0.0}" , 123.4567); // " 123.5" String .Format("{0,-10:0.0}" , 123.4567); // "123.5 " String .Format("{0,10:0.0}" , -123.4567); // " -123.5" String .Format("{0,-10:0.0}" , -123.4567); // "-123.5 "

Custom formatting for negative numbers and zero

If you need to use custom format for negative float numbers or zero, use semicolon separator ; “ to split pattern to three sections . The first section formats positive numbers, the second section formats negative numbers and the third section formats zero. If you omit the last section, zero will be formatted using the first section.


String .Format("{0:0.00;minus 0.00;zero}" , 123.4567); // "123.46" String .Format("{0:0.00;minus 0.00;zero}" , -123.4567); // "minus 123.46" String .Format("{0:0.00;minus 0.00;zero}" , 0.0); // "zero"

Some funny examples

As you could notice in the previous example, you can put any text into formatting pattern, e.g. before an usual pattern „my text 0.0 “. You can even put any text between the zeroes, e.g. „0aaa .bbb 0 “.


String .Format("{0:my number is 0.0}" , 12.3); // "my number is 12.3" String .Format("{0:0aaa.bbb0}" , 12.3); // "12aaa.bbb3"

Те, кто пишут на C# очень хорошо знают и часто используют механизм String.Format, которого сильно не хватает в JavaScript. Несмотря на его простоту и удобство, на просторах Сети мало что можно накопать, в основном вариации на тему sprintf (привет сишникам). Достаточно давно был написан скрипт, который позволял форматировать строки на JavaScript и был похож на String.Format C#. Форматирование стало использоваться коллегами достаточно плотно в скриптах и я решил немного причесать код и опубликовать для тех, кто хочет получить String.Format в JavaScript.

Итак, основные возможности:

  • Маркеры как в C#: {0}
  • Можно задавать используемую функцию форматирования: {0:d}
  • Можно передавать параметры функции форматирования: {0:n(,2)}
  • Можно регистрировать свои функции форматирования
  • Небольшой размер - 3.5Кб в упакованном виде
  • Работает быстро
  • Работает в IE, Chrome, Firefox (проверено), теоретически ничего не мешает работать в серверном JavaScript
  • Уже реализованы и встроены функции форматирования:
    • Форматирование массивов
    • Форматирование чисел
    • Форматирование даты и времени

Использование

Использовать можно 2-мя способами:
1. Как в C#:
var s = String.Format (format, arg0[ , arg1[ , arg2[ ...] ] ] );

2. Как функция у любой строки:
var s = "format string {0}" .format (arg0[ , arg1[ , arg2[ ...] ] ] );
Правила для маркеров
{0} - значение будет преобразовано в строку по правилам JavaScript
{0:f} - значение будет преобразовано в строку с помощью функции, зарегистрированной под именем f
{0:f(p1,p2)} - значение будет преобразовано в строку с помощью функции, зарегистрированной под именем f и этой функции будут переданы параметры p1 и p2 в массиве, количество и правила для параметров зависят от самой функции, однако есть несколько общих правил:
  1. Параметры разделяются запятыми
  2. Все знаки в круглых скобках значимы т.е. для {0:f(p1,p2)} будет передано ["p1", "p2"], а в случае {0:f(p1, p2)} будет передано ["p1", " p2"]
  3. Для маскирования запятой и закрывающей круглой скобки нужно использовать слэш: {0:f(p1\, p2)} будет передано ["p1, p2"]
  4. Параметры можно пропускать: для {0:f(,p2)} будет передано ["", "p2"]
  5. Можно использовать вложенные маркеры: для {0:f({1})} будет передано ["значение_из_параметра_с_индексом_1"], в этом случае форматирование недопустимо, а значение передается то же, что было передано функции format
Функции форматирования
Все функции форматирования получают 2 параметры: значение, которое нужно отформатировать и массив параметров. Вот так рекомендуется регистрировать функции форматирования:
(function (format)
{
// Регистрация функции форматирования
// name - имя для использования в маркерах
// v - значение для форматирования, в функцию будет передано так же, как его передали в функцию format
// params - массив параметров, всегда есть, но межет быть нулевого размера
// Функция обязана вернуть строку, которая будет подставлена вместо метки
format.add (name, function (v, params)
{
return ...;
} );
} )(String.prototype.format);
Встроенные функции форматирования
В скрипте уже встроены функции форматирования для чисел, массивов и дат.

{0:n} - форматирование числа, если в функцию пришло не число, то будет выведено NaN. Вид чисел 1.11111111e+20 будет преобразован в нормальный: 111111111000000000000. Можно передавать строки с числом: "1.67" или "123.456e+2" - будет вставлено соответственно 1.67 и 12345.6.

{0:n([i][,f])} - форматирование числа с заполнением нулями до нужного числа разрядов.
i - количество разрядов для целой части, если в целой части больше разрадов, то они остаются на месте, если меньше - в начале будет вставлено нужное число нулей.
f - количество разрядов для дробной части, лишние числа будут отброшены.
Параметры можно пропускать: {0:n(,2)} - вывести число с 2-мя знаками в десятичной части.

{0:df([f])} - произвольное форматирование даты, f - строка формата с подстановками, возможные подстановки:

  • yy или yyyy - Год, всегда выводится 4 знака.
  • M или MM - Месяц, 1 или 2 знака
  • d или dd - День, 1 или 2 знака
  • H или HH - Часы, 1 или 2 знака в 24-часовом формате
  • m или mm - Минуты, 1 или 2 знака
  • s или ss - Секунды, 1 или 2 знака
  • f...ffff - Миллисекунды, от 1 до 4 знаков

Сейчас же мы поговорим о их форматировании. Потребность в форматировании строк возникает довольно часто (вывод определенного количества знаков после запятой для числа, или дата в нужом формате и. т.д.).

В Си-шарп возможностью задать форматирование обладают следующие методы:

System.String.Format
- Console.WriteLine
- StreamWriter.Write
- ToString

Методы WriteLine и Write используются для вывода информации в консоль, и при этом дают возможность отформатировать вывод. Метод Format класса String предназначен конкретно для форматирования. Он возвращает отформатированную строку. Разницы между самим форматированием для этих методов нет. Форматирование в методе ToString можно задать только для чисел и дат.

Общая структура форматирования строк имеет следующий вид:

String.Format("строка формата", arg0, arg1, …, argn);


arg0 и arg1 здесь – аргументы форматирования (числа, строки, даты, и т. д.), из которых в результате будет создана новая отформатированная строка.

Строка формата может содержать обычные символы, которые будут отображены в том виде, в котором они заданы, и команды форматирования. Команда форматирования заключается в фигурные скобки и имеет следующую структуру:

{[номер аргумента], [ширина]:[формат]}


По [номеру аргумента] указывается к какому аргументу будет применена данная команда (отсчет аргументов начинается с нуля).
[ширина] задает минимальный размер поля.
[формат] – спецификатор формата.

Параметры [ширина] и [формат] не являются обязательными.

Пример простого форматирования:

string formattedString = string.Format("Result is {0}", 5); // "Result is 5"


Здесь на место команды {0} подставляется 0-й аргумент.

int num1 = 5, num2 = 3;
string formattedString = string.Format("{0}+{1}={2}", num1, num2, num1+num2); // "5+3=8"
Console.WriteLine(formattedString);
Console.ReadLine();

Параметр "ширина"

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

Console.WriteLine("Result is {0, 6}", 1.2789);
Console.WriteLine("Result is {0, 6}", 7.54);
Console.WriteLine("Result is {0, -6}", 1.2789);
Console.WriteLine("Result is {0, -6}", 7.54);


В результате получится, что в первых двух строках числа выровнены по правому краю, в двух других по левому:

Result is 1,2789
Result is 7,54
Result is 1,2789
Result is 7,54

Встроенные форматы числовых данных

А теперь мы рассмотрим параметр команды форматирования после двоеточия – формат. Для числовых аргументов определен целый ряд форматов, все они описаны в таблице 1. Почти для всех форматов можно также задать точность. Например, формат для чисел с фиксированной точкой «f» по умолчанию выводит не больше двух знаков после точки. Чтобы задать 4 знака - нужно указать после обозначения формата необходимое число, «f4».

Таблица 1

Специальный символ Формат Описание
c/C Денежная единица
d/D Целые числа
e/E Экспоненциальные числа Указывает количество десятичных знаков
f/F Числа с фиксированной точкой Указывает количество десятичных знаков
g/G Форматы e/E и g/G Использует более короткий формат из двух: f/F и g/G
n/N Числа с фиксированной точкой с отделением групп разрядов Указывает количество десятичных знаков
p/P Проценты Умножает число на 100 и выводит со знаком процентов. Указывает количество десятичных знаков
r/R Формат кругового преобразования. Только фиксированная точка Форматирует число в строку таким образом, что его можно обратно преобразовать без потерь точности
x/X Шестнадцатеричные числа Указывает минимальное количество цифр. При необходимости добавляются нули

Пример использования некоторых из встроенных форматов:

Console.WriteLine("{0:c}", 5.50); // "5,50 грн."
Console.WriteLine("{0:c1}", 5.50); // "5,5 грн."
Console.WriteLine("{0:e}", 5.50); // "5,500000е+000"
Console.WriteLine("{0:d}", 32); // "32"
Console.WriteLine("{0:d4}", 32); // "0032"
Console.WriteLine("{0:p}", 0.55); // "55,00%"

Пользовательский формат числовых данных

В таблице 1 были описаны стандартные форматы для числовых данных, но иногда необходимо определить некоторый собственный формат. Для создания пользовательских форматов используются специальные символы (Таблица 2):

Таблица 2

Пример использования пользовательских форматов:

Console.WriteLine("{0:0000.00}", 1024.32); // "1024,32"
Console.WriteLine("{0:00000.000}", 1024.32); // "01024,320"
Console.WriteLine("{0:####.###}", 1024.32); // "1024,32"
Console.WriteLine("{0:####.#}", 1024.32); // "1024,3"
Console.WriteLine("{0:#,###.##}", 1024.32); // "1 024,32"
Console.WriteLine("{0:##%}", 0.32); // "32%"
Console.WriteLine("{0:;[####.###];ноль}", 1024.32); // " "
Console.WriteLine("{0:;[####.###];ноль}", -1024.32); // ""
Console.WriteLine("{0:;[####.###];ноль}", 0); // "ноль"

Здесь стоит отметить, что если количество цифр целой части числа больше чем количество символов «0» или «#» в формате, целая часть числа всё равно будет выводиться полностью.

Встроенные форматы даты и времени

Для работы с датой и временем существует отдельный набор стандартных форматов. Данные форматы наведены в таблице 3:

Таблица 3

Специальный символ Формат Пример
d Короткая дата 30.06.2014
D Длинная дата 30 июня 2014 г.
t Короткое время 22:30
T Длинное время 22:30:10
f Длинная дата/короткое время 30 июня 2014 г. 22:30
F Длинная дата/длинное время 30 июня 2014 г. 22:30:10
g Короткая дата/короткое время 30.06.2014 22:30
G Короткая дата/длинное время 30.06.2014 22:30:10
M/m Месяц и день июня 30
O/o Обратный 2014-06-30T22:30:10.0000000
R/r RFC1123 Mon, 30 Jun 2014 22:30:10 GMT
s Для сортировки 2014-06-30T22:30:10
u Локальное, в универсальном формате 2014-06-30 22:30:10Z
U GMT 30 июня 2014 г. 19:30:10
Y Год и месяц Июнь 2014

Пример использования стандартных форматов даты и времени:

Console.WriteLine("{0:d}", DateTime.Now); // "30.06.2014"
Console.WriteLine("{0:D}", DateTime.Now); // "30 июня 2014 р."
Console.WriteLine("{0:t}", DateTime.Now); // "2:57"
Console.WriteLine("{0:T}", DateTime.Now); // "2:57:53"
Console.WriteLine("{0:U}", DateTime.Now); // "29 июня 2014 р. 23:57:53"
Console.WriteLine("{0:Y}", DateTime.Now); // "Июнь 2014 р."

Пользовательский формат даты и времени

Как и в случае с числовыми данными, для даты и времени можно определять пользовательский формат. Для этого используются специальные символы, которые наведены в таблице 4 (на примере даты 30.06.2014 22:30:10.1234):

Таблица 4

Специальный символ Значениe Результат
y Год 0-9 4
yy Год 00-99 14
yyyy Год, 4 цифры 2014
M Месяц 1-12 6
MM Месяц 01-12 06
d День 1-31 0
dd День 01-31 30
h Час 1-12 2
hh Час 01-12 10
H Час 1-24 22
H Час 01-24 22
m Минута 0-59 30
mm Минута 00-59 30
s Секунда 0-59 10
ss Секунда 00-59 10
f – ffffff Доли секунды 12 (для ff)
F-FFFFFF Доли секунды, если они не равны 0 12 (для ff)
MMM Сокращенное имя месяца Июн
MMMM Имя месяца Июнь
ddd Сокращенное имя дня недели Пн
dddd Имя дня недели понедельник
tt Маркер для "AM" и "PM" 12-часового формата PM
zz Смещение временной зоны, короткое +03
zzz Смещение временной зоны, полное +03:00
gg Эра A.D.
: Разделитель времени 22:30:10
/ Разделитель даты 30.06.2014
\ Экранирование

Пример использования пользовательских форматов даты и времени:

Console.WriteLine("{0:y yy yyy yyyy}", DateTime.Now); // "14 14 2014 2014"
Console.WriteLine("{0:d dd ddd dddd}", DateTime.Now); // "30 30 Пн понедельник"
Console.WriteLine("{0:M MM MMM}", DateTime.Now); // "6 06 Июн"
Console.WriteLine("{0:HH.mm.ss dd-MMM-yyyy}", DateTime.Now); // "03.21.22 30-Июн-2014"
Console.WriteLine("{0:z zz zzz}", DateTime.Now); // "+3 +03 +03:00"

Форматирование с использованием метода ToString

Все правила форматирования, описанные выше, могут быть использованы в перегруженном методе ToString для чисел и дат:

Console.WriteLine(DateTime.Now.ToString("dd MMM yyyy")); // 30 Июн 2014

Региональные параметры CultureInfo

В примерах выше стандартные параметры культуры. Деньги выводились в рублях, названия месяцев, дней на русском языке. CultureInfo также влияет на разделитель в числах, количество символов после точки по умолчанию и другое. Иногда возникает потребность изменить это, и для этого используется CultureInfo . По умолчанию CultureInfo соответствует настройкам Windows (например российские региональные настройки). Чтобы задать собственную культуру при форматировании, используя метод Format , необходимо в конструктор этого метода первым аргументом передать объект CultureInfo .

В примере ниже текущий день выводится с текущими настройками CultureInfo (российскими), с английскими (английский Соединенных Штатов), и с украинскими:

string formattedString = string.Format(new System.Globalization.CultureInfo("en-US"), "{0:dddd} Money - {1:c}", DateTime.Now, 15);
Console.WriteLine("{0:dddd} Money - {1:c}", DateTime.Now, 15); // "понедельник Money - 15,00 руб."
Console.WriteLine(formattedString); // "Monday Money - $15.00"
formatedString = string.Format(new System.Globalization.CultureInfo("uk-UA"), "{0:dddd} Money - {1:c}", DateTime.Now, 15);
Console.WriteLine(formattedString); // "понеділок Money - 15,00 грн."

Домашнее задание

Есть массив дат (с временем) и массив температур, и они соответствуют друг другу. Температуры в массиве имеют вид в формате: «26.3 27.1 30 24.7 25». Необходимо вывести информацию таким образом:

Июн 30 (Пн) 09:31 > 26,3 °C
Июн 30 (Пн) 10:31 > 27,1 °C
Июн 30 (Пн) 11:31 > 30,0 °C

Дробная часть температуры должна обязательно быть длиной в один знак, даже если температура целая.



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: