Reemplazar la última aparición en una cadena

JavaScriptJavaScriptBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, exploraremos la manipulación de cadenas en JavaScript implementando una función replaceLast. A diferencia del método replace incorporado, que reemplaza la primera aparición de un patrón, nuestra función se centrará específicamente en la última aparición. Esta capacidad es útil en muchos escenarios del mundo real, como actualizar extensiones de archivos, modificar URLs o limpiar texto.

A lo largo de este laboratorio, aprenderás sobre métodos de cadenas, expresiones regulares y cómo combinarlos para crear una función útil. Al final de este laboratorio, tendrás una comprensión sólida de las técnicas de manipulación de cadenas en JavaScript y una función reutilizable para tus proyectos de codificación.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL javascript(("JavaScript")) -.-> javascript/BasicConceptsGroup(["Basic Concepts"]) javascript/BasicConceptsGroup -.-> javascript/data_types("Data Types") javascript/BasicConceptsGroup -.-> javascript/comp_ops("Comparison Operators") javascript/BasicConceptsGroup -.-> javascript/logic_ops("Logical Operators") javascript/BasicConceptsGroup -.-> javascript/cond_stmts("Conditional Statements") javascript/BasicConceptsGroup -.-> javascript/functions("Functions") javascript/BasicConceptsGroup -.-> javascript/str_manip("String Manipulation") subgraph Lab Skills javascript/data_types -.-> lab-28594{{"Reemplazar la última aparición en una cadena"}} javascript/comp_ops -.-> lab-28594{{"Reemplazar la última aparición en una cadena"}} javascript/logic_ops -.-> lab-28594{{"Reemplazar la última aparición en una cadena"}} javascript/cond_stmts -.-> lab-28594{{"Reemplazar la última aparición en una cadena"}} javascript/functions -.-> lab-28594{{"Reemplazar la última aparición en una cadena"}} javascript/str_manip -.-> lab-28594{{"Reemplazar la última aparición en una cadena"}} end

Comprendiendo el problema y configurando el entorno

Antes de comenzar a codificar, entendamos qué debe hacer nuestra función replaceLast:

  1. Aceptar tres parámetros:

    • str: La cadena de entrada que se va a modificar
    • pattern: La subcadena o expresión regular a buscar
    • replacement: La cadena con la que se reemplazará la última aparición
  2. Devolver una nueva cadena con la última aparición del patrón reemplazada.

Creemos un archivo JavaScript para implementar nuestra función:

  1. Navegue hasta el directorio del proyecto en el explorador de archivos de WebIDE.
  2. Cree un nuevo archivo llamado replaceLast.js en el directorio replace-last.
  3. Agregue la siguiente estructura básica al archivo:
// Function to replace the last occurrence of a pattern in a string
function replaceLast(str, pattern, replacement) {
  // Our implementation will go here
  return str;
}

// We will add test cases here later

Para comprobar que todo está configurado correctamente, agreguemos una prueba simple:

// Example usage
console.log(replaceLast("Hello world world", "world", "JavaScript"));

Ahora, ejecutemos nuestro código para ver la salida actual:

  1. Abra la Terminal en WebIDE
  2. Navegue hasta el directorio replace-last:
    cd ~/project/replace-last
  3. Ejecute el archivo JavaScript utilizando Node.js:
    node replaceLast.js

Debería ver Hello world world en la salida porque nuestra función actualmente solo devuelve la cadena original sin realizar ningún cambio.

Implementando la lógica central de la función

Ahora que comprendemos el problema, implementemos la funcionalidad central de nuestra función replaceLast. Nos centraremos primero en manejar patrones de cadenas y luego abordaremos las expresiones regulares en el siguiente paso.

Cuando el patrón es una cadena, podemos usar el método lastIndexOf para encontrar la posición de la última aparición. Una vez que conocemos esta posición, podemos usar el método slice para reconstruir la cadena insertando el reemplazo.

Actualice su función replaceLast con la siguiente implementación:

function replaceLast(str, pattern, replacement) {
  // Ensure inputs are valid
  if (typeof str !== "string") {
    return str;
  }

  if (typeof pattern === "string") {
    // Find the position of the last occurrence
    const lastIndex = str.lastIndexOf(pattern);

    // If pattern not found, return original string
    if (lastIndex === -1) {
      return str;
    }

    // Rebuild the string with the replacement
    const before = str.slice(0, lastIndex);
    const after = str.slice(lastIndex + pattern.length);
    return before + replacement + after;
  }

  // We'll handle regex patterns in the next step
  return str;
}

Actualice sus casos de prueba para verificar que la función maneje correctamente los patrones de cadenas:

// Test cases for string patterns
console.log(replaceLast("Hello world world", "world", "JavaScript")); // Should output: "Hello world JavaScript"
console.log(replaceLast("abcabcabc", "abc", "123")); // Should output: "abcabc123"
console.log(replaceLast("abcdef", "xyz", "123")); // Should output: "abcdef" (pattern not found)

Ejecute el código nuevamente para ver la salida actualizada:

node replaceLast.js

Ahora debería ver la última aparición del patrón de cadena reemplazada en cada caso de prueba. Por ejemplo, "Hello world JavaScript" en lugar de "Hello world world".

Manejando patrones de expresiones regulares

Ahora, mejoremos nuestra función para manejar patrones de expresiones regulares. Cuando el patrón es una expresión regular, necesitamos:

  1. Encontrar todas las coincidencias en la cadena.
  2. Obtener la última coincidencia.
  3. Reemplazar esa última coincidencia con la cadena de reemplazo.

Actualice su función replaceLast para manejar patrones de expresiones regulares:

function replaceLast(str, pattern, replacement) {
  // Ensure inputs are valid
  if (typeof str !== "string") {
    return str;
  }

  // Handle string patterns
  if (typeof pattern === "string") {
    const lastIndex = str.lastIndexOf(pattern);
    if (lastIndex === -1) {
      return str;
    }
    const before = str.slice(0, lastIndex);
    const after = str.slice(lastIndex + pattern.length);
    return before + replacement + after;
  }

  // Handle regular expression patterns
  if (pattern instanceof RegExp) {
    // Create a new RegExp with global flag to find all matches
    const globalRegex = new RegExp(pattern.source, "g");

    // Find all matches
    const matches = str.match(globalRegex);

    // If no matches, return original string
    if (!matches || matches.length === 0) {
      return str;
    }

    // Get the last match
    const lastMatch = matches[matches.length - 1];

    // Find the position of the last match
    const lastIndex = str.lastIndexOf(lastMatch);

    // Rebuild the string with the replacement
    const before = str.slice(0, lastIndex);
    const after = str.slice(lastIndex + lastMatch.length);
    return before + replacement + after;
  }

  // If pattern is neither string nor RegExp, return original string
  return str;
}

Agregue casos de prueba para patrones de expresiones regulares:

// Test cases for string patterns
console.log(replaceLast("Hello world world", "world", "JavaScript")); // Should output: "Hello world JavaScript"
console.log(replaceLast("abcabcabc", "abc", "123")); // Should output: "abcabc123"
console.log(replaceLast("abcdef", "xyz", "123")); // Should output: "abcdef" (pattern not found)

// Test cases for regular expression patterns
console.log(replaceLast("Hello world world", /world/, "JavaScript")); // Should output: "Hello world JavaScript"
console.log(replaceLast("123 456 789", /\d+/, "numbers")); // Should output: "123 456 numbers"
console.log(replaceLast("abcdef", /xyz/, "123")); // Should output: "abcdef" (pattern not found)

Ejecute el código nuevamente para ver la salida actualizada:

node replaceLast.js

Tanto los patrones de cadenas como los patrones de expresiones regulares ahora deberían funcionar correctamente en la función replaceLast.

Optimización de la función y prueba de casos extremos

Nuestra función funciona para casos básicos, pero optimicémosla y manejemos algunos casos extremos:

  1. Debemos comprobar si la cadena de entrada está vacía.
  2. Podemos simplificar el manejo de expresiones regulares.
  3. Debemos manejar casos en los que el reemplazo no es una cadena.

