Udostępnij za pośrednictwem


Formatowanie złożone

Funkcja formatowania złożonego platformy .NET przyjmuje listę obiektów i ciąg formatu złożonego jako dane wejściowe. Ciąg formatu złożonego składa się ze stałego tekstu przeplatanego indeksowanymi symbolami zastępczymi, nazywanymi elementami formatu. Te elementy formatu odpowiadają obiektom na liście. Operacja formatowania zwraca ciąg wynikowy, który składa się z oryginalnego stałego tekstu zmieszanego z ciągiem reprezentującym obiekty na liście.

Ważne

Zamiast używać ciągów formatu złożonego, można użyć ciągów interpolowanych , jeśli używany język i jego wersja obsługują te ciągi. Ciąg interpolowany zawiera wyrażenia interpolowane. Każde wyrażenie interpolowane jest rozpoznawane przy użyciu wartości wyrażenia i uwzględniane w ciągu wynikowym po przypisaniu ciągu. Aby uzyskać więcej informacji, zobacz Interpolacja ciągów (odwołanie w C#) i ciągi interpolowane (odwołanie w języku Visual Basic).

Następujące metody obsługują funkcję formatowania złożonego:

Ciąg formatu złożonego

Ciąg formatu złożonego i lista obiektów są używane jako argumenty metod, które obsługują funkcję formatowania złożonego. Ciąg formatu złożonego składa się z zera lub więcej fragmentów stałego tekstu połączonych z co najmniej jednym elementem formatującym. Stały tekst to dowolny wybrany ciąg, a każdy element formatu odpowiada strukturze obiektu lub pola na liście. Reprezentacja ciągu każdego obiektu zastępuje odpowiedni element formatu.

Rozważmy następujący Format fragment kodu:

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

Stały tekst to Name = i , hours = . Elementy formatu to {0}, których indeks 0 odpowiada obiektowi name, i {1:hh}, którego indeks 1 odpowiada obiektowi DateTime.Now.

Formatowanie składni elementu

Każdy element formatu ma następującą postać i składa się z następujących składników:

{index[,width][:formatString]}

Pasujące nawiasy klamrowe ({ i }) są wymagane.

Składnik indeksu

Obowiązkowy index składnik, który jest również nazywany specyfikatorem parametru, jest liczbą rozpoczynającą się od 0, która identyfikuje odpowiedni element na liście obiektów. Oznacza to, że element formatu, którego specyfikator parametru jest 0 formatuje pierwszy obiekt na liście. Element formatu, którego specyfikator parametru jest 1 formatuje drugi obiekt na liście itd. Poniższy przykład zawiera cztery specyfikatory parametrów, ponumerowane zero do trzech, aby reprezentować liczby pierwsze mniejsze niż 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

Wiele elementów formatu może odwoływać się do tego samego elementu na liście obiektów, określając ten sam specyfikator parametrów. Na przykład można sformatować tę samą wartość liczbową w formacie szesnastkowym, naukowym i liczbowym, określając ciąg formatu złożonego, taki jak "0x{0:X} {0:E} {0:N}", jak pokazano w poniższym przykładzie:

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

Każdy element formatu może odwoływać się do dowolnego obiektu na liście. Jeśli na przykład istnieją trzy obiekty, możesz sformatować drugi, pierwszy i trzeci obiekt, określając ciąg formatu złożonego, taki jak {1} {0} {2}. Obiekt, do którego nie odwołuje się element formatu, jest ignorowany. FormatException występuje w czasie wykonywania, jeśli specyfikator parametru odnosi się do elementu poza zakresem listy obiektów.

Składnik szerokości

Składnik opcjonalny width to podpisana liczba całkowita wskazująca preferowaną sformatowaną szerokość pola. Jeśli wartość parametru width jest mniejsza niż długość sformatowanego ciągu, width jest ignorowana, a długość sformatowanego ciągu jest używana jako szerokość pola. Sformatowane dane w polu są wyrównane do prawej, jeśli width jest dodatnie i wyrównane do lewej, jeśli width jest ujemne. Jeśli dopełnienie jest konieczne, używany jest biały znak. Przecinek jest wymagany, jeśli width jest określony.

W poniższym przykładzie zdefiniowano dwie tablice, jedną zawierającą nazwy pracowników, a drugą zawierającą godziny pracy w ciągu dwóch tygodni. Ciąg formatu składanego wyrównuje nazwy do lewej w polu o szerokości 20 znaków i wyrównuje ich godziny do prawej w polu o szerokości 5 znaków. Standardowy ciąg formatu "N1" formatuje godziny z jedną cyfrą ułamkową.

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

Formatowanie składnika ciągu

Składnik opcjonalny formatString jest ciągiem formatu, który jest odpowiedni dla typu sformatowanego obiektu. Możesz określić:

  • Standardowy lub niestandardowy ciąg formatu liczbowego, jeśli odpowiadający mu obiekt jest wartością liczbową.
  • Standardowy lub niestandardowy ciąg formatu daty i godziny, jeśli odpowiedni obiekt jest obiektem DateTime .
  • Ciąg formatu wyliczenia, jeśli odpowiedni obiekt jest wartością wyliczenia.

Jeśli formatString nie jest określony, używany jest ogólny ("G") specyfikator formatu dla typu liczbowego, daty i godziny lub wyliczenia. Dwukropek jest wymagany, jeśli formatString jest określony.

W poniższej tabeli wymieniono typy lub kategorie typów w bibliotece klas platformy .NET, które obsługują wstępnie zdefiniowany zestaw ciągów formatu, i zawiera linki do artykułów, które zawierają listę obsługiwanych ciągów formatu. Formatowanie ciągów to rozszerzalny mechanizm, który umożliwia definiowanie nowych ciągów formatu dla wszystkich istniejących typów oraz definiowanie zestawu ciągów formatu obsługiwanych przez typ zdefiniowany przez aplikację.

Aby uzyskać więcej informacji, zobacz artykuły o interfejsie IFormattable i ICustomFormatter.

Typ lub kategoria typu Zobacz
Typy dat i godzin (DateTime, DateTimeOffset) Standardowe ciągi formatu data i godzina

Niestandardowe ciągi formatu daty i godziny
Typy wyliczenia (wszystkie typy pochodzące z System.Enum) Ciągi formatu enumeracji
Typy liczbowe (BigInteger, Byte, Decimal, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, UInt64) Standardowe ciągi formatów liczbowych

Niestandardowe ciągi formatujące liczby
Guid Guid.ToString(String)
TimeSpan ciągi formatu standardowego TimeSpan

niestandardowe ciągi formatu TimeSpan

Ucieczka nawiasów klamrowych

Otwierające i zamykające nawiasy klamrowe oznaczają początek i koniec elementu formatu. Aby wyświetlić dosłowny nawias klamrowy otwierający lub zamykający, należy użyć sekwencji ucieczki. Określ dwa otwierające nawiasy klamrowe ({{) w stałym tekście, aby wyświetlić jeden otwierający nawias klamrowy ({) lub dwa zamykające nawiasy klamrowe (}}), aby wyświetlić jeden zamykający nawias klamrowy (}).

Nawiasy klamrowe z elementem formatu są analizowane inaczej między platformami .NET i .NET Framework.

.SIEĆ

Nawiasy klamrowe można unikać wokół elementu formatu. Rozważmy na przykład element formatu {{{0:D}}}, który ma na celu pokazanie otwierającego nawiasu klamrowego, wartości liczbowej sformatowanej jako liczba dziesiętna oraz zamykającego nawiasu klamrowego. Element formatu jest interpretowany w następujący sposób:

  1. Pierwsze dwa początkowe nawiasy klamrowe ({{) są zescapowane i dają jeden otwierający nawias klamrowy.
  2. Następne trzy znaki ({0:) są interpretowane jako początek elementu formatu.
  3. Następny znak (D) jest interpretowany jako specyfikator standardowego formatu liczbowego w systemie dziesiętnym.
  4. Następny nawias klamrowy (}) jest interpretowany jako koniec elementu formatu.
  5. Ostatnie dwa nawiasy klamrowe zamykające są ucieczone i dają jeden nawias klamrowy zamykający.
  6. Wynik końcowy, który jest wyświetlany, to ciąg znaków literału {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}

Środowisko .NET Framework

Nawiasy klamrowe w elemencie formatu są interpretowane sekwencyjnie w kolejności ich napotkania. Interpretowanie zagnieżdżonych nawiasów klamrowych nie jest obsługiwane.

Sposób interpretacji unikniętych nawiasów klamrowych może prowadzić do nieoczekiwanych wyników. Rozważmy na przykład element formatu {{{0:D}}}, który ma na celu pokazanie otwierającego nawiasu klamrowego, wartości liczbowej sformatowanej jako liczba dziesiętna oraz zamykającego nawiasu klamrowego. Jednak element formatu jest interpretowany w następujący sposób:

  1. Pierwsze dwa początkowe nawiasy klamrowe ({{) są zescapowane i dają jeden otwierający nawias klamrowy.
  2. Następne trzy znaki ({0:) są interpretowane jako początek elementu formatu.
  3. Następny znak (D) mógłby być zinterpretowany jako specyfikator formatu dziesiętnego, ale następne dwa nawiasy klamrowe (}}) dają pojedynczy nawias klamrowy. pl-PL: Ponieważ ciąg wynikowy (D}) nie jest standardowym specyfikatorem formatu liczbowego, ciąg ten jest interpretowany jako ciąg formatu niestandardowego, który oznacza wyświetlanie dosłownego ciągu D}.
  4. Ostatni nawias klamrowy (}) jest interpretowany jako koniec elementu formatu.
  5. Wynik końcowy, który jest wyświetlany, to ciąg znaków literału {D}. Wartość liczbowa, która miała zostać sformatowana, nie jest wyświetlana.
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}

