Compartir a través de


Preguntas más frecuentes sobre formato String

Preguntas más frecuentes sobre el espacio de nombres de formato String.

¿Cómo se escribe una llave en formato String?
¿Produce el escape de llaves algún resultado extraño que deba conocer?
¿Cómo puedo usar el formato String para escribir algo como "{42.00}"?

Nos encanta conocer sus ideas, problemas o peticiones. Quizás esté interesado en saber por qué se ha diseñado algo de una manera en particular, la mejor manera de solucionar un problema o los motivos por los que el código que ha creado no funciona como esperaba. Además, puede enviar al equipo de BCL sus sugerencias para versiones futuras de Framework, como clases adicionales que incluir (siempre es útil describir los escenarios que necesita admitir) o API nuevas para clases existentes.

Para enviar su pregunta, simplemente envíe un correo electrónico a The BCL Team (bclpub@microsoft.com).

 


¿Cómo se escribe una llave en formato String?
Para imprimir una llave en una cadena con el formato String, use dos llaves seguidas. Esto se conoce como "escape" de la llave.

C#]string s = String.Format("{{ hello to all }}");Console.WriteLine(s);    //prints '{ hello to all }'


¿Produce el escape de llaves algún resultado extraño que deba conocer?
Se obtiene un resultado interesante al decidir usar dos llaves para imprimir una única llave en una cadena de formato.
Si desea utilizar la capacidad estándar del uso de un parámetro de referencia en formato String, escribirá este tipo de código:

[C#]int i = 42;string s = String.Format("{0}", i);   //prints '42'

Sin embargo, ¿qué sucede si desea imprimir "{42}"? Podría parecer que esta línea de código es bastante intuitiva, según el intento de escape de las llaves:

[C#]int i = 42;string s = String.Format("{{{0}}}", i);   //prints '{42}'

Ahora, sin embargo, desea sacar partido de algunas de las opciones de formato más estables disponibles y especificar un formato para la variable. Desea imprimir en formato Number, con el especificador N:

[C#]int i = 42;string s = String.Format("{0:N}", i);   //prints '42.00'

Para avanzar un poco más, imagine que desea imprimir el valor con llaves y utilizar el especificador de formato Number. Es de esperar que lo siguiente funcionase:

[C#]int i = 42;string s = String.Format("{{{0:N}}}", i);   //prints '{N}'

La cuestión es, ¿por qué fracasó el intento anterior? Hay que saber dos cosas para comprender este resultado:

  1. Al proporcionar un especificador de formato, es necesario seguir los siguientes pasos para el formato String:
    • Determine si el especificador es más largo que un carácter único: si es así, el especificador se considera como un formato personalizado. Un formato personalizado usa reemplazos adecuados para el formato, pero si no sabe qué hacer con algún carácter, simplemente lo escribirá como una literal encontrada en el formato.
      • Determine si el especificador de carácter único es un especificador compatible (como "N" para el formato Number). Si es así, aplique el formato en consecuencia. Si no, inicie una excepción ArgumnetException.
    • Mientras se intenta determinar el escape de una llave, las llaves se tratan simplemente en el orden en que se reciben. Así, "{{{" resultará en el escape de los dos primeros caracteres y se imprimirá la "{" literal, y la tercera llave comenzará la sección de formato. Según esto, en "}}}" se produce el escape de las dos primeras llaves. Por lo tanto, se escribirá una "{" literal en la cadena de formato y, a continuación, se considerará que la última llave finaliza la sección de formato.

Con esta información, podemos imaginar lo que sucede en nuestra situación "{{{0:N}}}". Se da el escape de las dos primeras llaves y, a continuación, tenemos una sección de formato. Sin embargo, después también se produce el escape de la llave de cierre, antes de cerrar la sección de formato. Así, en realidad, la sección de formato se interpreta como contenedora de "0:N}".

Ahora, el formateador observa el especificador de formato y detecta "N}" para el especificador. Esto se interpreta como formato personalizado. Ni N ni } tienen significado para un formato numérico personalizado, por lo que estos caracteres simplemente se escriben, en lugar del valor de la variable a la que se hace referencia.

Este último aspecto provoca cierta confusión, pero se aclara si se compara este comportamiento con el siguiente:

[C#]int i = 42;string s = String.Format("{0:N!}", i);   //prints 'N!'

Lo mismo ocurre en esta situación, pero la claridad es mayor, ya que no se produce ningún escape. Básicamente, el especificador de formato aparece como "N!", lo que se interpreta como formato personalizado (más largo que un carácter), y ya que el formato personalizado no tiene nada que ver con números, N! sólo se usa para el valor.


¿Cómo puedo usar el formato String para escribir algo como "{42.00}"?
El escape de llaves provoca algunos resultados extraños, por lo que esto no suele funcionar:

[C#]int i = 42;string s = String.Format("{{{0:N}}}", i);   //prints '{N}'

Entonces, la pregunta es la siguiente: ¿Cómo se puede escribir {42.00}?

Podemos responder esta pregunta con algunas alternativas, para ver si puede identificar la solución más estable y fácil. "Fácil" en cuanto a la sencillez de escritura y "estable" en cuanto a trabajar bajo diferentes condiciones (para resolver esta parte, necesitará conocimientos sobre opciones de formato de cadenas diferentes).

Se presentan tres opciones:

  1. [C#] int i = 42; string s = String.Format("{0}{1}{2}", "{", i, "}");   //prints '{42.00}'

     

  2. [C#] int i = 42; string s = String.Format("{{{0}}}", i.ToString("N")) ;   //prints '{42.00}'

     

  3. [C#] int i = 42; string s = String.Format("{0:{{0.00}}}", i);   //prints '{42.00}'

     

¿Cuál de las tres es la mejor? Bien, acertó, es una pregunta con truco. A primera vista, la opción 2 parece la más correcta. En realidad, es la que ofrece una lectura óptima (no implica el formato independiente de la opción 1 y es bastante más estable que la opción 3). Con la opción 3 se obtiene el mismo resultado, pero si cambiamos la referencia cultural del equipo, es posible que aparezcan resultados diferentes. O bien, si se usa un valor diferente para i, por ejemplo, 42000, se observa un comportamiento diferente. Así, todo apunta a que la opción 2 es la apropiada.

Pero, cuidado... La opción 2 es una buena elección si se está usando simplemente el formato anterior. ¿Qué ocurre si se usa la justificación izquierda en la cadena de formato para cambiar lo que aparece? Por ejemplo:

[C#]int i = 42;string s = String.Format("{0,-7:N}", i);   //prints '42.00  ', ",-7" left-justifies the string

Ahora, imagine que probamos las tres líneas de código: recuerde que estamos intentando imprimir "{42.00}", con espacios finales, no en medio:

[C#]int i = 42;string s1 = String.Format("{{{0,-7:N}}}", i);   //prints '{42.00  }'string s2 = String.Format("{{{0,-7}}}", i.ToString("N")) ;   //prints '{42.00  }'string s3 = String.Format("{0,-9:{{0.00}}}", i);   //prints '{42.00}  '

Aquí se puede ver, de manera decepcionante, que con la opción 2 no obtuvimos el resultado correcto. La única que sirve es la opción 3. Y recuerde que si hubiéramos usado el valor 42000, la opción 3 tampoco habría funcionado.

La buena noticia es que la opción 3 es más estable de lo que parece a primera vista, simplemente hay que saber qué formato personalizado se debe usar. En este caso, podemos mejorar la opción 3 mediante lo siguiente:

[C#]int i = 42000;string s = String.Format("{0,-15:{{#,##0.00}}}", i);   //prints '{42,000.00}     '

RESUMEN
Si intenta aplicar formato a algún valor entre llaves literales, le sugerimos lo siguiente:

  • Si no necesita justificar el resultado, use String.Format("{{{0}}}", variable.ToString(formatSpecifier)), es decir, la opción 2 anterior.
    • Si necesita justificar el resultado, use la opción 3 anterior, es decir, String.Format("{0,-7:{{customFormat}}}", variable), donde customFormat es un formato personalizado apropiado.