Actualice su función replaceLast con estas optimizaciones:

function replaceLast(str, pattern, replacement) {
  // Ensure str is a string
  if (typeof str !== "string") {
    return str;
  }

  // If str is empty or pattern is not provided, return original string
  if (str === "" || pattern === undefined) {
    return str;
  }

  // Ensure replacement is a string
  if (replacement === undefined) {
    replacement = "";
  } else if (typeof replacement !== "string") {
    replacement = String(replacement);
  }

  // Handle string patterns
  if (typeof pattern === "string") {
    const lastIndex = str.lastIndexOf(pattern);
    if (lastIndex === -1) {
      return str;
    }
    return (
      str.slice(0, lastIndex) +
      replacement +
      str.slice(lastIndex + pattern.length)
    );
  }

  // Handle regular expression patterns
  if (pattern instanceof RegExp) {
    // Create a global version of the regex to find all matches
    const globalRegex = new RegExp(
      pattern.source,
      "g" + (pattern.ignoreCase ? "i" : "") + (pattern.multiline ? "m" : "")
    );

    // Find all matches
    const matches = str.match(globalRegex);

    // If no matches, return original string
    if (!matches || matches.length === 0) {
      return str;
    }

    // Get the last match
    const lastMatch = matches[matches.length - 1];

    // Find the position of the last match
    const lastIndex = str.lastIndexOf(lastMatch);

    // Rebuild the string with the replacement
    return (
      str.slice(0, lastIndex) +
      replacement +
      str.slice(lastIndex + lastMatch.length)
    );
  }

  // If pattern is neither string nor RegExp, return original string
  return str;
}

Agreguemos más casos de prueba para cubrir los casos extremos:

// Test cases for string patterns
console.log(replaceLast("Hello world world", "world", "JavaScript")); // Should output: "Hello world JavaScript"
console.log(replaceLast("abcabcabc", "abc", "123")); // Should output: "abcabc123"
console.log(replaceLast("abcdef", "xyz", "123")); // Should output: "abcdef" (pattern not found)

// Test cases for regular expression patterns
console.log(replaceLast("Hello world world", /world/, "JavaScript")); // Should output: "Hello world JavaScript"
console.log(replaceLast("123 456 789", /\d+/, "numbers")); // Should output: "123 456 numbers"
console.log(replaceLast("abcdef", /xyz/, "123")); // Should output: "abcdef" (pattern not found)

// Edge cases
console.log(replaceLast("", "abc", "123")); // Should output: "" (empty string)
console.log(replaceLast("abcdef", "", "123")); // Should output: "abcde123f" (empty pattern)
console.log(replaceLast("abcdef", "def", "")); // Should output: "abc" (empty replacement)
console.log(replaceLast("AbCdEf", /[a-z]/, "X")); // Should output: "AbCdEX" (case-sensitive regex)
console.log(replaceLast("AbCdEf", /[a-z]/i, "X")); // Should output: "AbCdEX" (case-insensitive regex)

Ejecute el código nuevamente para ver la salida actualizada:

node replaceLast.js

Esta versión de la función maneja más casos extremos y mantiene un código limpio. Ahora tiene una función replaceLast robusta lista para usar en sus proyectos.

Creación de un módulo y uso de la función

En este último paso, convertiremos nuestra función en un módulo de JavaScript adecuado que se pueda importar y usar en otros archivos. Esta es una práctica común en el desarrollo de JavaScript en el mundo real.

Primero, creemos un archivo de módulo para nuestra función. Cree un nuevo archivo llamado replaceLastModule.js en el directorio replace-last:

/**
 * Replaces the last occurrence of a pattern in a string.
 *
 * @param {string} str - The input string.
 * @param {string|RegExp} pattern - The pattern to replace (string or RegExp).
 * @param {string} replacement - The replacement string.
 * @returns {string} - The string with the last occurrence replaced.
 */
