Cómo formatear una cadena en Java con ejemplos

C

Introducción

Hay varias formas de formatear cadenas en Java. Algunos de ellos son de la vieja escuela y se tomaron prestados directamente de viejos clásicos (como printfde C), mientras que otros están más en el espíritu de la programación orientada a objetos, como la MessageFormatclase.

En este artículo, pasaremos por alto varios de estos enfoques. Mostraremos algunos detalles de cómo se puede utilizar cada una de las técnicas y en qué circunstancias. Con este conocimiento, sabrá cómo abordar el formato de cadenas y cuál de las técnicas utilizar.

System.out.printf ()

Comencemos con el viejo clásico printf(). Como se mencionó anteriormente, printf()proviene del lenguaje de programación C y significa formato de impresión. printf()Usos bajo el capó, de los java.util.Formatterque hablaremos más adelante.

La forma en que printf()funciona se puede explicar por sus argumentos. La forma más común de uso printf()es la siguiente:

System.out.printf(String format, String... arguments);

Podemos ver que el método espera un formaty un vararg arguments. El formatargumento define la forma en que desea que se formatee la cadena: una plantilla para el resultado final.

Por ejemplo, es posible que desee imprimir un número decimal con exactamente siete lugares decimales o un número en representación hexadecimal. O puede tener un mensaje predefinido para saludar a los usuarios, pero le gustaría formatearlo para incluir el nombre de usuario.

El argumentsvararg espera convenientemente los argumentos (es decir, valores) para la plantilla String. Por ejemplo, si la plantilla tiene marcadores de posición para dos números, el printf()método también esperará dos números como arguments:

System.out.printf("%d %d", 42, 23);

Hemos puesto dos %dsímbolos en la plantilla String. Estos dos símbolos representan marcadores de posición para un cierto tipo de valor. Por ejemplo, %des un marcador de posición para un valor numérico decimal. Como tenemos dos de ellos, tenemos que pasar dos argumentos que se correspondan con valores numéricos, como 42y 23.

Ejecutar este código producirá:

42 23

Especificadores de formato

Con printf(), puede imprimir valores como números, cadenas, fechas, etc. Para que el método sepa qué es exactamente lo que está intentando imprimir, debe proporcionar un especificador de formato para cada uno de los valores. Echemos un vistazo a un ejemplo:

System.out.printf("Hello, %s!", "reader");

Si se ejecuta, este código se imprimirá Hello, readeren la consola. El %ssímbolo representa un especificador de formato para cadenas, similar a cómo %drepresenta un especificador de formato para números decimales.

Hay muchos especificadores de formato que podemos utilizar. Éstos son algunos de los más comunes:

  • % c – Carácter
  • % d – Número decimal (base 10)
  • % e – Número de punto flotante exponencial
  • % f : número de coma flotante
  • % i – Entero (base 10)
  • % o – Número octal (base 8)
  • % s : cadena
  • % u : número decimal sin signo (entero)
  • % x – Número hexadecimal (base 16)
  • % t – Fecha / hora
  • % n : nueva línea

Si queremos imprimir, por ejemplo, un carácter y un número octal, usaríamos especificadores %cy %o, respectivamente. Puede notar algo inusual: el especificador de nueva línea. Si no está acostumbrado al printf()comportamiento de C, puede parecer un poco extraño tener que especificar cosas como esta.

Bueno, printf()no escribe una nueva línea por defecto. De hecho, no hace casi nada por defecto. Básicamente, si quieres que suceda algo, tienes que hacerlo tú mismo.

Es decir, si tenemos varias printf()declaraciones sin un especificador de nueva línea:

System.out.printf("Hello, %s!", "Michael Scott");
System.out.printf("Hello, %s!", "Jim");
System.out.printf("Hello, %s!", "Dwight");

El resultado sería:

Hello, Michael Scott!Hello, Jim!Hello, Dwight!

Sin embargo, si incluimos el carácter de nueva línea:

