{"id":657,"date":"2026-02-18T20:20:28","date_gmt":"2026-02-18T20:20:28","guid":{"rendered":"https:\/\/www.bogotajvm.com.co\/?page_id=657"},"modified":"2026-07-01T00:30:57","modified_gmt":"2026-07-01T00:30:57","slug":"string-y-stringbuilder","status":"publish","type":"page","link":"https:\/\/www.bogotajvm.com.co\/en\/starter-kit\/string-y-stringbuilder\/","title":{"rendered":"String y StringBuilder"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"657\" class=\"elementor elementor-657\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-60c4690 e-flex e-con-boxed e-con e-parent\" data-id=\"60c4690\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-b709102 e-con-full e-flex e-con e-child\" data-id=\"b709102\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-f541605 elementor-widget elementor-widget-html\" data-id=\"f541605\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<link rel=\"license\" href=\"https:\/\/creativecommons.org\/licenses\/by\/4.0\/\">\r\n\r\n<link rel=\"stylesheet\" href=\"css\/main.css\">\r\n<link href=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/themes\/prism.css\" rel=\"stylesheet\" \/>\r\n<link href=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/plugins\/line-numbers\/prism-line-numbers.css\" rel=\"stylesheet\" \/>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/prism.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/components\/prism-java.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/plugins\/line-numbers\/prism-line-numbers.min.js\"><\/script>\r\n\r\n<h1>String y StringBuilder<\/h1>\r\n\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption>C\u00f3digo 1 - substring()<\/figcaption>\r\n        <pre class=\"line-numbers\"><code class=\"language-java\">String tel\u00e9fonoConFormato(String tel\u00e9fono) {\r\n    var primerosTres = tel\u00e9fono.substring(0, 3);\r\n    var siguientesTres = tel\u00e9fono.substring(3, 6);\r\n    var \u00faltimos = tel\u00e9fono.substring(6);\r\n    var conFormato = String.format(\"(%s) %s-%s\", primerosTres, siguientesTres, \u00faltimos);\r\n    return conFormato;\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n <div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; tel\u00e9fonoConFormato(\"1234567890\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>(123) 456-7890\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n        \r\n        \r\n<p>El primer tipo de dato que usamos fue String. Ahora vamos a profundizar en \u00e9l.<\/p>\r\n\r\n<p>Las Strings est\u00e1n presentes en casi todo lo que hacemos en programaci\u00f3n, \u00a1se podr\u00eda decir que\r\nest\u00e1n sobre utilizados! Como recordatorio, un String es una secuencia de caracteres: letras,\r\nd\u00edgitos, signos de puntuaci\u00f3n, emojis, etc.<\/p>\r\n\r\n<p>Un String no es un tipo de dato primitivo, es una clase. M\u00e1s adelante profundizaremos en qu\u00e9\r\nes una clase, y c\u00f3mo crear clases nuestras. Una diferencia fundamental entre datos primitivos y\r\nclases es que est\u00e1s \u00faltimas pueden definir m\u00e9todos que se llaman de una manera diferente de\r\nla que hemos usado hasta ahora.<\/p>\r\n\r\n<p>En la l\u00ednea 2, llamamos el m\u00e9todo substring() de la variable &lt;telefono&gt;. Lo importante es que a\r\ndiferencia de m\u00e9todos como &lt;Math.sqrt&gt; o &lt;String.format&gt;, aqu\u00ed el m\u00e9todo se llama sobre una\r\nvariable. Podemos pensarlo como que cada String creado, tiene un comportamiento que se\r\naccede mediante sus m\u00e9todos.<\/p>\r\n\r\n<p>Dado que un String es una cadena de caracteres, internamente se le asigna un \u00edndice a cada\r\ncar\u00e1cter para poder hacer referencia a ellos individualmente. Pero tiene algo extra\u00f1o y es que el\r\n\u00edndice empieza en 0 y no en 1 como quiz\u00e1s uno esperar\u00eda.<\/p>\r\n\r\n<img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/02\/string.png\"\/>\r\n\r\n<p>La cadena \"Hola Mundo!\" que tiene 11 caracteres, tiene \u00edndices que empiezan en 0 y el \u00faltimo\r\nes el total de caracteres, su tama\u00f1o, menos 1. El caracter en el \u00edndice 0 es 'H', el caracter en el\r\n\u00edndice 4 es ' ' y en el \u00edndice 5 es 'M'. El \u00edndice del caracter 'a' es 3,  mientras que el primer \u00edndice donde se encuentra una 'o' es 1  y el \u00faltimo es 9.<\/p>\r\n\r\n<aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>El primer \u00edndice de un String es siempre 0 y el \u00faltimo \u00edndice es la longitud\r\n                   del String menos 1.<\/p>\r\n            <\/div>\r\n        <\/aside>\r\n\r\n        <p>Uno de los aspectos m\u00e1s importantes con un String es poder extraer informaci\u00f3n de \u00e9l y\r\n            substring() es una de las formas m\u00e1s comunes de hacerlo. Como su nombre lo indica, devuelve\r\n            solo una parte de un String, utilizando \u00edndices para indicar donde se hacen los cortes.<\/p>\r\n\r\n        <p> En la l\u00ednea 02, tel\u00e9fono.substring(0, 3) retornar\u00eda un String que consiste \u00fanicamente de\r\n        los caracteres 0, 1 y 2. El \u00faltimo \u00edndice de substring(), es decir el segundo par\u00e1metro que toma, no est\u00e1 inclu\u00eddo en el String resultante.<\/p>\r\n\r\n<aside class=\"aside-box question\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n        <p> Comenzar los \u00edndices en 0 no es algo que se haya hecho de manera caprichosa, hay\r\n            una raz\u00f3n muy pr\u00e1ctica por la que se hizo as\u00ed. Lo que hace el \u00edndice es indicar\r\n            el desplazamiento que debes hacer desde el inicio de la cadena hasta el\r\n            caracter deseado. El desplazamiento desde el inicio de la cadena hasta el\r\n            primer caracter es 0 porque este mismo es el inicio de la cadena. \u00bfCrees qu\u00e9\r\n            fue error implementarlo de la manera m\u00e1s sencilla para las m\u00e1quinas as\u00ed\r\n            resulte inicialmente poco intuitivo para los programadores?<\/p>\r\n            <\/div>\r\n        <\/aside>\r\n\r\n        <p>Los parametros son de tipo int lo que quiere decir que puedes usar \u00edndices negativos, pero esto\r\n        siempre producir\u00e1 un error en tiempo de ejecuci\u00f3n. Igualmente si usas un \u00edndice m\u00e1s grande\r\n        que el m\u00e1ximo \u00edndice v\u00e1lido recibir\u00e1s un error en tiempo de ejecuci\u00f3n.<\/p>\r\n\r\n <aside class=\"aside-box warning\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>Si utilizas un \u00edndice que no sea v\u00e1lido, menor que 0 y mayor o igual al tama\u00f1o\r\n                del String obtendr\u00e1s un error en tiempo de ejecuci\u00f3n.<\/p>\r\n            <\/div>\r\n        <\/aside>\r\n\r\n        <p>Pero la clase String tiene 2 m\u00e9todos con el mismo nombre: subtring(), uno de ellos toma un int,\r\n        y el otro toma dos. Esto, Que 2 m\u00e9todos se llamen igual pero tengan diferentes par\u00e1metros, se\r\n        llama sobrecarga de m\u00e9todos. Por ahora lo importante es entender qu\u00e9 diferencia hay entre\r\n        ambos. La versi\u00f3n que solo toma 1, asume que el \u00edndice final es el final de la cadena.<\/p>\r\n\r\n        <p>Estas dos expresiones son equivalentes:<\/p>    \r\n\r\n    <figcaption><strong><\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">tel\u00e9fono.substring(6); \/\/ todos los d\u00edgitos despu\u00e9s del \u00edndice 6<\/code><\/pre>\r\n           \r\n    \r\n        <p>Y<\/p>\r\n\r\n     <figcaption><strong><\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">\/\/ todos los d\u00edgitos entre 6 y\r\n\/\/ el \u00edndice que es 1 menor que la longitud del String\r\ntel\u00e9fono.substring(6, phone.length() - 1);<\/code><\/pre>\r\n              \r\n\r\n        <p>Como habr\u00e1s visto, existe un m\u00e9todo String para calcular su longitud, llamado\r\n        apropiadamente length(), que resulta \u00fatil si deseas encontrar el \u00edndice del \u00faltimo car\u00e1cter, ya\r\n        que solo necesitas restar 1 a la longitud.<\/p>\r\n\r\n        <p>Esta no es una lista exhaustiva de los m\u00e9todos de String, pero te brindar\u00e1 suficientes\r\n        herramientas para poder descubrir c\u00f3mo usar una gran cantidad de m\u00e9todos que encontrar\u00e1s en la\r\n        documentaci\u00f3n.<\/p>\r\n\r\n     <aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>Documentaci\u00f3n oficial de String:<a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html\"> https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/lang\/String.html<\/a>.<\/p>\r\n            <\/div>\r\n        <\/aside>       \r\n\r\n        \r\n\r\n<H2 id='metodos-destacados'>M\u00e9todos Destacados de String<\/H2>\r\n\r\n<P>Otros m\u00e9todos que podr\u00edas utilizar con frecuencia:<\/P>\r\n\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#charAt(int)\">charAt(int)<\/a><\/ul><\/li><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \"Hola\".charAt(0)\r\n&gt; \"Hola\".chatAt(3)\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>'H'\r\n'a'                \r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#contains(java.lang.CharSequence)\">contains(String)<\/a><\/ul><\/li><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \"casa\".contains(\"as\")\r\n&gt; \"casa\".contains(\"Ca\")\r\n&gt; \"casa\".contains(\"sas\")\r\n&gt; \"casa\".contains(\"me\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>true\r\nFalse\r\nFalse\r\nFalse                \r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#equals(java.lang.Object)\">equals(Object)<\/a><\/ul><\/li><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \"hola\".equals(\"hola\")\r\n&gt; \"hola\".equals(\"adios\")\r\n&gt; !(\"hola\".equals(\"adios\"))\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>true\r\nFalse\r\ntrue\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#indexOf(java.lang.String)\">indexOf(String)<\/a><\/ul><\/li><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \"hola\".indexOf('h')\r\n&gt; \"hola\".indexOf('a')\r\n&gt; \"hola\".indexOf('z')\r\n&gt; \"hola\".indexOf('H')\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>0\r\n3\r\n-1\r\n-1\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#indexOf(java.lang.String,int)\">indexOf(String, int)<\/a><\/ul><\/li><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \"casa\".indexOf('a')\r\n&gt; \"casa\".indexOf('a', 2)\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>1\r\n3\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>        \r\n\r\n<p><ul><li><a href\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#lastIndexOf(java.lang.String)\">lastIndexOf(String)<\/a><\/ul><\/li><\/p>\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#lastIndexOf(java.lang.String,int)\">lastIndexOf(String, int)<\/a><\/ul><\/li><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \"casa\".lastIndexOf('a')\r\n&gt; \"casa\".lastIndexOf('a', 2)\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>3\r\n1\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>      \r\n\r\n<p>M\u00e9todos relacionados con Strings en otras clases:<\/p>\r\n\r\n\r\n<p><ul><li><a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/Integer.html#parseInt(java.lang.String)\">Integer.parseInt(String)<\/a><\/ul><\/li><\/p>\r\n\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; Integer.parseInt(\"56\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>56\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>     \r\n\r\n<aside class=\"aside-box warning\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>\u00bfSi usamos == y != para primitivas, tambi\u00e9n podemos usarlo con String? \u00a1No!\r\n                    Al no ser un dato primitivo, esos operadores tienen un significado diferente,\r\n                    que a veces pueden dar el resultado correcto. Como est\u00e1 en la lista anterior,\r\n                    equals() y !equals() son la manera correcta de revisar que 2 String sean o no\r\n                    iguales.<\/p>\r\n            <\/div>\r\n        <\/aside>        \r\n\r\n<figure class=\"code-block\">\r\n          <figcaption>C\u00f3digo 2 - Parsear un String para extraer tiempos<\/figcaption>\r\n        <pre class=\"line-numbers\"><code class=\"language-java\">\/\/ Un String de tiempo en formato ISO 8601\r\n\/\/ p.j. 2021-11-20T13:15:00 pero tambi\u00e9n 08:05:00\r\n int tiempoEnSegundos(String fecha) {\r\n    var separador = fecha.indexOf('T'); \/\/ puede ser -1\r\n    var tiempo = (separador != -1) ? fecha.substring(separador + 1) : fecha;\r\n    var horas = Integer.parseInt(tiempo.substring(0, 2));\r\n    var minutos = Integer.parseInt(tiempo.substring(3, 5));\r\n    var segundos = Integer.parseInt(tiempo.substring(6));\r\n    var SEGUNDOS_POR_MINUTO = 60;\r\n    var MINUTOS_POR_HORA = 60;\r\n    var SEGUNDOS_POR_HORA = SEGUNDOS_POR_MINUTO * MINUTOS_POR_HORA;\r\n    return SEGUNDOS_POR_HORA * horas + SEGUNDOS_POR_MINUTO * minutos + segundos;\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>> tiempoEnSegundos(\"2023-04-20T00:00:15\")\r\n> tiempoEnSegundos(\"2023-04-20T00:01:00\")\r\n> tiempoEnSegundos(\"2023-04-20T00:10:00\")\r\n> tiempoEnSegundos(\"2023-04-20T01:00:00\")\r\n> tiempoEnSegundos(\"00:00:32\")\r\n> tiempoEnSegundos(\"00:02:00\")\r\n> tiempoEnSegundos(\"10:00:00\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>15\r\n60\r\n600\r\n3600\r\n32\r\n120\r\n36000\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>     \r\n     \r\n\r\n\r\n<p>En la l\u00ednea 04 utilizamos el m\u00e9todo indexOf() para encontrar el \u00edndice en el que se encuentra el\r\ncaracter 'T'. El est\u00e1ndar ISO 8601 indica que un tiempo que incluye una fecha y un tiempo,\r\nutiliza ese caracter para separar  los datos de la fecha, de los del tiempo. Pero si el String solo indica un\r\ntiempo entonces no hay 'T', as\u00ed que nuestro primer paso es garantizar que el String no incluya la\r\nparte de la fecha.<\/p>\r\n\r\n\r\n<p>El m\u00e9todo indexOf() retorna el menor \u00edndice en el que se encuentra un caracter dado. El\r\nest\u00e1ndar es claro que si hay un 'T', solo hay uno as\u00ed que buscar el primero, equivale a buscar el\r\n\u00fanico.<\/p>\r\n\r\n<p>La primera acci\u00f3n que queremos hacer es quitar la informaci\u00f3n de la fecha si es que existe.\r\nUtilizamos el operador ternario para crear una nueva variable &laquo;tiempo&raquo; que haga un substring()\r\nsi existe el caracter 'T', y en caso contrario sea una copia de la variable &laquo;fecha&raquo;<\/p>\r\n\r\n<p>Ya garantizado que la variable &laquo;tiempo&raquo; no incluye informaci\u00f3n sobre una fecha, entonces\r\nqueremos extraer los n\u00fameros que se encuentran entre caracteres ':', utilizando nuevamente\r\nsubstring(), pero usando el valor de retorno de estos como argumento  de Integer.parseInt(). Lo importante de esta operaci\u00f3n es que nos va a permitir\r\nmultiplicar y sumar ese valor.<\/p>\r\n\r\n<p>Finalmente sabemos que hay 60 minutos en una hora y 60 segundos en un minuto, por lo tanto\r\npodemos hacer una f\u00f3rmula para terminar de encontrar cu\u00e1ntos segundos desde el inicio del\r\nd\u00eda han transcurrido hasta la hora consignada en el String.<\/p>\r\n\r\n\r\n<h2 id=\"string-format\">String Format<\/h2>\r\n\r\n    <p>Crear un String a partir de cierta informaci\u00f3n es una tarea muy com\u00fan en programaci\u00f3n. Como\r\n    vimos anteriormente, String.format() es una forma pr\u00e1ctica de hacerlo. Hay muchas cosas sobre ese m\u00e9todo, que bien vale la pena que conozcas. Pero vale la\r\n    pena mostrar algunos ejemplos.<\/p>    \r\n\r\n    <p>String.format() no solo funciona con Strings, funciona con otros tipos de datos:<\/p>\r\n\r\n    \r\n <div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \/\/ %d para ints \r\n  String.format(\"%d\", 123);\r\n&gt; \/\/ %f para doubles \r\n  String.format(\"%f\", 3.14);    \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"123\"\r\n\r\n\"3.140000\"    \r\n\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>           \r\n\r\n<P>Incluso podemos hacer conversi\u00f3n de n\u00fameros enteros a base 16:<\/P>\r\n\r\n <div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \/\/ %x para d\u00edgitos en min\u00fasculas\r\n  String.format(\"%x\", 123);\r\n&gt; \/\/ %X para d\u00edgitos en may\u00fasculas\r\n  String.format(\"%X\", 123);    \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"7b\"\r\n\r\n\"7B\"    \r\n\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>      \r\n\r\n<P>Tambi\u00e9n podemos convertir Strings a may\u00fasculas:<\/P>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; \/\/ %s no modifica el String\r\n  String.format(\"%s\", \"C\u00f3digo\");\r\n&gt; \/\/ %S transforma a may\u00fasculas\r\n  String.format(\"%S\", \"C\u00f3digo\");   \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"C\u00f3digo\"\r\n\r\n\"C\u00d3DIGO\"    \r\n\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>   \r\n\r\n<P>Tambi\u00e9n podemos garantizar que el String resultante tenga un tama\u00f1o m\u00ednimo, utilizando un\r\nn\u00famero entero entre el % y el indicador del tipo de dato:<\/P>        \r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; String.format(\"%s\", \"Casa\");\r\n&gt; String.format(\"%8s\", \"Casa\");\r\n&gt; String.format(\"%d\", 6789);\r\n&gt; String.format(\"%6d\", 6789);  \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"Casa\"\r\n\" Casa\"\r\n\"6789\"    \r\n\" 6789\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>   \r\n\r\n<P>Para los n\u00fameros, puede indicar que si hacen falta caracteres para llegar a la longitud m\u00ednima, se usen cero en vez de espacios:<\/P>\r\n\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; String.format(\"%06d\", 6789);\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"006789\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<P>Por \u00faltimo para n\u00fameros reales, podemos indicar cu\u00e1ntos n\u00famero decimales queremos en el\r\nString resultante, utilizando un n\u00famero antecedido por un punto. El resultado va a ser\r\nredondeado:<\/P>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; String.format(\"%f\", Math.sqrt(2.0));\r\n&gt; String.format(\"%.3f\", Math.sqrt(2.0));\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"1.414214\"\r\n\"1.414\"                \r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<P>Todas estas reglas pueden ser combinadas. Y recuerda que hay a\u00fan otras funcionales\r\nadicionales, aunque est\u00e1s son posiblemente las que m\u00e1s puedas usar.<\/P>\r\n\r\n<h2 id='stringbuilder'>StringBuilder<\/h2>\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption>C\u00f3digo 3 - StringBuilder<\/figcaption>\r\n        <pre class=\"line-numbers\"><code class=\"language-java\">String phoneFormatter(String tel\u00e9fono) {\r\n    var primerosTres = tel\u00e9fono.substring(0, 3);\r\n    var siguientesTres = tel\u00e9fono.substring(3, 6);\r\n    var \u00faltimos = tel\u00e9fono.substring(6);\r\n    var builder = new StringBuilder();\r\n    builder.append(\"(\");\r\n    builder.append(primerosTres);\r\n    builder.append(\") \");\r\n    builder.append(siguientesTres);\r\n    builder.append(\" - \");\r\n    builder.append(\u00faltimos);\r\n    var formattedPhone = builder.toString();\r\n    return formattedPhone;\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n<p>\r\n    \r\n<\/p>\r\n<p>El c\u00f3digo 3 muestra una implementaci\u00f3n alternativa de phoneFormatter utilizando StringBuilder.\r\nPuede que esta no sea la mejor implementaci\u00f3n, pero nos permite hablar de un tipo de dato\r\nimportante: String Builder.<\/p>\r\n\r\n<p>String.format() es una de las formas de construir Strings, \u00a1pero no es la \u00fanica! String.format() es\r\nmuy \u00fatil cuando tienes un patr\u00f3n para String y quieres interpolar algunas variables. Pero tal\r\nvez quieras construir un String paso a paso, y eso es lo que StringBuilder hace mejor.<\/p>\r\n\r\n\r\n<p>La l\u00ednea 05 es c\u00f3mo se crea un StringBuilder vac\u00edo. Los detalles de qu\u00e9 hace la palabra reservada \u00abnew\u00bb, se discutir\u00e1n m\u00e1s adelante, por ahora recuerda que lo necesitas para crear este tipo de dato. Con un StringBuilder\r\npuedes invocar el m\u00e9todo append() tantas veces como quieras y usar cualquier tipo de variable que tengas\r\npara crear el String, paso a paso.<\/p>\r\n\r\n<p>La l\u00ednea 06 agrega el literal String \u201c(\u201c. Luego la l\u00ednea 07 agrega la variable  \u00abprimerosTres\u00bb, que es un\r\nString. Pero no importar\u00eda si fuera de otro tipo, ya que append() puede aceptar cualquier tipo.\r\nLuego las siguientes 4 l\u00edneas agregan la informaci\u00f3n restante necesaria para crear la String.\r\nDespu\u00e9s de agregar todos los datos necesarios,  , llamamos al m\u00e9todo toString() para convertir StringBuilder en un String en la l\u00ednea 12, y finalmente devolver ese String resultante en la l\u00ednea 13.<\/p>\r\n\r\n<p>StringBuilder tiene m\u00e1s m\u00e9todos para ayudarle a construir String pero no son importantes por\r\nahora, append() que es el m\u00e9todo m\u00e1s utilizado.<\/p>\r\n\r\n\r\n <aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>Documentaci\u00f3n oficial de StringBuilder: <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#%3Cinit%3E(java.lang.StringBuilder)\"> \"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/lang\/StringBuilder.html\"><\/a>.<\/p>\r\n            <\/div>\r\n        <\/aside>\r\n\r\n<h2 id='inmutabilidad'>Misi\u00f3n secundaria: Inmutabilidad<\/h2>\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption>C\u00f3digo 4 - StringBuilder<\/figcaption>\r\n        <pre class=\"line-numbers\"><code class=\"language-java\">String stringEsInmutable(String s) {\r\n    s.substring(1);\r\n    return s;\r\n} \r\nStringBuilder stringBuilderEsMutable\r\n(StringBuilder builder) {\r\n    builder.substring(1);\r\n    return builder;\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>> > stringsAreImmutable(\"foo\")\r\n> stringBuilderAreMutable(new StringBuilder(\"foo\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>foo\r\noo\r\n<\/code><\/pre>\r\n        <\/div>\r\n        \r\n\r\n\r\n<p>Presentar StringBuilder nos ayuda a hablar sobre un gran tema en programaci\u00f3n: la\r\ninmutabilidad. En Java, las strings son inmutables, mientras que los StringBuilders no lo son.\r\nLos tipos inmutables una vez creados no se pueden cambiar, sin importar qu\u00e9 m\u00e9todos los\r\ninvoques. Para tipos mutables, al invocar ciertos m\u00e9todos vamos cambiando el valor del objeto.<\/p>\r\n\r\n<p>En stringEsInmutable() invocamos el m\u00e9todo substring() en la variable e inmediatamente retornamos esa variable. Como las\r\nstrings son inmutables, substring() no cambia la string, crea una nueva string con el valor\r\nactualizado. Recuerda que el m\u00e9todo substring(), puede tomar uno o dos argumentos. Con un argumento, devolver\u00e1 el substring() desde el \u00edndice indicado hasta el final de la cadena por lo tanto s.substring(1) devuelve el substring que comienza desde el segundo car\u00e1cter.<\/p>\r\n\r\n<p>En stringBuilderEsMutable() tambi\u00e9n llamamos a substring() pero esta vez es el m\u00e9todo substring() de StringBuilder. Como este tipo de dato es mutable, el valor de StringBuilder cambia despu\u00e9s de ese llamado. Inmediatamente lo retornamos y as\u00ed podemos ver el cambio.\r\n<\/p>\r\n\r\n\r\n<p>Otra manera de verlo es que en las clases inmutables, debemos atrapar los valores de retorno para ver los cambios, de otra manera se pierden. Eso es lo que pasa con stringEsInmutable(), al llamar a substring(int) de String ese valor no lo atrapamos y el cambio no es visible de ninguna manera. En el caso de stringBuilderEsMutable(), llamamos el m\u00e9todo substring(int) de StringBuilder y ese cambio se ve reflejado sin hacer nada adicional.<\/p>\r\n\r\n<p>La inmutabilidad es un tema importante cuando creas tus propios tipos. Cuando utilices tipos ya definidos, simplemente lee la documentaci\u00f3n o estudia c\u00f3mo funcionan sus m\u00e9todos para saber si es mutable o no.<\/p>\r\n\r\n<h2>Resumen<\/h2>\r\n\r\n<p>\u00a1Los Strings son muy importantes en la programaci\u00f3n! Es importante saber c\u00f3mo crearlos y\r\nmanipularlos. Para crearlos, la forma recomendada es String.format() y StringBuilder. Se\r\nprefiere lo primero si se puede crear la string en un solo paso, utilizando los datos disponibles y\r\nproporcionando una plantilla. Se prefiere lo \u00faltimo si crea la string en pasos, c\u00f3mo en un bucle\r\nque ver\u00e1 en el siguiente cap\u00edtulo.<\/p>\r\n\r\n<p>Hay muchos m\u00e9todos en la API de Strings, probablemente los m\u00e1s utilizados son: charAt,\r\ncontains, compareTo, equals, indexOf y lastIndexOf.<\/p>\r\n\r\n<p>Debido a que las strings a veces contienen informaci\u00f3n confidencial, son inmutables: \u00a1eso\r\nsignifica que una vez que se crea una string no puedes modificarla! Entonces, los m\u00e9todos que\r\nparecen hacerlo, en realidad, devuelven una nueva string con los estados actualizados. Es muy\r\nimportante que se sienta c\u00f3modo manejando tipos inmutables antes de profundizar en un\r\ncap\u00edtulo posterior.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-975465d elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"975465d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-2110a78 e-con-full e-flex e-con e-child\" data-id=\"2110a78\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t<div class=\"elementor-element elementor-element-52005f3 e-con-full e-flex e-con e-child\" data-id=\"52005f3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6b8c0a0 elementor-widget elementor-widget-html\" data-id=\"6b8c0a0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t\n   <h1 id='quiz'>Strings<\/h1>\n  <p class=\"subtitle\">Quiz Interactivo<\/p>\n  <hr \/>\n\n  <!--\n    The quiz will render inside this div.\n    Show a brief intro before the quiz starts \u2014 clicking the button calls QuizEngine.init().\n  -->\n  <div id=\"quiz-root\">\n    <div class=\"start-screen\">\n      <p>Antes de intentar los ejercicios, toma unos minutos para verificar tu entendimiento de Strings tomando este quiz.<\/p>\n      <ul>\n        <li>Las preguntas y el orden de las opciones son diferentes cada vez que tomes el quiz.<\/li>\n        <li>Las preguntas que tengas mal, vuelven a aparecer luego hasta que las contestes correctamente.<\/li>\n        <li>Cada pregunta tiene una pista y una explicaci\u00f3n.<\/li>\n      <\/ul>\n      <button class=\"qe-start-btn\" onclick=\"QuizEngine.init('quiz-root')\">Empezar \u2192<\/button>\n    <\/div>\n  <\/div>\n\n  <!-- Load engine first, then the chapter data, then kick off -->\n  <script src=\"quiz-engine.js\"><\/script>\n  <script src=\"quiz-data-chapter1.js\"><\/script>\n  \n  <script>\nconst QuizEngine = (() => {\n\n  \/* \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  function shuffle(arr) {\n    const a = [...arr];\n    for (let i = a.length - 1; i > 0; i--) {\n      const j = Math.floor(Math.random() * (i + 1));\n      [a[i], a[j]] = [a[j], a[i]];\n    }\n    return a;\n  }\n\n  function prepareQuestion(q) {\n    \/\/ Attach a shuffled copy of options; preserve the original for reference\n    return { ...q, _options: shuffle(q.options) };\n  }\n\n  \/* \u2500\u2500 State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  let root, allQuestions, queue, nonPassed, current;\n  let stats = { total: 0, firstPassCorrect: 0, attempts: 0 };\n  let isFirstPass = true;\n\n  \/* \u2500\u2500 Render helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  function progressLabel(offset = 0) {\n    const remaining = queue.length + nonPassed.length;\n    const done = stats.total - remaining - offset;\n    return `Pregunta ${done + 1} de ${stats.total}`;\n  }\n\n  function renderQuestion() {\n    current = queue.shift();\n    const opts = current._options;\n\n    root.innerHTML = `\n      <div class=\"qe-wrap\">\n        <div class=\"qe-progress\">\n          <div class=\"qe-progress-bar\" style=\"width:${\n            ((stats.total - queue.length - nonPassed.length - 1) \/ stats.total) * 100\n          }%\"><\/div>\n        <\/div>\n        <p class=\"qe-label\">${progressLabel(1)}<\/p>\n        <h2 class=\"qe-question\">${current.question}<\/h2>\n        <ul class=\"qe-options\" role=\"list\">\n          ${opts.map((o, i) => `\n            <li>\n              <button class=\"qe-option\" data-index=\"${i}\" aria-label=\"Option ${i + 1}: ${o.text}\">\n                <span class=\"qe-option-key\">${['A','B','C','D'][i]}<\/span>\n                <span class=\"qe-option-text\">${o.text}<\/span>\n              <\/button>\n            <\/li>\n          `).join('')}\n        <\/ul>\n        <div class=\"qe-feedback\" aria-live=\"polite\"><\/div>\n      <\/div>`;\n\n    root.querySelectorAll('.qe-option').forEach(btn => {\n      btn.addEventListener('click', () => handleAnswer(btn, opts));\n    });\n  }\n\n  function handleAnswer(btn, opts) {\n    stats.attempts++;\n    const idx = parseInt(btn.dataset.index, 10);\n    const chosen = opts[idx];\n    const feedback = root.querySelector('.qe-feedback');\n\n    \/\/ Disable all buttons to prevent double-clicks\n    root.querySelectorAll('.qe-option').forEach(b => b.disabled = true);\n\n    if (chosen.correct) {\n      btn.classList.add('qe-correct');\n      if (isFirstPass) stats.firstPassCorrect++;\n\n      feedback.innerHTML = `\n        <p class=\"qe-feedback-correct\">\u2713 Correcto!<\/p>\n        ${current.explanation ? `<p class=\"qe-feedback-explanation\">${current.explanation}<\/p>` : ''}`;\n\n      setTimeout(() => {\n        if (queue.length === 0 && nonPassed.length === 0) {\n          \/\/ All done on first pass or no more retries needed\n          if (isFirstPass && nonPassed.length === 0) {\n            renderComplete();\n          } else {\n            renderComplete();\n          }\n        } else if (queue.length === 0 && nonPassed.length > 0) {\n          startRetryRound();\n        } else {\n          renderQuestion();\n        }\n      }, current.explanation ? 2200 : 1000);\n\n    } else {\n      btn.classList.add('qe-wrong');\n\n      \/\/ Grey out all options equally \u2014 no correct answer revealed\n      root.querySelectorAll('.qe-option').forEach(b => b.classList.add('qe-dimmed'));\n\n      feedback.innerHTML = `\n        <p class=\"qe-feedback-wrong\">\u2717 No exactamente.<\/p>\n        ${current.hint ? `<p class=\"qe-feedback-hint\"><strong>Pista:<\/strong> ${current.hint}<\/p>` : ''}\n       \n        <button class=\"qe-next-btn\">Siguiente pregunta \u2192<\/button>`;\n\n      \/\/ Save to nonPassed (fresh shuffle of its options)\n      nonPassed.push(prepareQuestion(current));\n\n      feedback.querySelector('.qe-next-btn').addEventListener('click', () => {\n        if (queue.length === 0) {\n          startRetryRound();\n        } else {\n          renderQuestion();\n        }\n      });\n    }\n  }\n\n  function startRetryRound() {\n    isFirstPass = false;\n    queue = shuffle(nonPassed.map(q => prepareQuestion(q)));\n    nonPassed = [];\n    stats.total = queue.length; \/\/ reset progress counter for retry round\n    stats.attempts = 0;\n\n    root.innerHTML = `\n      <div class=\"qe-wrap qe-interlude\">\n        <div class=\"qe-interlude-icon\">\u21a9<\/div>\n        <h2>Ya casi!<\/h2>\n        <p>Revisemos las ${queue.length} pregunta${queue.length > 1 ? 's' : ''} que fallaste. Mismas preguntas, diferente orden.<\/p>\n        <button class=\"qe-start-btn\">Continuar<\/button>\n      <\/div>`;\n\n    root.querySelector('.qe-start-btn').addEventListener('click', renderQuestion);\n  }\n\n  function renderComplete() {\n    const pct = Math.round((stats.firstPassCorrect \/ allQuestions.length) * 100);\n    launchConfetti();\n\n    root.innerHTML = `\n      <div class=\"qe-wrap qe-complete\">\n        <div class=\"qe-trophy\">\ud83c\udf89<\/div>\n        <h2>Quiz completado!<\/h2>\n        <p class=\"qe-score\">Obtuviste <strong>${stats.firstPassCorrect} de ${allQuestions.length}<\/strong> correctas en tu primer intento (${pct}%).<\/p>\n        ${pct >= 80\n          ? `<p class=\"qe-msg qe-msg-good\">Excelentes resultados estas listo para los ejercicios.<\/p>`\n          : `<p class=\"qe-msg qe-msg-ok\">Recuerda poner m\u00e1s atenci\u00f3n, intenta el quiz nuevamente.<\/p>`\n        }\n        <button class=\"qe-restart-btn\">Reinicia el quiz<\/button>\n      <\/div>`;\n\n    root.querySelector('.qe-restart-btn').addEventListener('click', () => init(root.parentElement.id || root.id));\n  }\n\n  \/* \u2500\u2500 Confetti \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  function launchConfetti() {\n    const canvas = document.createElement('canvas');\n    canvas.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9999';\n    document.body.appendChild(canvas);\n    const ctx = canvas.getContext('2d');\n    canvas.width = innerWidth; canvas.height = innerHeight;\n\n    const pieces = Array.from({ length: 120 }, () => ({\n      x: Math.random() * canvas.width,\n      y: Math.random() * -canvas.height,\n      w: 8 + Math.random() * 8,\n      h: 4 + Math.random() * 4,\n      r: Math.random() * Math.PI * 2,\n      vx: (Math.random() - 0.5) * 3,\n      vy: 2 + Math.random() * 4,\n      vr: (Math.random() - 0.5) * 0.15,\n      color: ['#FF6B6B','#FFD93D','#6BCB77','#4D96FF','#C77DFF','#FF9F40'][Math.floor(Math.random()*6)]\n    }));\n\n    let frame;\n    function draw() {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      pieces.forEach(p => {\n        ctx.save();\n        ctx.translate(p.x, p.y);\n        ctx.rotate(p.r);\n        ctx.fillStyle = p.color;\n        ctx.fillRect(-p.w\/2, -p.h\/2, p.w, p.h);\n        ctx.restore();\n        p.x += p.vx; p.y += p.vy; p.r += p.vr;\n      });\n      if (pieces.some(p => p.y < canvas.height + 20)) {\n        frame = requestAnimationFrame(draw);\n      } else {\n        canvas.remove();\n      }\n    }\n    draw();\n    setTimeout(() => { cancelAnimationFrame(frame); canvas.remove(); }, 4000);\n  }\n\n  \/* \u2500\u2500 CSS injection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  function injectStyles() {\n    if (document.getElementById('qe-styles')) return;\n    const s = document.createElement('style');\n    s.id = 'qe-styles';\n    s.textContent = `\n     .qe-wrap { max-width: 640px; margin: 0 auto; font-family: 'Segoe UI', system-ui, sans-serif; padding: 1.5rem 0; }\n      .qe-progress { height: 4px; background: #e5e7eb; border-radius: 4px; margin-bottom: 1rem; overflow: hidden; }\n      .qe-progress-bar { height: 100%; background: #4D96FF; border-radius: 4px; transition: width 0.4s ease; }\n      .qe-label { font-size: 0.8rem; color: #6b7280; margin: 0 0 0.4rem; letter-spacing: 0.04em; text-transform: uppercase; }\n      .qe-question { font-size: 1.3rem; font-weight: 600; margin: 0 0 1.4rem; line-height: 1.4; }\n      .qe-options { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }\n      .qe-option { display: flex; align-items: center; gap: 12px; width: 100%; padding: 0.75rem 1rem; background: #dcdde6; border: 1.5px solid #a2bcf0; border-radius: 10px; cursor: pointer; font-size: 1rem; transition: border-color 0.15s, background 0.15s; text-align: left; }\n      .qe-option:hover:not(:disabled) { border-color: #4D96FF; background: #f0f7ff; }\n      .qe-option:disabled { cursor: default; }\n      .qe-option-key { display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 6px; background: #f3f4f6; font-size: 0.8rem; font-weight: 700; color: #374151; flex-shrink: 0; }\n      .qe-option-text { flex: 1; color: black; }\n      .qe-correct { border-color: #22c55e !important; background: #f0fdf4 !important; }\n      .qe-correct .qe-option-key { background: #22c55e; color: #fff; }\n      .qe-dimmed { opacity: 0.45; border-color: #e5e7eb !important; background: #f9fafb !important; }\n      .qe-wrong { border-color: #ef4444 !important; background: #fef2f2 !important; }\n      .qe-wrong .qe-option-key { background: #ef4444; color: #fff; }\n      .qe-feedback { margin-top: 1.2rem; }\n      .qe-feedback-correct { color: #16a34a; font-weight: 600; margin: 0 0 0.4rem; }\n      .qe-feedback-wrong { color: #dc2626; font-weight: 600; margin: 0 0 0.4rem; }\n      .qe-feedback-hint { color: #92400e; background: #fef3c7; border-left: 3px solid #f59e0b; padding: 0.6rem 0.8rem; border-radius: 0 6px 6px 0; margin: 0.5rem 0; font-size: 0.95rem; }\n      .qe-feedback-explanation { color: #374151; background: #f9fafb; border: 1px solid #e5e7eb; padding: 0.6rem 0.8rem; border-radius: 6px; margin: 0.5rem 0; font-size: 0.93rem; line-height: 1.5; }\n      .qe-next-btn, .qe-start-btn, .qe-restart-btn { margin-top: 0.8rem; padding: 0.6rem 1.4rem; background: #4D96FF; color: #fff; border: none; border-radius: 8px; cursor: pointer; font-size: 0.95rem; font-weight: 600; transition: background 0.15s; }\n      .qe-next-btn:hover, .qe-start-btn:hover, .qe-restart-btn:hover { background: #2563eb; }\n      .qe-interlude { text-align: center; padding: 2.5rem 1rem; }\n      .qe-interlude-icon { font-size: 2.5rem; margin-bottom: 0.5rem; }\n      .qe-interlude h2 { margin: 0 0 0.5rem; font-size: 1.4rem; }\n      .qe-interlude p { color: #6b7280; margin-bottom: 1.2rem; }\n      .qe-complete { text-align: center; padding: 2.5rem 1rem; }\n      .qe-trophy { font-size: 3rem; margin-bottom: 0.5rem; }\n      .qe-complete h2 { font-size: 1.6rem; margin: 0 0 0.5rem; }\n      .qe-score { font-size: 1.1rem; color: #374151; margin: 0 0 0.5rem; }\n      .qe-msg { font-size: 0.95rem; padding: 0.6rem 1rem; border-radius: 8px; display: inline-block; margin: 0.4rem 0 1.2rem; }\n      .qe-msg-good { background: #f0fdf4; color: #15803d; }\n      .qe-msg-ok { background: #fff7ed; color: #c2410c; }\n\n     \n    `;\n    document.head.appendChild(s);\n  }\n\n  \/* \u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  \/**\n   * init(rootId)\n   * @param {string} rootId - The id of the container element where the quiz will render.\n   *\n   * Call after both quiz-engine.js and the chapter quiz-data file have loaded.\n   *\/\n  function init(rootId) {\n    if (!window.QUIZ_DATA || !window.QUIZ_DATA.length) {\n      console.error('QuizEngine: window.QUIZ_DATA is missing or empty.');\n      return;\n    }\n    injectStyles();\n    root = document.getElementById(rootId);\n    if (!root) { console.error(`QuizEngine: element #${rootId} not found.`); return; }\n\n    allQuestions = window.QUIZ_DATA;\n    queue = shuffle(allQuestions.map(prepareQuestion));\n    nonPassed = [];\n    isFirstPass = true;\n    stats = { total: allQuestions.length, firstPassCorrect: 0, attempts: 0 };\n\n    renderQuestion();\n  }\n\n  return { init };\n\n})();\n\n<\/script>\n\n<script>window.QUIZ_DATA = [\n  {\n    question: \"En el String \\\"Hola Mundo\\\" \u00bfcu\u00e1l es el \u00edndice del caracter \\'a\\'?\",\n    options: [\n      { text: \"4\",   correct: false },\n      { text: \"3\",   correct: true  },\n      { text: \"5\",   correct: false  },\n      { text: \"0\",   correct: false  },\n    ],\n    hint: \"Los \u00edndices son secuenciales y empiezan en un n\u00famero que no es el que esperar\u00edas posiblemente.\",\n    explanation: \"Los \u00edndices empiezan en 0 y crecen de izquierda a derecha.\"\n  },\n  {\n    question: \"\u00bfCu\u00e1l de estas es la manera es la correcta para encontrar la longitud de un String?\",\n    options: [\n      { text: \"\\\"Hola\\\".length()\", correct: true },\n      { text: \"String.length(\\\"Hola\\\")\", correct: false  },\n      { text: \"length(\\\"Hola\\\")\", correct: false },\n      { text: \"length(\\'Hola\\')\", correct: false },\n    ],\n    hint: \"Los String son diferentes a los tipos primitivos y utilizan una sintaxis que no puedes isar con ellos.\",\n    explanation: \"Para llamar los m\u00e9todos de una clase, primero necesitas un valor de este tipo y con el operador punto pueden invocar el m\u00e9todo.\"\n  },\n  {\n    question: \"\u00bfCu\u00e1l no es un m\u00e9todo de String?\",\n    options: [\n      { text: \"size()\", correct: true },\n      { text: \"charAt(int)\", correct: false },\n      { text: \"indexOf(char)\", correct: false },\n      { text: \"substring(int)\",   correct: false },\n    ],\n    hint: \"Hay una de las opciones que tiene un nombre relacionado pero diferente al m\u00e9todo real.\",\n    explanation: \"Los m\u00e9todos m\u00e1s usados de String son: length(), charAt(int), indexOf(char), substring(int)\"\n  },\n  {\n    question: \"\u00bfCu\u00e1l es la manera de obtener el \u00faltimo caracter de un String llamado &laquo;s&raquo;?\",\n    options: [\n      { text: 's.charAt(s.length() - 1)',  correct: true },\n      { text: 's.charAt(s.length())', correct: false },\n      { text: 's.lastChar()', correct: false },\n      { text: 's.lastCharAt(s.length())', correct: false },\n    ],\n    hint: \"Si empiezas a contar los caracteres arrancando desde 0 en \\\"Hola\\\" cu\u00e1l es el \u00faltimo \u00edndice\",\n    explanation: \"No existe ninguna buena raz\u00f3n para reutilizar variables.\"\n  },\n  {\n    question: \"\u00bfCu\u00e1l de estas afirmaciones NO es cierta sobre caracteres de reemplazo para String.format()?\",\n    options: [\n      { text: \"%s convierte un String todo en min\u00fasculas.\", correct: true },\n      { text: \"%X convierte un int en un String con hexadecimales en may\u00fasculas.\", correct: false  },\n      { text: \"%2d convierte un int en un String con m\u00ednimo 2 caracteres usando espacios si hacen falta.\", correct: false },\n      { text: \"%5.2f convierte un double en un String con m\u00ednimo 5 caracteres y exactamente 2 d\u00edgitos decimales.\", correct: false },\n    ],\n    hint: \"En un c\u00f3digo puedes escribir variables de tipo int, boolean, double, char todos con diferente n\u00fameros de caracteres.\",\n    explanation: \"Una vez m\u00e1s, la legibilidad es mucho m\u00e1s importante de lo que podr\u00edas creer.\"\n  }\n];\n  <\/script>\n  \t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f844e64 elementor-widget-divider--view-line elementor-widget elementor-widget-divider\" data-id=\"f844e64\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"divider.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-divider\">\n\t\t\t<span class=\"elementor-divider-separator\">\n\t\t\t\t\t\t<\/span>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-d4f1c40 e-con-full e-flex e-con e-child\" data-id=\"d4f1c40\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-39ccefb elementor-widget elementor-widget-html\" data-id=\"39ccefb\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<link rel=\"license\" href=\"https:\/\/creativecommons.org\/licenses\/by\/4.0\/\">\r\n\r\n<link rel=\"stylesheet\" href=\"css\/main.css\">\r\n<link href=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/themes\/prism.css\" rel=\"stylesheet\" \/>\r\n<link href=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/plugins\/line-numbers\/prism-line-numbers.css\" rel=\"stylesheet\" \/>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/prism.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/components\/prism-java.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/prismjs@1.29.0\/plugins\/line-numbers\/prism-line-numbers.min.js\"><\/script>\r\n\r\n\r\n<h1 id=\"ejercicios-cap4\">Ejercicios<\/h1>\r\n<p>\r\n    \r\n<\/p>\r\n<h3>Errores del compilador y del tiempo de ejecuci\u00f3n<\/h3>\r\n\r\n<p>Escribe los siguientes c\u00f3digos y lee el error devuelto por el compilador o el entorno de\r\nejecuci\u00f3n. Luego escribe el c\u00f3digo correcto.<\/p>\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption><strong>E4.1<\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">boolean empiezaConMin\u00fascula(String s) {\r\n   var primerCaracter = String.charAt(s, 0);\r\n   return Character.isLowerCase(primerCaracter);\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; empiezaConMin\u00fascula(\"manzana\")\r\n&gt; empiezaConMin\u00fascula(\"Manzana\")    \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>true\r\nfalse                \r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n            <p>M\u00e9todo isLowerCase de Character: <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/Character.html#isLowerCase(char)\"> \"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/lang\/\r\n            Character.html#isLowerCase(char)\"><\/a><\/p>\r\n            <\/div>\r\n<\/aside>\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption><strong>E4.2<\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">String pluralizar(int conteo, String s) {\r\n   return (conteo &lt; 2) ? s : s.format(\"%d %ss\", conteo);\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; pluralizar(1, \"c\u00f3digo\")\r\n&gt; pluralizar(2, \"c\u00f3digo\")    \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"c\u00f3digo\"\r\n\"2 c\u00f3digos\"                \r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption><strong>E4.3<\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">boolean esVocal(char letra) {\r\n    var letraMin\u00fascula = Character.toLowerCase(letra);\r\n    return 'aeiou'.contains(Character.toString(letraMin\u00fascula));\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; esVocal('a')\r\n&gt; esVocal('A')\r\n&gt; esVocal('c')\r\n&gt; esVocal('@')   \r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>true\r\ntrue\r\nfalse\r\nfalse\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n            <p>M\u00e9todo toLowerCase de Character: <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/Character.html#toLowerCase(char)\">\"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/lang\/C\r\n               haracter.html#toLowerCase(char)\"><\/a><\/p>\r\n            <\/div>\r\n<\/aside>        \r\n\r\n<aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n            <p>M\u00e9todo contains de String: <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/String.html#contains(java.lang.CharSequence)\"> \"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/lang\/S\r\n               tring.html#contains(java.lang.CharSequence)\"><\/a><\/p>\r\n            <\/div>\r\n<\/aside>     \r\n\r\n<aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n            <p>M\u00e9todo toString de Character: <a href=\"https:\/\/docs.oracle.com\/en\/java\/javase\/26\/docs\/api\/java.base\/java\/lang\/Character.html#toString(char)\"> \"https:\/\/docs.oracle.com\/en\/java\/javase\/17\/docs\/api\/java.base\/java\/lang\/C\r\n               haracter.html#toString(char)\"><\/a><\/p>\r\n            <\/div>\r\n<\/aside>     \r\n\r\n<h4>Ejercicios de codificaci\u00f3n<\/h4>\r\n\r\n<h4><strong>E4.4<\/strong><\/h4>\r\n\r\n<p>Escribe una funci\u00f3n que tome un String y lo devuelva con la primera letra en may\u00fascula y las\r\ndem\u00e1s en min\u00fasculas (en ingl\u00e9s esto se llama title case).<\/p>\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption><strong>E4.4<\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">String titleCase(String texto) {\r\n    var primeraLetra = texto.substring(___, ___);\r\n    var restoDelTexto = texto.substring(___);\r\n    return String.format(\"%S%s\", primeraLetra, restoDelTexto.toLowerCase());\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; titleCase(\"java\")\r\n&gt; titleCase(\"Java\")\r\n&gt; titleCase(\"JAVA\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"Java\"\r\n\"Java\"\r\n\"Java\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><strong>E4.5<\/strong><\/h4>\r\n\r\n<p>Escribe una funci\u00f3n terminaEnS() que verifique si una palabra termina en la letra S.<\/p>\r\n\r\n<figure class=\"code-block\">\r\n          <figcaption><strong>E4.5<\/strong><\/figcaption>\r\n            <pre><code class=\"language-java\">boolean terminaEnS(String texto) {\r\n    var \u00faltimoCaracter = texto.___(texto.___ - 1);\r\n    return (\u00faltimoCaracter == 's') || (\u00faltimoCaracter == 'S');\r\n}<\/code><\/pre>\r\n        <\/figure>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; terminaEnS(\"mi\u00e9rcoles\")\r\n&gt; terminaEnS(\"jueves\")\r\n&gt; terminaEnS(\"s\u00e1bado\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>true\r\ntrue\r\nfalse\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><strong>E4.6<\/strong><\/h4>\r\n\r\n<p>Es \u00fatil cuando se intenta escribir una funci\u00f3n, codificar primero una versi\u00f3n m\u00e1s simple de la\r\n    misma y extenderla desde all\u00ed. Escribe una funci\u00f3n que verifique si un String de dos letras es un\r\n    pal\u00edndromo. Un pal\u00edndromo es una oraci\u00f3n que se lee igual independientemente de d\u00f3nde se\r\n    lea, p.j. \u201cAnita, lava la tina\".<\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; esPalindrome(\"ab\")\r\n&gt; esPalindrome(\"ee\")\r\n&gt; esPalindrome(\"Aa\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>false\r\ntrue\r\ntrue\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><strong>E4.7<\/strong><\/h4>\r\n\r\n <p>Escribe una funci\u00f3n esExterno() que tome una string que represente un enlace y devuelva\r\n    true si el enlace es externo. Para este ejercicio tenga en cuenta que los enlaces internos\r\n    comienzan con \u201c\/\u201d y los enlaces externos utilizan los protocolos \u201chttp\u201d o \u201chttps\u201d.  <\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; esExterno(\"\/definetely-internal\")\r\n&gt; esExterno(\"https:\/\/www.java.com\")\r\n&gt; esExterno(\"http:\/\/dont-go.com\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>false\r\ntrue\r\ntrue\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><strong>E4.8<\/strong><\/h4>\r\n\r\n <p>Escribe una funci\u00f3n extensi\u00f3n() que tome un String que represente una ruta a un archivo y\r\n    devuelva la extensi\u00f3n del archivo, todo lo que viene despu\u00e9s del \u00faltimo punto del archivo que es\r\n    parte del nombre del archivo. Las rutas pueden ser relativas o absolutas. Recuerda que es\r\n    posible que un archivo no tenga extensiones.  <\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; extension(\"debug.sh\")\r\n&gt; extension(\"\/path\/to\/debug.sh\")\r\n&gt; extension(\"\/the.dot\/file.java\")\r\n&gt; extension(\"no-extension\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"sh\"\r\n\"sh\"\r\n\"java\"\r\n\"\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><strong>E4.9<\/strong><\/h4>\r\n\r\n <p>El an\u00e1lisis de Strings es muy com\u00fan en la programaci\u00f3n y generalmente existen algunos tipos o\r\n    bibliotecas que ayudan con eso. Pero a veces solo necesitas una operaci\u00f3n muy espec\u00edfica, por\r\n    lo que puede tener sentido escribir una funci\u00f3n b\u00e1sica en lugar de agregar una dependencia\r\n    adicional. Escribe una funci\u00f3n que tome una URL y devuelva el dominio, la parte que viene\r\n    despu\u00e9s del protocolo y termina en la siguiente barra o al final de la string si no hay ninguna.\r\n    Puede suponer que todos los par\u00e1metros comenzar\u00e1n con \"https:\/\/\", que es el protocolo. <\/p>\r\n\r\n    <div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; domain(\"https:\/\/www.java.com\/en\/\")\r\n&gt; domain(\"https:\/\/jcp.org\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"www.java.com\"\r\n\"jcp.org\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><strong>E4.10<\/strong><\/h4>\r\n\r\n <p>\u00bfTe has preguntado c\u00f3mo se calcula la Semana Santa? El domingo de Pascua es el primer\r\n    domingo despu\u00e9s de la primera luna llena despu\u00e9s del equinoccio de primavera. Dado que las\r\n    lunas llenas se rigen por un ciclo distinto de los meses, cada a\u00f1o esta fecha cambia. Resulta\r\n    que hay un algoritmo que puede ayudar a tener en cuenta todos estos sucesos y es el que se\r\n    utiliza hoy en d\u00eda para determinar esa fecha. El algoritmo, dado el a\u00f1o, es el siguiente:<\/p>\r\n\r\n<figure class=\"code-block\">\r\n        <pre><code class=\"language-java\">var a = a\u00f1o % 19;\r\nvar b = a\u00f1o \/ 100;\r\nvar c = a\u00f1o % 100;\r\nvar d = b \/ 4;\r\nvar e = b % 4;\r\nvar g = ((8 * b) + 13) \/ 25;\r\nvar h = ((19 * a) + b - d - g + 15) % 30;\r\nvar i = c \/ 4;\r\nvar k = c % 4;\r\nvar l = (32 + (2 * e) + (2 * i) - h - k) % 7;\r\nvar m = (a + (11 * h) + (19 * l)) \/ 433;\r\n\/\/ n es el n\u00famero del mes, 3 = marzo, 4 = abril\r\nvar n = (h + l - (7 * m) + 90) \/ 25;\r\n\/\/ p es el d\u00eda del mes\r\nvar p = (h + l - (7 * m) + (33 * n) + 19) % 32;\r\n        <\/code><\/pre>\r\n        <\/figure>\r\n\r\n<p>Por ejemplo, si el a\u00f1o fuera 2024, entonces n = 3, p = 31<\/p>\r\n\r\n<p>Escribe una funci\u00f3n domingoDePascua(int) que dado un par\u00e1metro entero, el a\u00f1o a averiguar,\r\nretorne la fecha del domingo de pascua para ese a\u00f1o como un String con el formato\r\n\"YYYY\/mm\/dd\" es decir el a\u00f1o con sus 4 d\u00edgitos, el mes con 2 d\u00edgitos \"03\" para marzo y \"04\"\r\npara abril y el d\u00eda tambi\u00e9n con 2 d\u00edgitos, si el d\u00eda es menor de 10 con un 0 por delante, p.j. \"05\",\r\n\"21\", etc.<\/p>\r\n\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; domingoDePascua(2024)\r\n&gt; domingoDePascua(2025)\r\n&gt; domingoDePascua(1961)\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"2024\/03\/31\"\r\n\"2025\/04\/20\"\r\n\"1961\/04\/02\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n <aside class=\"aside-box question\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>Regresar una fecha como un String no es la mejor opci\u00f3n aunque es la \u00fanica\r\n                   de la que disponemos por ahora. \u00bfQu\u00e9 dificultades crees que puede tener?<\/p>\r\n            <\/div>\r\n        <\/aside>\r\n\r\n<h4><strong>E4.11<\/strong><\/h4>\r\n\r\n<p>Hay muchos m\u00e9todos para representar colores en un computador. Uno de ellos es usando el\r\nmodelo de color RGB en que los colores se describen utilizando diferentes intensidades de 3\r\ncolores: Rojo, Verde (Green en ingl\u00e9s) y Azul (Blue en ingl\u00e9s) Esta intensidad es un valor entre\r\n0 y 255.<\/p>\r\n\r\n<p>Aunque uno podr\u00eda representar un color RGB como un conjunto de 3 n\u00fameros entre 0 y 255, la\r\nmanera m\u00e1s com\u00fan de representarlos es con un String de 6 d\u00edgitos, donde los primeros 2\r\nrepresentan la intensidad del rojo, los siguientes 2 la intensidad del verde y los \u00faltimos 2 la\r\nintensidad del azul pero escritos en base hexadecimal o base 16 (la raz\u00f3n siendo que todos los\r\nn\u00fameros entre 0 y 255 se pueden escribir m\u00e1ximo con 2 d\u00edgitos)<\/p>\r\n\r\n<p>Escribe una funci\u00f3n hexString(int, int, int) que reciba 3 n\u00fameros enteros, en el rango de 0 a 255,\r\ny retorne un String con todos los caracteres en may\u00fasculas representando el n\u00famero RGB\r\ncomo un String.<\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; hexString(0, 0, 0)\r\n&gt; hexString(255, 255, 255)\r\n&gt; hexString(12, 15, 77)\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"000000\"\r\n\"FFFFFF\"\r\n\"0C0F4D\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/04\/taza.png\"\/ height=\"40\" width=\"40\">E4.12\r\n<\/h4>\r\n\r\n    <p>Escribe una funci\u00f3n correoElectronicoValido() que, dado un correo electr\u00f3nico, devuelva\r\n    true si es un correo electr\u00f3nico v\u00e1lido. A los efectos del ejercicio un correo electr\u00f3nico\r\n    v\u00e1lido tiene estas caracter\u00edsticas:<\/p>\r\n\r\n\r\n<p><ul><li>Tiene solo una @<\/li>\r\n<li>Tiene solo un \".\" despu\u00e9s de la @<\/li>\r\n<li>Hay al menos un car\u00e1cter antes de @<\/li>\r\n<li>Hay al menos un car\u00e1cter entre @ y el \u00faltimo \".\"<\/li>\r\n<li>Hay al menos un car\u00e1cter despu\u00e9s del \u00faltimo \".\"<\/li><\/ul><\/p>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; correoElectronicoValido(\"abc@me.com\")\r\n&gt; correoElectronicoValido(\"abc@me.\")\r\n&gt; correoElectronicoValido(\"abc@mecom\")\r\n&gt; correoElectronicoValido(\"abc@me@com\")\r\n&gt; correoElectronicoValido(\"@me.com\")\r\n&gt; correoElectronicoValido(\"a.bc@me.com\")\r\n&gt; correoElectronicoValido(\"abc@me.co.m\")\r\n&gt; correoElectronicoValido(\"a@c@me.com\")\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>true\r\nfalse\r\nfalse\r\nfalse\r\nfalse\r\ntrue\r\nfalse\r\nfalse\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<h4><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/04\/taza.png\"\/ height=\"40\" width=\"40\">E4.13\r\n<\/h4>\r\n\r\n    <p>En sitios web donde se muestra mucho texto en combinaci\u00f3n con otros elementos, es usual\r\ntener que cortar un t\u00edtulo por temas de espacio. Pero si cortamos un t\u00edtulo, es importante que\r\npodamos transmitir al lector que est\u00e1 leyendo un t\u00edtulo acortado y usualmente se hace esto\r\nagregando puntos suspensivos. A esta operaci\u00f3n de acortar un t\u00edtulo y agregar puntos\r\nsuspensivos si el t\u00edtulo fue acortado, lo llamaremos elipsificar (porque en ingl\u00e9s el caracter de\r\nlos puntos suspensivos se llama ellipsis)<\/p>\r\n\r\n<p>Escribe una funci\u00f3n para elipsificar un String. As\u00ed es como deber\u00eda funcionar:<\/p>\r\n\r\n<p><ul>\r\n    <li>Los puntos suspensivos solo se agregan si el texto se debe acortar y es el \u00faltimo car\u00e1cter del String en caso de estar presentes.<\/li>\r\n    <li>Los puntos suspensivos solo se agregan en un lugar donde antes hab\u00eda un espacio y no debe haber espacios inmediatamente antes del car\u00e1cter.<\/li>\r\n    <li>La cadena debe ser la m\u00e1s larga posible teniendo m\u00ednimo la longitud deseada m\u00e1s el car\u00e1cter de los puntos suspensivos.<\/li>\r\n<\/ul><\/p>\r\n\r\n<aside class=\"aside-box info\">\r\n            <div class=\"icon\"><\/div>\r\n            <div class=\"content\">\r\n                <p>Aunque en espa\u00f1ol el caracter se llama puntos suspensivos, es importante\r\n                   aclarar que no son 3 puntos uno detr\u00e1s de otro. De hecho es un caracter\r\n                   espec\u00edfico.<\/p>\r\n            <\/div>\r\n        <\/aside>\r\n\r\n<div class=\"io-example\">\r\n          <div class=\"input\">\r\n            <div class=\"label\">Input<\/div>\r\n<pre><code>&gt; elipsificar(\"Java is fun\", 4)\r\n&gt; elipsificar(\"Java is fun\", 6)\r\n&gt; elipsificar(\"Java is fun\", 11)\r\n&gt; elipsificar(\"Java is fun\", 20)\r\n<\/code><\/pre>\r\n          <\/div>\r\n        <div class=\"output\">\r\n          <div class=\"label\">Output<\/div>\r\n             <pre><code>\"Java\u2026\"\r\n\"Java is\u2026\"\r\n\"Java is fun\"\r\n\"Java is fun\"\r\n<\/code><\/pre>\r\n        <\/div>\r\n        <\/div>\r\n\r\n<p>Para todos los ejemplos, ten en cuenta que \"Java is fun\" es un String de 11 caracteres. El\r\nprimer ejemplo busca acortar el t\u00edtulo para que tenga solo 4 caracteres. El primer espacio\r\ndespu\u00e9s del cuarto caracter es el que se encuentra despu\u00e9s de \"Java\" que tiene una longitud\r\nmenor que el original, por lo tanto el String retornado es \"Java\u2026\". Para el segundo ejemplo, la\r\nlongitud m\u00e1xima es 6, pero no podemos partir ah\u00ed mismo porque partir\u00edamos la palabra \"is\", el\r\nprimer espacio despu\u00e9s de ese espacio es precisamente al final de la palabra \"is\". El String\r\nretornado es \"Java is\u2026\". Para los \u00faltimos 2 ejemplos, la cadena cuenta ya con menos o la\r\nmisma cantidad de caracteres necesaria as\u00ed que retornamos la cadena sin ning\u00fan cambio.<\/p>        \r\n\r\n\r\n<p>\u00a9 2022 Carlos Obreg\u00f3n. This work is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0)<\/p>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-22ef1b4 e-flex e-con-boxed e-con e-parent\" data-id=\"22ef1b4\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-d564aff elementor-widget elementor-widget-shortcode\" data-id=\"d564aff\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">\t\t<div data-elementor-type=\"container\" data-elementor-id=\"2038\" class=\"elementor elementor-2038\" data-elementor-post-type=\"elementor_library\">\n\t\t\t\t<div class=\"elementor-element elementor-element-95a4ae3 e-flex e-con-boxed e-con e-parent\" data-id=\"95a4ae3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-19c4dee elementor-widget elementor-widget-html\" data-id=\"19c4dee\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t   <script>\nfunction initChapterNav(activeIndex) {\n\n  \/* \u2500\u2500 Chapters \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  const chapters = [\n    {\n      title: \"Funciones\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/funciones\",\n      sections: [\n        { title: \"\u00a1Hola Mundo! \u00a1Hola Java!\", anchor: \"hola-java\" },\n        { title: \"\u00a1Hola Mundo! version 2.0\",  anchor: \"hola-java-refactor\" },\n        { title: \"Espacio en blanco\",          anchor: \"espacio-en-blanco\" },\n        { title: \"Comentarios\",                anchor: \"comentarios\" },\n        { title: \"Quiz\",                anchor: \"Quiz\" },\n        { title: \"Ejercicios\",                 anchor: \"ejercicios\" },\n      ]\n    },\n    {\n      title: \"Operadores\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/operadores\",\n      sections: [\n        { title: \"Tipos Primitivos\",          anchor: \"tipos-primitivos\" },\n        { title: \"Operadores Num\u00e9ricos\",      anchor: \"operadores-numericos\" },\n        { title: \"Operadores Relacionales\",   anchor: \"operadores-relacionales\" },\n        { title: \"Operadores L\u00f3gicos\",        anchor: \"operadores-logicos\" },\n        { title: \"Operador Ternario\",         anchor: \"operador-ternario\" },\n        { title: \"Diversi\u00f3n con Funciones\",   anchor: \"diversion-con-funciones\" },\n          { title: \"Quiz\",                anchor: \"Quiz\" },\n        { title: \"Ejercicios\",                anchor: \"ejercicios-cap2\" },\n      ]\n    },\n    {\n      title: \"Variables\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/variables\",\n      sections: [\n        { title: \"C\u00f3digo legado: c\u00f3digo sin var\",       anchor: \"codigo-sin-var\" },\n        { title: \"Cuidados con literales y variables\",  anchor: \"literales-variables\" },\n        { title: \"N\u00fameros M\u00e1gicos\",                     anchor: \"numeros-magicos\" },\n        { title: \"Reasignaciones\",                      anchor: \"reasignaciones\" },\n        { title: \"Misi\u00f3n secundaria: Casting\",          anchor: \"casting\" },\n        { title: \"Quiz\",          anchor: \"Quiz\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicios-cap3\" },\n      ]\n    },\n    {\n      title: \"String y StringBuilder\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/string-y-stringbuilder\",\n      sections: [\n          \n          { title: \"M\u00e9todos Destacados de String\",       anchor: \"metodos-destacados\" },\n        { title: \"String Format\",  anchor: \"string-format\" },\n        { title: \"StringBuilder\",                     anchor: \"stringbuilder\" },\n        { title: \"Misi\u00f3n secundaria: Inmutabilidad\",                      anchor: \"inmutabilidad\" },\n        { title: \"Quiz\",          anchor: \"quiz\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicios-cap4\" },\n        ]\n    },\n    {\n      title: \"Programas en Java\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/programas-en-java\",\n      sections: [     \n          { title: \"Paquetes\",       anchor: \"paquetes\" },\n        { title: \"Importaciones\",  anchor: \"importaciones\" },\n        { title: \"Importaciones Static\",                     anchor: \"importaciones-static\" },\n        { title: \"Constantes de Clase\",                      anchor: \"constantes-clase\" },\n        { title: \"Especificaciones\",                      anchor: \"especificaciones\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicios-cap5\" },\n        ]\n    },\n    {\n      title: \"Ciclos\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/ciclos\",\n      sections: [\n           { title: \"Operadores compuestos\",       anchor: \"operadores -compuestos\" },\n        { title: \"Ciclos For\",  anchor: \"ciclos-for\" },\n        { title: \"Strings\",                     anchor: \"strings\" },\n        { title: \"Ciclos For vs Ciclos While\",                      anchor: \"ciclosfor-cicloswhile\" },\n        { title: \"Ciclos Anidados\",                      anchor: \"ciclos-anidados\" },\n        { title: \"Strings de m\u00faltiples l\u00edneas\",                      anchor: \"strings-multipleslineas\" },\n         { title: \"Ciclos Infinitos\",                      anchor: \"ciclos-infinitos\" },\n          { title: \"Logs\",                          anchor: \"logs\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicios-cap6\" },\n        ]\n    },\n    {\n      title: \"Condicionales\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/condicionales\",\n      sections: [\n          \n           { title: \"Las muchas formas de switch\",       anchor: \"muchasformas\" },\n        { title: \"Las muchas formas de if\",  anchor: \"formas-if\" },\n        { title: \"Flujos de ejecuci\u00f3n con condicionales\",                     anchor: \"ejecuci\u00f3ncondicionales\" },\n        { title: \"Orden de condiciones\",                      anchor: \"condiciones\" },\n        { title: \"Switch vs If\",                      anchor: \"switch\" },\n        { title: \"m\u00faltiples retornos en una funci\u00f3n\",                      anchor: \"retornosfunci\u00f3n\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicios-cap7\" },\n        ]\n    },\n    {\n      title: \"Arreglos\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/arreglos\",\n      sections: [\n          { title: \"Arreglos como Par\u00e1metros\",       anchor: \"Comoparametros\" },\n        { title: \"Mutabilidad en los arreglos\",  anchor: \"mutabilidad\" },\n        { title: \"Par\u00e1metros de salida\",                     anchor: \"parametrossalida\" },\n        { title: \"Arreglos como valores de retorno\",                      anchor: \"arreglos-retorno\" },\n        { title: \"Valores predeterminados\",                      anchor: \"valores-predeterminados\" },\n        { title: \"Arreglos Multidimensionales\",                      anchor: \"a-multidimensionales\" },\n        { title: \"Copiar una matriz\",                      anchor: \"copiar-matriz\" },\n        { title: \"Iteraciones\",                      anchor: \"iteraciones\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicios-cap8\" },\n          ]\n    },\n    {\n      title: \"Miscel\u00e1nea de Ejercicios\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/miscelanea-de-ejercicios\/\",\n      sections: []\n    },\n    {\n      title: \"Tipos de Datos\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/tipos-de-datos\/\",\n      sections: [\n           { title: \"M\u00e9todos no accesores\",       anchor: \"metodosaccesores\" },\n        { title: \"Estatico vs No- Estatico\",  anchor: \"estatico\" },\n        { title: \"Igualdad\",                     anchor: \"igualdad\" },\n        { title: \"Implementaci\u00f3n por defecto de una clase\",                      anchor: \"implementacionclase\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicioscap9\" },\n        ]\n    },\n    {\n      title: \"Constructores\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/constructores\/\",\n      sections: [\n           { title: \"M\u00faltiples Constructores\",       anchor: \"multiplesconstructores\" },\n        { title: \"F\u00e1bricas Est\u00e1ticas\",  anchor: \"fabricasestaticas\" },\n        { title: \"Java Beans\",                     anchor: \"javabeans\" },\n        { title: \"Constructores Con Visibilidad por Defecto\",                      anchor: \"constructoresdefecto\" },\n         { title: \"Side Quest: Builders\",                      anchor: \"sidequestbuilders\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicioscap11\" },\n        ]\n    },\n    {\n      title: \"Referencias y Null\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/referencias-y-null\/\",\n      sections: [\n                  { title: \"Pasar por valor\",       anchor: \"pasarporvalor\" },\n        { title: \"NULL\",  anchor: \"null\" },\n        { title: \"Valores Nulos\",                     anchor: \"valoresnulos\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicioscap12\" },\n        ]\n    },\n    {\n      title: \"Enums\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/enums\/\",\n      sections: [\n           { title: \"Metodos y Atributos\",       anchor: \"metodosyatributos\" },\n        { title: \"Sobreescritura de M\u00e9todos por Constante\",  anchor: \"sobreescrituraconstante\" },\n        { title: \"Ejercicios\",                          anchor: \"ejercicioscapenums\" },\n        ]\n    },\n    {\n      title: \"Inmutabilidad\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/inmutabilidad\/\",\n      sections: [\n           { title: \"Mutabilidad en el interior\",       anchor: \"mutabilidadinterior\" },\n        { title: \"Withers\",  anchor: \"withers\" },\n        { title: \"Ejercicios\",                          anchor: \"ejerciciopuzzle\" },\n        ]\n    },\n    {\n      title: \"Manejo de Errores\",\n      url: \"https:\/\/www.bogotajvm.com.co\/starter-kit\/manejo-de-errores\/\",\n      sections: [\n          { title: \"Estrategia de Manejo de Errores\",       anchor: \"estrategiaerrores\" },\n        { title: \"El usuario final no debe ver un stacktrace\",  anchor: \"stacktrace\" },\n        { title: \"Cambios en el C\u00f3digo\",                     anchor: \"cambiosc\u00f3digo\" },\n        { title: \"Mensajes de Error\",                      anchor: \"mensajeserror\" },\n         { title: \"Librer\u00eda de Validaciones\",                      anchor: \"librer\u00edavalidaciones\" },\n        ]\n    }\n  ];\n\n  \/* \u2500\u2500 Styles \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  const CSS = `\n    #cn-toggle {\n      position: fixed;\n      bottom: 24px;\n      left: 24px;\n      width: clamp(44px, 6vw, 100px);\n      height: clamp(44px, 6vw, 100px);\n      border-radius: 50%;\n      background: #fff;\n      border: 1px solid #d0d0d0;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      cursor: pointer;\n      z-index: 9000;\n      box-shadow: 0 2px 8px rgba(0,0,0,.12);\n      transition: background .15s;\n      padding: 0;\n    }\n    #cn-toggle:hover { background: #f5f5f5; }\n    #cn-toggle svg {\n      color: black;\n      display: block;\n      width: clamp(18px, 2.4vw, 40px);\n      height: clamp(18px, 2.4vw, 40px);\n    }\n\n@media (prefers-color-scheme: dark) {\n#cn-toggle { background: #2a2a2a; border-color: #444; }\n#cn-toggle:hover { background: #333; }\n}\n\n    #cn-panel {\n      position: fixed;\n      bottom: calc(clamp(44px, 6vw, 100px) + 36px);\n      left: 24px;\n      width: 270px;\n      max-height: 72vh;\n      overflow-y: auto;\n      background: #fff;\n      border: 1px solid #d0d0d0;\n      border-radius: 12px;\n      padding: 10px 0;\n      z-index: 8999;\n      box-shadow: 0 4px 16px rgba(0,0,0,.10);\n      display: none;\n      box-sizing: border-box;\n      font-family: inherit;\n    }\n    #cn-panel.cn-open { display: block; }\n\n    @media (prefers-color-scheme: dark) {\n      #cn-panel { background: #1e1e1e; border-color: #444; box-shadow: 0 4px 16px rgba(0,0,0,.4); }\n    }\n\n    .cn-header {\n      font-size: 11px;\n      font-weight: 600;\n      letter-spacing: .07em;\n      text-transform: uppercase;\n      color: #999;\n      padding: 0 14px 8px;\n      border-bottom: 1px solid #eee;\n      margin-bottom: 4px;\n    }\n    @media (prefers-color-scheme: dark) {\n      .cn-header { color: #666; border-color: #333; }\n    }\n\n    .cn-chapter {\n      display: flex;\n      align-items: center;\n    }\n    .cn-chapter-link {\n      flex: 1;\n      padding: 7px 6px 7px 14px;\n      font-size: 13.5px;\n      line-height: 1.35;\n      color: #222;\n      text-decoration: none;\n      display: block;\n    }\n    .cn-chapter-link:hover { color: #0066cc; }\n    .cn-chapter-link.cn-active {\n      font-weight: 600;\n      color: #0066cc;\n    }\n    @media (prefers-color-scheme: dark) {\n      .cn-chapter-link { color: #ddd; }\n      .cn-chapter-link:hover, .cn-chapter-link.cn-active { color: #5aacff; }\n    }\n\n    .cn-expand-btn {\n      width: 30px;\n      height: 30px;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      cursor: pointer;\n      color: #bbb;\n      border-radius: 6px;\n      margin-right: 8px;\n      flex-shrink: 0;\n      background: none;\n      border: none;\n      padding: 0;\n      transition: color .15s, background .15s;\n    }\n    .cn-expand-btn:hover { color: #555; background: #f0f0f0; }\n    .cn-expand-btn svg { transition: transform .2s; display: block; }\n    .cn-expand-btn.cn-open svg { transform: rotate(90deg); }\n\n    @media (prefers-color-scheme: dark) {\n      .cn-expand-btn { color: #555; }\n      .cn-expand-btn:hover { color: #aaa; background: #2e2e2e; }\n    }\n\n    .cn-section-list {\n      display: none;\n      padding: 2px 8px 6px 28px;\n      border-bottom: 1px solid #f0f0f0;\n      margin-bottom: 2px;\n    }\n    .cn-section-list.cn-open { display: block; }\n\n    @media (prefers-color-scheme: dark) {\n      .cn-section-list { border-color: #2a2a2a; }\n    }\n\n    .cn-section-link {\n      display: block;\n      padding: 4px 0;\n      font-size: 12.5px;\n      line-height: 1.4;\n      color: #666;\n      text-decoration: none;\n    }\n    .cn-section-link:hover { color: #0066cc; }\n\n    @media (prefers-color-scheme: dark) {\n      .cn-section-link { color: #888; }\n      .cn-section-link:hover { color: #5aacff; }\n    }\n  `;\n\n  \/* \u2500\u2500 SVG icons \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n  function iconMenu() {\n    return `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\n      stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n      <line x1=\"4\" y1=\"6\" x2=\"20\" y2=\"6\"\/>\n      <line x1=\"4\" y1=\"12\" x2=\"20\" y2=\"12\"\/>\n      <line x1=\"4\" y1=\"18\" x2=\"20\" y2=\"18\"\/>\n    <\/svg>`;\n  }\n\n  function iconClose() {\n    return `<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\"\n      stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n      <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\"\/>\n      <line x1=\"19\" y1=\"5\" x2=\"5\" y2=\"19\"\/>\n    <\/svg>`;\n  }\n\n  function iconChevron() {\n    return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\"\n      stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n      <polyline points=\"9 18 15 12 9 6\"\/>\n    <\/svg>`;\n  }\n\n  \/* \u2500\u2500 Build UI \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 *\/\n\n  \/\/ Inject styles\n  const style = document.createElement(\"style\");\n  style.textContent = CSS;\n  document.head.appendChild(style);\n\n  \/\/ Build toggle button\n  const toggle = document.createElement(\"button\");\n  toggle.id = \"cn-toggle\";\n  toggle.setAttribute(\"aria-label\", \"Toggle navigation\");\n  toggle.innerHTML = iconMenu();\n\n  \/\/ Build panel\n  const panel = document.createElement(\"nav\");\n  panel.id = \"cn-panel\";\n  panel.setAttribute(\"aria-label\", \"Course navigation\");\n\n  const header = document.createElement(\"div\");\n  header.className = \"cn-header\";\n  header.textContent = \"Contenidos\";\n  panel.appendChild(header);\n\n  chapters.forEach(function (chapter, idx) {\n    const isActive = activeIndex !== undefined && idx === activeIndex;\n    const hasSections = chapter.sections && chapter.sections.length > 0;\n\n    \/\/ Chapter row\n    const row = document.createElement(\"div\");\n    row.className = \"cn-chapter\";\n\n    const link = document.createElement(\"a\");\n    link.className = \"cn-chapter-link\" + (isActive ? \" cn-active\" : \"\");\n    link.href = chapter.url;\n    link.textContent = chapter.title;\n    row.appendChild(link);\n\n    if (hasSections) {\n      \/\/ Expand button\n      const btn = document.createElement(\"button\");\n      btn.className = \"cn-expand-btn\" + (isActive ? \" cn-open\" : \"\");\n      btn.setAttribute(\"aria-label\", isActive ? \"Hide sections\" : \"Show sections\");\n      btn.innerHTML = iconChevron();\n      row.appendChild(btn);\n\n      \/\/ Section list\n      const sectionList = document.createElement(\"div\");\n      sectionList.className = \"cn-section-list\" + (isActive ? \" cn-open\" : \"\");\n\n      chapter.sections.forEach(function (section) {\n        const sLink = document.createElement(\"a\");\n        sLink.className = \"cn-section-link\";\n        sLink.href = isActive\n          ? \"#\" + section.anchor\n          : chapter.url + \"#\" + section.anchor;\n        sLink.textContent = section.title;\n        sectionList.appendChild(sLink);\n      });\n\n      btn.addEventListener(\"click\", function () {\n        const isOpen = sectionList.classList.contains(\"cn-open\");\n\n        \/\/ Close all section lists and reset all expand buttons\n        panel.querySelectorAll(\".cn-section-list\").forEach(function (list) {\n          list.classList.remove(\"cn-open\");\n        });\n        panel.querySelectorAll(\".cn-expand-btn\").forEach(function (b) {\n          b.classList.remove(\"cn-open\");\n          b.setAttribute(\"aria-label\", \"Show sections\");\n        });\n\n        \/\/ If it wasn't open before, open it now (clicking an open chapter just closes it)\n        if (!isOpen) {\n          sectionList.classList.add(\"cn-open\");\n          btn.classList.add(\"cn-open\");\n          btn.setAttribute(\"aria-label\", \"Hide sections\");\n        }\n      });\n\n      panel.appendChild(row);\n      panel.appendChild(sectionList);\n    } else {\n      panel.appendChild(row);\n    }\n  });\n\n  toggle.addEventListener(\"click\", function (e) {\n    e.stopPropagation();\n    const open = panel.classList.toggle(\"cn-open\");\n    toggle.innerHTML = open ? iconClose() : iconMenu();\n    toggle.setAttribute(\"aria-label\", open ? \"Close navigation\" : \"Open navigation\");\n  });\n\n  document.addEventListener(\"click\", function (e) {\n    if (!panel.contains(e.target) && !toggle.contains(e.target)) {\n      panel.classList.remove(\"cn-open\");\n      toggle.innerHTML = iconMenu();\n      toggle.setAttribute(\"aria-label\", \"Open navigation\");\n    }\n  });\n\n  document.body.appendChild(toggle);\n  document.body.appendChild(panel);\n}\n\n  \n    initChapterNav();\n  <\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>String y StringBuilder C\u00f3digo 1 &#8211; substring()String tel\u00e9fonoConFormato(String tel\u00e9fono) { var primerosTres = tel\u00e9fono.substring(0, 3); var siguientesTres = tel\u00e9fono.substring(3, 6); [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":315,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-657","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/pages\/657","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/comments?post=657"}],"version-history":[{"count":76,"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/pages\/657\/revisions"}],"predecessor-version":[{"id":2068,"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/pages\/657\/revisions\/2068"}],"up":[{"embeddable":true,"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/pages\/315"}],"wp:attachment":[{"href":"https:\/\/www.bogotajvm.com.co\/en\/wp-json\/wp\/v2\/media?parent=657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}