function replaceLast(str, pattern, replacement) {
  // Ensure str is a string
  if (typeof str !== "string") {
    return str;
  }

  // If str is empty or pattern is not provided, return original string
  if (str === "" || pattern === undefined) {
    return str;
  }

  // Ensure replacement is a string
  if (replacement === undefined) {
    replacement = "";
  } else if (typeof replacement !== "string") {
    replacement = String(replacement);
  }

  // Handle string patterns
  if (typeof pattern === "string") {
    const lastIndex = str.lastIndexOf(pattern);
    if (lastIndex === -1) {
      return str;
    }
    return (
      str.slice(0, lastIndex) +
      replacement +
      str.slice(lastIndex + pattern.length)
    );
  }

  // Handle regular expression patterns
  if (pattern instanceof RegExp) {
    // Create a global version of the regex to find all matches
    const globalRegex = new RegExp(
      pattern.source,
      "g" + (pattern.ignoreCase ? "i" : "") + (pattern.multiline ? "m" : "")
    );

    // Find all matches
    const matches = str.match(globalRegex);

    // If no matches, return original string
    if (!matches || matches.length === 0) {
      return str;
    }

    // Get the last match
    const lastMatch = matches[matches.length - 1];

    // Find the position of the last match
    const lastIndex = str.lastIndexOf(lastMatch);

    // Rebuild the string with the replacement
    return (
      str.slice(0, lastIndex) +
      replacement +
      str.slice(lastIndex + lastMatch.length)
    );
  }

  // If pattern is neither string nor RegExp, return original string
  return str;
}

// Export the function
module.exports = replaceLast;

Ahora, creemos otro archivo para usar nuestro módulo. Cree un nuevo archivo llamado app.js en el directorio replace-last:

// Import the replaceLast function
const replaceLast = require("./replaceLastModule");

// Examples of using the replaceLast function
console.log(
  "Example 1:",
  replaceLast("Hello world world", "world", "JavaScript")
);
console.log("Example 2:", replaceLast("abcabcabc", "abc", "123"));
console.log("Example 3:", replaceLast("file.txt.backup.txt", ".txt", ".md"));
console.log("Example 4:", replaceLast("123 456 789", /\d+/, "numbers"));
console.log(
  "Example 5:",
  replaceLast("The fox jumped over the lazy dog", /[a-z]+/i, "cat")
);

// Practical examples
const filePath = "/path/to/my/file.txt";
console.log("File with new extension:", replaceLast(filePath, ".txt", ".md"));

const url = "https://example.com/products/category/item?color=red";
console.log("URL with updated parameter:", replaceLast(url, "red", "blue"));

const htmlTag = "<div class='container'><p>Text</p></div>";
console.log(
  "HTML with replaced tag:",
  replaceLast(htmlTag, /<\/?\w+>/g, "<span>")
);

Ejecute la aplicación para ver cómo funciona el módulo:

node app.js

Debería ver la salida con todos los ejemplos que demuestran cómo se puede usar la función replaceLast en diversos escenarios.

Felicidades. Ha creado con éxito una útil función de utilidad de JavaScript y la ha empaquetado como un módulo que se puede reutilizar en sus proyectos.

Resumen

En este laboratorio, has aprendido cómo crear una función de utilidad de JavaScript que reemplaza la última aparición de un patrón en una cadena. A lo largo del proceso, has adquirido conocimientos valiosos sobre:

  • Métodos de manipulación de cadenas como lastIndexOf y slice
  • Trabajar con expresiones regulares en JavaScript
  • Manejar diferentes tipos de entradas y casos extremos
  • Crear y exportar módulos de JavaScript
  • Escribir código limpio y reutilizable con una documentación adecuada

La función replaceLast que has creado es una utilidad práctica que se puede utilizar en muchos escenarios del mundo real, como la manipulación de rutas de archivos, modificaciones de URL y procesamiento de texto. Este tipo de manipulación de cadenas es comúnmente necesario, pero no está directamente disponible en la biblioteca estándar de JavaScript.

Al entender los conceptos y técnicas cubiertos en este laboratorio, ahora estás mejor preparado para resolver problemas similares de manipulación de cadenas en tus futuros proyectos de programación.