System.out.printf("Hello, %s!%n", "Michael Scott");
System.out.printf("Hello, %s!%n", "Jim");
System.out.printf("Hello, %s!%n", "Dwight");

Entonces el resultado sería:

Hello, Michael Scott!
Hello, Jim!
Hello, Dwight!

Nota: %n es un formato especial que puede ser uno rno solo n. nes el símbolo de nueva línea real, mientras que res el símbolo de retorno de carro. Por lo general, se recomienda su uso, nya que funciona como se espera en todos los sistemas, a diferencia de lo %nque puede entenderse como cualquiera de los dos. Más sobre esto más adelante.

Personajes de escape

Además de los especificadores de formato descritos anteriormente, hay otro tipo de símbolos de formato: Caracteres de escape.

Imaginemos que queremos imprimir un "símbolo usando printf(). Podemos probar algo como:

System.out.printf(""");

Si intenta ejecutar esto, su compilador definitivamente lanzará una excepción. Si observa de cerca, incluso el código que resalta el código en esta página se resaltará );como una Cadena, y no como el corchete cerrado del método.

Lo que sucedió fue que intentamos imprimir un símbolo que tiene un significado especial y reservado. Las comillas se utilizan para indicar el principio y el final de una cadena.

Comenzamos y terminamos un String "", después de lo cual abrimos otro "pero no lo cerramos. Esto hace que la impresión de caracteres reservados como este sea imposible, utilizando este enfoque.

La forma de evitar esto es escapando . Para imprimir caracteres especiales (como ") directamente, primero debemos escapar de sus efectos, y en Java eso significa prefijarlos con una barra invertida ( ). Para imprimir legalmente una comilla en Java, haríamos lo siguiente:

System.out.printf(""");

La combinación de y "le dice específicamente al compilador que nos gustaría insertar el "carácter en ese lugar y que debería tratar el "como un valor concreto, no como un símbolo reservado.

La aplicación del carácter de escape puede invocar diferentes efectos en función del siguiente. Pasar un carácter regular (no reservado) no hará nada y será tratado como un valor.

Sin embargo, ciertas combinaciones (también llamadas comandos) tienen un significado diferente para el compilador:

  • b – Insertar retroceso
  • f : el primer carácter de la siguiente línea comienza a la derecha del último carácter de la línea actual
  • n – Insertar nueva línea
  • r – Insertar retorno de carro
  • t – pestaña Insertar
  • \ – Insertar barra invertida
  • %% – Insertar signo de porcentaje

Por lo tanto, usaría npara imprimir un separador de línea en la consola, comenzando efectivamente cualquier contenido nuevo desde el principio de la siguiente línea. De manera similar, para agregar pestañas, usaría el tespecificador.

Es posible que lo hayas notado %%como la última combinación.

¿Por qué es esto? ¿Por qué no %se usa simplemente?

El %carácter ya es un carácter de escape específicamente para el printf()método. Seguido por personajes como d, i, f, etc, el formateador en tiempo de ejecución sabe cómo tratar a estos valores.

El carácter, sin embargo, es para el compilador. Le dice dónde y qué insertar. El %comando simplemente no está definido y usamos el %carácter de escape para escapar del efecto del %carácter siguiente , si eso tiene sentido.

Para el compilador, %no es un carácter especial, pero lo es. Además, es una convención que los caracteres especiales escapen por sí mismos. escapa y %escapa %.

Uso básico

Formateemos una cadena con múltiples argumentos de diferentes tipos:

System.out.printf("The quick brown %s jumps %d times over the lazy %s.n", "fox", 2, "dog");

La salida será:

The quick brown fox jumps 2 times over the lazy dog.

Flotación y doble precisión

Con printf(), podemos definir precisión personalizada para números de punto flotante:

double a = 35.55845;
double b = 40.1245414;

System.out.printf("a = %.2f b = %.4f", a, b);

Dado que %fse usa para flotantes, podemos usarlo para imprimir doubles. Sin embargo, al agregar un .n, donde nes el número de lugares decimales, podemos definir la precisión personalizada.

