Поделиться через


Составное форматирование

Функция составного форматирования .NET принимает список объектов и составную строку форматирования в качестве входных данных. Строка составного формата состоит из фиксированного текста, перемешанного с индексированными заполнителями, называемыми элементами форматирования. Эти элементы формата соответствуют объектам в списке. Операция форматирования создает результирующую строку, состоящую из исходного фиксированного текста, в который включено строковое представление объектов из списка.

Это важно

Вместо использования составных строк форматирования можно использовать интерполированные строки , если язык и его версия поддерживают их. Интерполированная строка содержит интерполированные выражения. Each interpolated expression is resolved with the expression's value and included in the result string when the string is assigned. Дополнительные сведения см. в разделе "Интерполяция строк( справочник по C#) и интерполированные строки (справочник по Visual Basic)".

Следующие методы поддерживают функцию составного форматирования:

Строка составного формата

Строка составного формата и список объектов используются в качестве аргументов методов, поддерживающих функцию составного форматирования. Строка составного формата состоит из нуля или более фрагментов фиксированного текста, перемешанных с одним или несколькими элементами формата. Фиксированный текст — это любая выбранная строка, и каждый элемент формата соответствует объекту или прямоугольной структуре в списке. Строковое представление каждого объекта заменяет соответствующий элемент формата.

Рассмотрим следующий Format фрагмент кода:

string.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now);
String.Format("Name = {0}, hours = {1:hh}", "Fred", DateTime.Now)

Фиксированный текст — это Name = и , hours = . Элементы {0}формата, индекс которых 0 соответствует объекту name, и {1:hh}индекс которого 1 соответствует объекту DateTime.Now.

Format item syntax

Каждый элемент форматирования имеет следующий вид и состоит из следующих компонентов:

{index[,width][:formatString]}

The matching braces ({ and }) are required.

Компонент индекса

The mandatory index component, which is also called a parameter specifier, is a number starting from 0 that identifies a corresponding item in the list of objects. То есть элемент формата, чья спецификация параметра — 0, форматирует первый объект в списке. Элемент формата, параметрический спецификатор которого указан как 1, форматирует второй объект в списке и так далее. В следующем примере содержатся четыре описателя параметров, нумерованные от нуля до трех, для представления простых чисел меньше 10:

string primes = string.Format("Four prime numbers: {0}, {1}, {2}, {3}",
                              2, 3, 5, 7);
Console.WriteLine(primes);

// The example displays the following output:
//      Four prime numbers: 2, 3, 5, 7
Dim primes As String = String.Format("Four prime numbers: {0}, {1}, {2}, {3}",
                                      2, 3, 5, 7)
Console.WriteLine(primes)

'The example displays the following output
'     Four prime numbers 2, 3, 5, 7

Несколько элементов формата могут ссылаться на один и тот же элемент в списке объектов, указав один и тот же описатель параметров. Например, можно отформатировать одно числовое значение в шестнадцатеричном, научном и числовом формате, указав строку составного формата, например "0x{0:X} {0:E} {0:N}"в следующем примере:

string multiple = string.Format("0x{0:X} {0:E} {0:N}",
                                Int64.MaxValue);
Console.WriteLine(multiple);

// The example displays the following output:
//      0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00
Dim multiple As String = String.Format("0x{0:X} {0:E} {0:N}",
                                       Int64.MaxValue)
Console.WriteLine(multiple)

'The example displays the following output
'     0x7FFFFFFFFFFFFFFF 9.223372E+018 9,223,372,036,854,775,807.00

Каждый элемент формата может ссылаться на любой объект в списке. Например, если есть три объекта, можно отформатировать второй, первый и третий объект, указав строку составного формата, например {1} {0} {2}. Объект, на который не ссылается элемент формата, игнорируется. Выбрасывается FormatException во время выполнения, если описатель параметра назначает элемент, выходящий за пределы списка объектов.

Width component

The optional width component is a signed integer indicating the preferred formatted field width. If the value of width is less than the length of the formatted string, width is ignored, and the length of the formatted string is used as the field width. The formatted data in the field is right-aligned if width is positive and left-aligned if width is negative. If padding is necessary, white space is used. The comma is required if width is specified.

В следующем примере определяются два массива, один из них содержит имена сотрудников и другой, содержащий часы, которые они работали в течение двух недель. The composite format string left-aligns the names in a 20-character field and right-aligns their hours in a 5-character field. Строка стандартного формата N1 форматирует часы с одной дробной цифрой.

string[] names = { "Adam", "Bridgette", "Carla", "Daniel",
                   "Ebenezer", "Francine", "George" };
decimal[] hours = { 40, 6.667m, 40.39m, 82,
                    40.333m, 80, 16.75m };

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours");

for (int counter = 0; counter < names.Length; counter++)
    Console.WriteLine("{0,-20} {1,5:N1}", names[counter], hours[counter]);

// The example displays the following output:
//      Name                 Hours
//      
//      Adam                  40.0
//      Bridgette              6.7
//      Carla                 40.4
//      Daniel                82.0
//      Ebenezer              40.3
//      Francine              80.0
//      George                16.8
Dim names As String() = {"Adam", "Bridgette", "Carla", "Daniel",
                         "Ebenezer", "Francine", "George"}

Dim hours As Decimal() = {40, 6.667D, 40.39D, 82,
                          40.333D, 80, 16.75D}

Console.WriteLine("{0,-20} {1,5}\n", "Name", "Hours")

For counter = 0 To names.Length - 1
    Console.WriteLine("{0,-20} {1,5:N1}", names(counter), hours(counter))
Next

'The example displays the following output
'     Name                 Hours
'     
'     Adam                  40.0
'     Bridgette              6.7
'     Carla                 40.4
'     Daniel                82.0
'     Ebenezer              40.3
'     Francine              80.0
'     George                16.8

Форматирование компонента строки

The optional formatString component is a format string that's appropriate for the type of object being formatted. Можно указать следующее:

  • Строка стандартного или настраиваемого числового формата, если соответствующий объект является числовым значением.
  • Стандартная или настраиваемая строка формата даты и времени, если соответствующий DateTime объект является объектом.
  • An enumeration format string if the corresponding object is an enumeration value.

If formatString isn't specified, the general ("G") format specifier for a numeric, date and time, or enumeration type is used. The colon is required if formatString is specified.

В следующей таблице перечислены типы или категории типов в библиотеке классов .NET, поддерживающие предопределенный набор строк форматирования, а также ссылки на статьи, которые перечисляют поддерживаемые строки формата. Форматирование строк — это расширяемый механизм, позволяющий определить новые строки формата для всех существующих типов и определить набор строк форматирования, поддерживаемых приложением.

Дополнительные сведения см. в статьях интерфейса IFormattable и ICustomFormatter.

Тип или категория типа Смотри
Типы даты и времени (DateTime, DateTimeOffset) Стандартные строки формата даты и времени

Настраиваемые строки формата даты и времени
Типы перечисления (все типы, производные от System.Enum) Enumeration Format Strings
Числовые типы (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) Стандартные строки в числовом формате

Настраиваемые числовые строковые форматы
Guid Guid.ToString(String)
TimeSpan Строки стандартного формата TimeSpan

Настраиваемые строки форматирования "TimeSpan"

Escaping braces

Opening and closing braces are interpreted as starting and ending a format item. To display a literal opening brace or closing brace, you must use an escape sequence. Укажите две открывающие фигурные скобки ({{) в фиксированном тексте, чтобы отобразить одну открывающую скобку ({) или две закрывающие фигурные скобки (}}), чтобы отобразить одну закрывающую скобку (}).

Escaped braces with a format item are parsed differently between .NET and .NET Framework.

.NET

Braces can be escaped around a format item. Например, рассмотрим элемент {{{0:D}}}формата, который предназначен для отображения открывающей фигурной скобки, числового значения, отформатированного в виде десятичного числа, и закрывающей фигурной скобки. Элемент формата интерпретируется следующим образом:

  1. The first two opening braces ({{) are escaped and yield one opening brace.
  2. Следующие три символа ({0:) интерпретируются как начало элемента формата.
  3. Следующий символ (D) интерпретируется как описатель стандартного числового формата десятичного стандарта.
  4. Следующая фигурная скобка (}) интерпретируется как конец элемента формата.
  5. The final two closing braces are escaped and yield one closing brace.
  6. Конечный результат, отображаемый, — литеральная строка {6324}.
int value = 6324;
string output = string.Format("{{{0:D}}}", value);

Console.WriteLine(output);
// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}", value)

Console.WriteLine(output)

'The example displays the following output
'      {6324}

Платформа .NET Framework

Braces in a format item are interpreted sequentially in the order they're encountered. Interpreting nested braces isn't supported.

The way escaped braces are interpreted can lead to unexpected results. Например, рассмотрим элемент {{{0:D}}}формата, который предназначен для отображения открывающей фигурной скобки, числового значения, отформатированного в виде десятичного числа, и закрывающей фигурной скобки. Однако элемент формата интерпретируется следующим образом:

  1. The first two opening braces ({{) are escaped and yield one opening brace.
  2. Следующие три символа ({0:) интерпретируются как начало элемента формата.
  3. The next character (D) would be interpreted as the Decimal standard numeric format specifier, but the next two escaped braces (}}) yield a single brace. Так как результирующая строка (D}) не является стандартным числовым описателем, результирующая строка интерпретируется как настраиваемая строка форматирования, которая означает отображение литеральной строки D}.
  4. Последняя фигурная скобка (}) интерпретируется как конец элемента формата.
  5. Конечный результат, отображаемый, — литеральная строка {D}. Числовое значение, которое должно быть отформатировано, не отображается.
int value = 6324;
string output = string.Format("{{{0:D}}}",
                              value);
Console.WriteLine(output);

// The example displays the following output:
//       {D}
Dim value As Integer = 6324
Dim output As String = String.Format("{{{0:D}}}",
                                     value)
Console.WriteLine(output)

'The example displays the following output:
'      {D}

One way to write your code to avoid misinterpreting escaped braces and format items is to format the braces and format items separately. That is, in the first format operation, display a literal opening brace. In the next operation, display the result of the format item, and in the final operation, display a literal closing brace. В следующем примере показан такой подход:

int value = 6324;
string output = string.Format("{0}{1:D}{2}",
                             "{", value, "}");
Console.WriteLine(output);

// The example displays the following output:
//       {6324}
Dim value As Integer = 6324
Dim output As String = String.Format("{0}{1:D}{2}",
                                     "{", value, "}")
Console.WriteLine(output)

'The example displays the following output:
'      {6324}

Порядок обработки

Если вызов метода составного форматирования включает аргумент IFormatProvider, значение которого не является null, среда выполнения вызывает его метод IFormatProvider.GetFormat для запроса реализации ICustomFormatter. Если метод может вернуть реализацию ICustomFormatter , он кэширован во время вызова метода составного форматирования.

Каждое значение в списке параметров, соответствующее элементу формата, преобразуется в строку следующим образом:

  1. Если значение, которое должно быть отформатировано null, возвращается пустая строка String.Empty .

  2. Если реализация ICustomFormatter доступна, среда выполнения вызывает её метод Format. Среда выполнения передает значение элемента formatString формата (или null если оно отсутствует) методу. The runtime also passes the IFormatProvider implementation to the method. Если вызов метода ICustomFormatter.Format возвращается null, выполнение переходит к следующему шагу. Otherwise, the result of the ICustomFormatter.Format call is returned.

  3. Если значение реализует IFormattable интерфейс, вызывается метод интерфейса ToString(String, IFormatProvider) . If one is present in the format item, the formatString value is passed to the method. Otherwise, null is passed. Аргумент IFormatProvider определяется следующим образом:

    • Для числового значения, если вызывается составной метод форматирования с ненулевым IFormatProvider аргументом, среда выполнения запрашивает NumberFormatInfo объект из метода IFormatProvider.GetFormat . If it's unable to supply one, if the value of the argument is null, or if the composite formatting method doesn't have an IFormatProvider parameter, the NumberFormatInfo object for the current culture is used.

    • Для значения даты и времени, если вызывается составной метод форматирования с ненулевым IFormatProvider аргументом, среда выполнения запрашивает DateTimeFormatInfo объект из метода IFormatProvider.GetFormat . In the following situations, the DateTimeFormatInfo object for the current culture is used instead:

    • Для объектов других типов, если метод составного форматирования вызывается с аргументом IFormatProvider , его значение передается непосредственно в реализацию IFormattable.ToString . В противном случае null передается реализации IFormattable.ToString.

  4. The type's parameterless ToString method, which either overrides Object.ToString() or inherits the behavior of its base class, is called. В этом случае строка формата, указанная formatString компонентом в элементе форматирования, если она присутствует, игнорируется.