Jednym ze sposobów napisania kodu, aby uniknąć błędnej interpretacji klamer i elementów formatu, jest oddzielne formatowanie klamer i elementów. Oznacza to, że w pierwszej operacji formatowania wyświetl dosłownie otwierający nawias klamrowy. W następnej operacji wyświetl wynik elementu formatu, a w końcowej operacji wyświetl dosłowny zamykający nawias klamrowy. Poniższy przykład ilustruje to podejście:

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}

Przetwarzanie zamówienia

Jeśli wywołanie metody formatowania złożonego zawiera argument IFormatProvider, którego wartość nie jest null, środowisko uruchomieniowe wywołuje metodę IFormatProvider.GetFormat w celu zażądania implementacji ICustomFormatter. Jeśli metoda może zwrócić implementację ICustomFormatter , jest buforowana podczas wywołania metody formatowania złożonego.

Każda wartość na liście parametrów odpowiadająca elementowi formatu jest konwertowana na ciąg w następujący sposób:

  1. Jeśli wartość do sformatowania to null, zwracany jest pusty ciąg String.Empty .

  2. Jeśli implementacja ICustomFormatter jest dostępna, środowisko uruchomieniowe wywołuje jego Format metodę. Środowisko uruchomieniowe przekazuje wartość elementu formatString formatu (lub null jeśli nie jest obecna) do metody . Środowisko uruchomieniowe przekazuje również implementację IFormatProvider do metody . Jeśli wywołanie metody ICustomFormatter.Format zwróci null, wykonanie przejdzie do następnego kroku. W przeciwnym razie zwracany jest wynik ICustomFormatter.Format wywołania.

  3. Jeśli wartość implementuje IFormattable interfejs, wywoływana jest metoda interfejsu ToString(String, IFormatProvider) . Jeśli element formatu jest obecny, wartość formatString jest przekazywana do metody. W przeciwnym razie, null jest przekazywany. Argument IFormatProvider jest określany w następujący sposób:

  4. Wywoływana jest metoda typu bezparametrowego ToString, która zastępuje Object.ToString() lub dziedziczy zachowanie klasy bazowej. W takim przypadku ciąg formatu określony przez komponent formatString w elemencie formatu, jeśli jest obecny, jest ignorowany.

Wyrównanie jest stosowane po wykonaniu poprzednich kroków.

Przykłady kodu

W poniższym przykładzie pokazano jeden ciąg utworzony przy użyciu formatowania złożonego, a drugi utworzony przy użyciu metody obiektu ToString . Oba typy formatowania generują równoważne wyniki.

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")

Zakładając, że bieżący dzień to czwartek w maju, wartość obu ciągów w poprzednim przykładzie jest Thursday May w kulturze amerykańsko-angielskiej.

Console.WriteLine uwidacznia tę samą funkcjonalność co String.Format. Jedyną różnicą między dwiema metodami jest to, że String.Format zwraca jego wynik jako ciąg, podczas gdy Console.WriteLine zapisuje wynik do strumienia wyjściowego skojarzonego z obiektem Console . W poniższym przykładzie użyto metody Console.WriteLine do sformatowania wartości myNumber na wartość walutową.

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

W poniższym przykładzie pokazano formatowanie wielu obiektów, w tym formatowanie jednego obiektu na dwa różne sposoby:

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

W poniższym przykładzie pokazano użycie szerokości w formatowaniu. Argumenty sformatowane są umieszczane między pionowymi znakami paska (|), aby wyróżnić wynikowe wyrównanie.

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   |

Zobacz też