Ejecutar este código produce:

a = 35.56
b = 40.1245

Formato de relleno

También podemos agregar relleno, incluido el String pasado:

System.out.printf("%10sn", "stack");

Aquí, después del %carácter, hemos pasado un número y un especificador de formato. Específicamente, queremos una cadena con 10caracteres, seguida de una nueva línea. Dado que stacksolo contiene 5 caracteres, se agregan 5 más como relleno para “completar” la Cadena en el destino del carácter:

     stack

También puede agregar relleno a la derecha en su lugar:

System.out.printf("%-10sn", "stack");

Local

También podemos pasar a Localecomo primer argumento, formateando la Cadena de acuerdo con él:

System.out.printf(Locale.US, "%,dn", 5000);
System.out.printf(Locale.ITALY, "%,dn", 5000);

Esto produciría dos números enteros con formato diferente:

5,000
5.000

Índice de argumentos

Si no se proporciona un índice de argumento, los argumentos simplemente seguirán el orden de presencia en la llamada al método:

System.out.printf("First argument is %d, second argument is %d", 2, 1);

Esto daría como resultado:

First argument is 2, argument number is 1

Sin embargo, después del %carácter de escape y antes del especificador de formato, podemos agregar otro comando. $nespecificará el índice del argumento:

System.out.printf("First argument is %2$d, second argument is %1$d", 2, 1);

Aquí, 2$se encuentra entre %y d. 2$especifica que nos gustaría adjuntar el segundo argumento de la lista de argumentos a este especificador. De manera similar, 1$especifica que nos gustaría adjuntar el primer argumento de la lista al otro especificador.

Ejecutar este código da como resultado:

First argument is 1, second argument is 2

Puede apuntar ambos especificadores al mismo argumento. En nuestro caso, eso significaría que solo usamos un único argumento proporcionado en la lista. Eso está perfectamente bien, aunque todavía tenemos que proporcionar todos los argumentos presentes en la plantilla String:

System.out.printf("First argument is %2$d, second argument is %2$d", 2, 1);

Esto resultará en:

First argument is 1, second argument is 1

System.out.format ()

Antes de hablar System.out.format(), centrémonos brevemente en System.out.

Todos los sistemas UNIX tienen tres conductos principales: conducto de entrada estándar ( stdin), conducto de salida estándar ( stdout) y conducto de error estándar ( stderr). El outcampo corresponde a la stdouttubería y es de PrintStreamtipo.

Esta clase tiene muchos métodos diferentes para imprimir representaciones basadas en texto con formato en una secuencia, algunos de los cuales son format()y printf().

Según la documentación, ambos se comportan exactamente de la misma manera. Esto significa que no hay diferencia entre los dos y se puede utilizar para obtener los mismos resultados. Todo lo que hemos dicho hasta ahora printf()también funciona format().

Ambos printf()e System.out.format()imprimen en la stdouttubería, que normalmente está dirigida a la consola / terminal.

String.format ()

Otra forma de formatear cadenas es con el String.format()método que también utiliza internamente java.util.Formatter, que exploraremos en la siguiente sección.

La principal ventaja de String.format()over printf()es su tipo de retorno: devuelve un String. En lugar de simplemente imprimir el contenido en la tubería de salida estándar y no tener un tipo de retorno ( void) como lo printf()hace, String.format()se usa para formatear una Cadena que se puede usar o reutilizar en el futuro:

String formattedString = String.format("Local time: %tT", Calendar.getInstance());

Ahora puede hacer lo que quiera con el formattedString. Puede imprimirlo, guardarlo en un archivo, modificarlo o conservarlo en una base de datos. Imprimirlo resultaría en:

Local time: 16:01:42

El String.format()método utiliza exactamente el mismo principio subyacente que el printf()método. Ambos usan internamente la Formatterclase para dar formato a las cadenas. Por tanto, todo lo dicho printf()también se aplica al String.format()método.