Выравнивание применяется после выполнения предыдущих шагов.

Примеры кода

В следующем примере показана одна строка, созданная с помощью составного форматирования, а другая создана с помощью метода объекта ToString . Оба типа форматирования создают эквивалентные результаты.

string formatString1 = string.Format("{0:dddd MMMM}", DateTime.Now);
string formatString2 = DateTime.Now.ToString("dddd MMMM");
Dim formatString1 As String = String.Format("{0:dddd MMMM}", DateTime.Now)
Dim formatString2 As String = DateTime.Now.ToString("dddd MMMM")

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

Console.WriteLine предоставляет те же функции, что и String.Format. Единственное различие между двумя методами заключается в том, что String.Format возвращает результат в виде строки, а Console.WriteLine результат записывается в выходной поток, связанный с Console объектом. В следующем примере метод Console.WriteLine используется для форматирования значения myNumber в денежное выражение.

int myNumber = 100;
Console.WriteLine($"{myNumber:C}");

// The example displays the following output
// if en-US is the current culture:
//        $100.00
Dim myNumber As Integer = 100
Console.WriteLine("{0:C}", myNumber)

'The example displays the following output
'if en-US Is the current culture:
'       $100.00

В следующем примере показано форматирование нескольких объектов, включая форматирование одного объекта двумя способами.

string myName = "Fred";
Console.WriteLine(string.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now));

// Depending on the current time, the example displays output like the following:
//        Name = Fred, hours = 11, minutes = 30
Dim myName As String = "Fred"
Console.WriteLine(String.Format("Name = {0}, hours = {1:hh}, minutes = {1:mm}",
                                myName, DateTime.Now))
'Depending on the current time, the example displays output Like the following:
'       Name = Fred, hours = 11, minutes = 30

The following example demonstrates the use of width in formatting. Аргументы, отформатированные, помещаются между символами вертикальной полосы (|), чтобы выделить результирующее выравнивание.

string firstName = "Fred";
string lastName = "Opals";
int myNumber = 100;

string formatFirstName = string.Format("First Name = |{0,10}|", firstName);
string formatLastName = string.Format("Last Name =  |{0,10}|", lastName);
string formatPrice = string.Format("Price =      |{0,10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);
Console.WriteLine();

formatFirstName = string.Format("First Name = |{0,-10}|", firstName);
formatLastName = string.Format("Last Name =  |{0,-10}|", lastName);
formatPrice = string.Format("Price =      |{0,-10:C}|", myNumber);
Console.WriteLine(formatFirstName);
Console.WriteLine(formatLastName);
Console.WriteLine(formatPrice);

// The example displays the following output on a system whose current
// culture is en-US:
//     First Name = |      Fred|
//     Last Name =  |     Opals|
//     Price =      |   $100.00|
//
//     First Name = |Fred      |
//     Last Name =  |Opals     |
//     Price =      |$100.00   |
Dim firstName As String = "Fred"
Dim lastName As String = "Opals"
Dim myNumber As Integer = 100

Dim formatFirstName As String = String.Format("First Name = |{0,10}|", firstName)
Dim formatLastName As String = String.Format("Last Name =  |{0,10}|", lastName)
Dim formatPrice As String = String.Format("Price =      |{0,10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)
Console.WriteLine()

formatFirstName = String.Format("First Name = |{0,-10}|", firstName)
formatLastName = String.Format("Last Name =  |{0,-10}|", lastName)
formatPrice = String.Format("Price =      |{0,-10:C}|", myNumber)
Console.WriteLine(formatFirstName)
Console.WriteLine(formatLastName)
Console.WriteLine(formatPrice)

'The example displays the following output on a system whose current
'culture Is en-US:
'    First Name = |      Fred|
'    Last Name =  |     Opals|
'    Price =      |   $100.00|
'
'    First Name = |Fred      |
'    Last Name =  |Opals     |
'    Price =      |$100.00   |

См. также