Usar printf(), String.format()o Formatteres esencialmente lo mismo. Lo único que difiere es el tipo de retorno: printf()imprime en el flujo de salida estándar (normalmente su consola) y String.format()devuelve un formato String.

Dicho esto, String.format()es más versátil, ya que puede utilizar el resultado en más de una forma.

La clase Formatter

Dado que todos los métodos anteriores llaman inherentemente al Formatter, conocer solo uno significa que los conoce todos.

El uso de Formatteres bastante similar a otras técnicas mostradas anteriormente. La mayor diferencia es que para usarlo, es necesario crear una instancia de un Formatterobjeto:

Formatter f = new Formatter();
f.format("There are %d planets in the Solar System. Sorry, Pluto", 8);
System.out.println(f);

Esto plantea la pregunta:

¿Por qué no usaría siempre los métodos anteriores, ya que son más concisos?

Hay una distinción más importante que hace que la Formatterclase sea bastante flexible:

StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb);

formatter.format("%d, %d, %d...n", 1, 2, 3);

En lugar de trabajar solo con Strings, Formattertambién puede trabajar con lo StringBuilderque hace posible (re) usar ambas clases de manera eficiente.

De hecho, Formatteres capaz de trabajar con cualquier clase que implemente la Appendableinterfaz. Un ejemplo es el ya mencionado StringBuilder, pero otros ejemplos incluyen clases, tales como BufferedWriter, FileWriter, PrintStream, PrintWriter, StringBuffer, etc. La lista completa se puede encontrar en la documentación .

Por último, todos los especificadores de formato, caracteres de escape, etc., también son válidos para la Formatterclase ya que es la lógica principal para el formato de cadenas en los tres casos: String.format(), printf(), y Formatter.

MessageFormat

Finalmente, mostremos una técnica de formato final que no se usa Formatterbajo el capó.

MessageFormatfue creado para producir y proporcionar mensajes concatenados de una manera neutral en cuanto al lenguaje. Esto significa que el formato será el mismo, independientemente de si está utilizando Java, Python o algún otro lenguaje compatible MessageFormat.

MessageFormatextiende la Formatclase abstracta , cómo DateFormaty cómo NumberFormat. La Formatclase está destinada a formatear objetos sensibles a la configuración regional en cadenas.

Veamos un buen ejemplo, cortesía de MessageFormatla documentación de ‘ .

int planet = 7;
String event = "a disturbance in the Force";

String result = MessageFormat.format(
	"At {1, time} on {1, date}, there was {2} on planet {0, number, integer}.",
	planet, new Date(), event
);

Crédito del código: Oracle Docs

La salida es:

At 11:52 PM on May 4, 2174, there was a disturbance in the Force on planet 7.

En lugar de los especificadores de porcentaje que hemos visto hasta ahora, aquí usamos llaves para cada uno de los argumentos. Tomemos el primer argumento {1, time}. El número 1representa el índice del argumento que debe usarse en su lugar. En nuestro caso, los argumentos son planet, new Date()y event.

La segunda parte, se timerefiere al tipo de valor. Tipos de formato de nivel superior son number, date, time, y choice. Para cada uno de los valores, se puede hacer una selección más específica, como con la {0, number, integer}que dice que el valor debe tratarse no solo como un número, sino también como un entero.

El conjunto completo de tipos y subtipos de formato se puede encontrar en la documentación .

Conclusión

En este artículo, hemos pasado por alto un buen número de formas de formatear cadenas en el núcleo de Java.

Cada una de las técnicas que hemos mostrado tiene su propia razón de ser. printf(), por ejemplo, reString al método C de la vieja escuela del mismo nombre de.

Otros enfoques, como Formatteru MessageFormatofrecen un enfoque más moderno que explota algunos de los beneficios de la programación orientada a objetos.

Cada técnica tiene casos de uso específicos, por lo que, con suerte, podrá saber cuándo usar cada una en el futuro.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad