¿Cómo se accede a los grupos coincidentes en una expresión regular de JavaScript?

Quiero hacer coincidir una parte de una cadena usando un expresión regular y luego acceda a esa subcadena entre paréntesis:

var myString = "something format_abc"; // I want "abc"

var arr = /(?:^|\s)format_(.*?)(?:\s|$)/.exec(myString);

console.log(arr);     // Prints: [" format_abc", "abc"] .. so far so good.
console.log(arr[1]);  // Prints: undefined  (???)
console.log(arr[0]);  // Prints: format_undefined (!!!)

¿Qué estoy haciendo mal?


Descubrí que no había nada de malo con el código de expresión regular anterior: la cadena real con la que estaba probando era esta:

"date format_%A"

Informar que "% A" no está definido parece un comportamiento muy extraño, pero no está directamente relacionado con esta pregunta, así que abrí una nueva, ¿Por qué una subcadena coincidente devuelve "indefinido" en JavaScript?.


El problema era que console.log toma sus parámetros como un printf declaración, y dado que la cadena que estaba registrando ("%A") tenía un valor especial, estaba tratando de encontrar el valor del siguiente parámetro.

preguntado el 11 de enero de 09 a las 05:01

22 Respuestas

Puede acceder a grupos de captura como este:

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
var match = myRegexp.exec(myString);
console.log(match[1]); // abc

Y si hay varias coincidencias, puede iterar sobre ellas:

var myString = "something format_abc";
var myRegexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
match = myRegexp.exec(myString);
while (match != null) {
  // matched text: match[0]
  // match start: match.index
  // capturing group n: match[n]
  console.log(match[0])
  match = myRegexp.exec(myString);
}

Editar: 2019-09-10

Como puede ver, la forma de iterar sobre múltiples coincidencias no fue muy intuitiva. Esto condujo a la propuesta de la String.prototype.matchAll método. Se espera que este nuevo método se envíe en el Especificación ECMAScript 2020. Nos brinda una API limpia y resuelve múltiples problemas. Se ha comenzado a aterrizar en los principales navegadores y motores JS como Chrome 73+ / Nodo 12+ y Firefox 67+.

El método devuelve un iterador y se usa de la siguiente manera:

const string = "something format_abc";
const regexp = /(?:^|\s)format_(.*?)(?:\s|$)/g;
const matches = string.matchAll(regexp);
    
for (const match of matches) {
  console.log(match);
  console.log(match.index)
}

Como devuelve un iterador, podemos decir que es perezoso, esto es útil cuando se manejan cantidades particularmente grandes de grupos de captura o cadenas muy grandes. Pero si lo necesita, el resultado se puede transformar fácilmente en una matriz utilizando el sintaxis extendida o Array.from método:

function getFirstGroup(regexp, str) {
  const array = [...str.matchAll(regexp)];
  return array.map(m => m[1]);
}

// or:
function getFirstGroup(regexp, str) {
  return Array.from(str.matchAll(regexp), m => m[1]);
}

Mientras tanto, si bien esta propuesta obtiene un apoyo más amplio, puede utilizar la paquete de calzas oficial.

Además, el funcionamiento interno del método es sencillo. Una implementación equivalente usando una función generadora sería la siguiente:

function* matchAll(str, regexp) {
  const flags = regexp.global ? regexp.flags : regexp.flags + "g";
  const re = new RegExp(regexp, flags);
  let match;
  while (match = re.exec(str)) {
    yield match;
  }
}

Se crea una copia de la expresión regular original; esto es para evitar efectos secundarios debidos a la mutación del lastIndex propiedad al pasar por los partidos múltiples.

Además, debemos asegurarnos de que la expresión regular tenga la global bandera para evitar un bucle infinito.

También me alegra ver que incluso se hizo referencia a esta pregunta de StackOverflow en el discusiones de la propuesta.

Respondido el 10 de Septiembre de 19 a las 15:09

+1 Tenga en cuenta que en el segundo ejemplo debe usar el objeto RegExp (no solo "/ myregexp /"), porque mantiene el valor lastIndex en el objeto. Sin usar el objeto Regexp, iterará infinitamente - ianaz

@ianaz: ¿No creo que sea verdad? http://jsfiddle.net/weEg9/ parece funcionar en Chrome, al menos. - flecha

¿Por qué hacer lo anterior en lugar de: var match = myString.match(myRegexp); // alert(match[1])? - John Allen

No se necesita una "nueva RegExp" explícita, sin embargo, el bucle infinito se producirá a menos que se especifique / g - George C.

Otra forma de no encontrarse con un bucle infinito es actualizar explícitamente la cadena, por ejemplo string = string.substring(match.index + match[0].length) - Olga

Aquí hay un método que puede utilizar para obtener el nTh grupo de captura para cada partido:

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);

Respondido 17 Abr '15, 07:04

Esta es una respuesta muy superior a las demás porque muestra correctamente la iteración sobre todas las coincidencias en lugar de obtener solo una. - Rob Evans

mnn tiene razón. Esto producirá un bucle infinito si la bandera 'g' no está presente. Tenga mucho cuidado con esta función. - Sal

Mejoré esto para que sea similar a re.findall () de python. Agrupa todas las coincidencias en una matriz de matrices. También corrige el problema del bucle infinito del modificador global. jsfiddle.net/ravishi/MbwpV - ravishi

@MichaelMikowski ahora acaba de ocultar su bucle infinito, pero su código se ejecutará lento. Yo diría que es mejor romper el código de una manera incorrecta para que lo detectes en el desarrollo. Poner algunas iteraciones máximas de BS es descuidado. Ocultar problemas en lugar de solucionar su causa raíz no es la respuesta. - Wallacer

@MichaelMikowski eso no es significativamente más lento cuando no estás alcanzando el límite de ejecución. Cuando lo estás, claramente es mucho más lento. No estoy diciendo que su código no funcione, estoy diciendo que en la práctica creo que causará más daño que bien. Las personas que trabajan en un entorno de desarrollo verán que el código funciona bien sin carga a pesar de realizar 10,000 ejecuciones innecesarias de una parte del código. Luego, lo enviarán a un entorno de producción y se preguntarán por qué su aplicación se cae bajo carga. En mi experiencia, es mejor si las cosas se rompen de una manera obvia y antes en el ciclo de desarrollo. - Wallacer

var myString = "something format_abc";
var arr = myString.match(/\bformat_(.*?)\b/);
console.log(arr[0] + " " + arr[1]);

La \b no es exactamente lo mismo. (Funciona en --format_foo/, pero no funciona en format_a_b) Pero quería mostrar una alternativa a tu expresión, lo cual está bien. Por supuesto, el match llamar es lo importante.

contestado el 23 de mayo de 17 a las 17:05

Es exactamente al revés. '\ b' delimita palabras. palabra = '\ w' = [a-zA-Z0-9_]. "format_a_b" es una palabra. - BF

@BFHonestly, agregué "no funciona en format_a_b"como un pensamiento posterior hace 6 años, y no recuerdo lo que quise decir allí ... :-) Supongo que significaba" no funciona para capturar a sólo ", es decir, la primera parte alfabética después de format_. - Filho

Quería decir que \ b (- format_foo /} \ b no devuelve "--format_foo /" porque "-" y "/" no son caracteres de \ word. Pero \ b (format_a_b) \ b devuelve "format_a_b ". ¿Verdad? Me refiero a su declaración de texto entre corchetes. (¡No voté en contra!) - BF

En lo que respecta a los ejemplos de paréntesis de múltiples coincidencias anteriores, estaba buscando una respuesta aquí después de no obtener lo que quería de:

var matches = mystring.match(/(?:neededToMatchButNotWantedInResult)(matchWanted)/igm);

Después de mirar las llamadas de función ligeramente complicadas con while y .push () arriba, me di cuenta de que el problema se puede resolver de manera muy elegante con mystring.replace () en su lugar (el reemplazo NO es el punto, y ni siquiera está hecho , la opción de llamada de función recursiva integrada y LIMPIA para el segundo parámetro es!):

var yourstring = 'something format_abc something format_def something format_ghi';

var matches = [];
yourstring.replace(/format_([^\s]+)/igm, function(m, p1){ matches.push(p1); } );

Después de esto, no creo que vuelva a usar .match () para casi nada.

Respondido 17 Jul 14, 05:07

Por último, pero no menos importante, encontré una línea de código que funcionó bien para mí (JS ES6):

let reg = /#([\S]+)/igm; // Get hashtags.
let string = 'mi alegría es total! ✌🙌\n#fiestasdefindeaño #PadreHijo #buenosmomentos #france #paris';

let matches = (string.match(reg) || []).map(e => e.replace(reg, '$1'));
console.log(matches);

Esto devolverá:

['fiestasdefindeaño', 'PadreHijo', 'buenosmomentos', 'france', 'paris']

Respondido el 21 de diciembre de 18 a las 14:12

¡AUGE! Eso es La la solución más elegante aquí. Encontré esto mejor que el completo replace enfoque de Alexz porque este es menos anticipado y más elegante para múltiples resultados. Buen trabajo en esto, Sebastien H. - Cody

Esto funciona tan bien que su que probar definitivamente entrando en mis utilidades :) - Cody

¡Esto es mucho mejor que las otras respuestas! ¡Gracias! - Owen Versteeg

String#matchAll (Véase el Borrador de la Etapa 3 / Propuesta del 7 de diciembre de 2018), simplifica el acceso a todos los grupos en el objeto de coincidencia (tenga en cuenta que el Grupo 0 es la coincidencia completa, mientras que los grupos adicionales corresponden a los grupos de captura en el patrón):

Con matchAll disponible, puede evitar el while bucle y exec con /g... En cambio, usando matchAll, obtiene un iterador que puede usar con el método más conveniente for...of, dispersión de matriz o el Array.from() construcciones

Este método produce una salida similar a Regex.Matches C ª#, re.finditer en Python, preg_match_all en PHP.

Vea una demostración de JS (probado en Google Chrome 73.0.3683.67 (compilación oficial), beta (64 bits)):

var myString = "key1:value1, key2-value2!!@key3=value3";
var matches = myString.matchAll(/(\w+)[:=-](\w+)/g);
console.log([...matches]); // All match with capturing group values

La console.log([...matches]) enseñe

enter image description here

También puede obtener un valor de coincidencia o valores de grupo específicos usando

let matchData = "key1:value1, key2-value2!!@key3=value3".matchAll(/(\w+)[:=-](\w+)/g)
var matches = [...matchData]; // Note matchAll result is not re-iterable

console.log(Array.from(matches, m => m[0])); // All match (Group 0) values
// => [ "key1:value1", "key2-value2", "key3=value3" ]
console.log(Array.from(matches, m => m[1])); // All match (Group 1) values
// => [ "key1", "key2", "key3" ]

NOTA: Ver el compatibilidad del navegador Detalles.

respondido 08 mar '19, 08:03

Ejemplo perfecto para pares clave-valor. Conciso y fácil de leer, muy sencillo de usar. Además, un mejor manejo de errores, la extensión devolverá una matriz vacía en lugar de nula, por lo que no más 'error, no propiedad' longitud 'de nulo' - Jarrod McGuire

Terminología utilizada en esta respuesta:

  • Match indica el resultado de ejecutar su patrón RegEx contra su cadena de la siguiente manera: someString.match(regexPattern).
  • Patrones coincidentes indicar todas las partes coincidentes de la cadena de entrada, que residen dentro de la partido formación. Todas estas son instancias de su patrón dentro de la cadena de entrada.
  • Grupos emparejados indican todos los grupos a capturar, definidos en el patrón RegEx. (Los patrones entre paréntesis, así: /format_(.*?)/g, Donde (.*?) sería un grupo emparejado.) Estos residen dentro de patrones combinados.

Descripción

Para acceder a la grupos emparejados, en cada uno de los patrones combinados, necesita una función o algo similar para iterar sobre el partido. Hay varias formas de hacer esto, como muestran muchas de las otras respuestas. La mayoría de las otras respuestas usan un ciclo while para iterar sobre todas patrones combinados, pero creo que todos conocemos los peligros potenciales con ese enfoque. Es necesario emparejar contra un new RegExp() en lugar de solo el patrón en sí, que solo se mencionó en un comentario. Esto se debe a que .exec() El método se comporta de manera similar a un función del generador , se detiene cada vez que hay un partido, pero mantiene su .lastIndex para continuar de ahí en el siguiente .exec() llamada.

Ejemplos de código

A continuación se muestra un ejemplo de una función searchString que devuelve un Array de todos patrones combinados, donde cada match es un Array con todo lo que contiene grupos emparejados. En lugar de usar un ciclo while, he proporcionado ejemplos usando tanto el Array.prototype.map() funcionar, así como de una manera más eficaz, utilizando un for-círculo.

Versiones concisas (menos código, más azúcar sintáctico)

Estos son menos eficaces ya que básicamente implementan una forEach-loop en lugar del más rápido for-círculo.

// Concise ES6/ES2015 syntax
const searchString = 
    (string, pattern) => 
        string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match => 
            new RegExp(pattern.source, pattern.flags)
            .exec(match));

// Or if you will, with ES5 syntax
function searchString(string, pattern) {
    return string
        .match(new RegExp(pattern.source, pattern.flags))
        .map(match =>
            new RegExp(pattern.source, pattern.flags)
            .exec(match));
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

Versiones de alto rendimiento (más código, menos azúcar sintáctico)

// Performant ES6/ES2015 syntax
const searchString = (string, pattern) => {
    let result = [];

    const matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (let i = 0; i < matches.length; i++) {
        result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
};

// Same thing, but with ES5 syntax
function searchString(string, pattern) {
    var result = [];

    var matches = string.match(new RegExp(pattern.source, pattern.flags));

    for (var i = 0; i < matches.length; i++) {
        result.push(new RegExp(pattern.source, pattern.flags).exec(matches[i]));
    }

    return result;
}

let string = "something format_abc",
    pattern = /(?:^|\s)format_(.*?)(?:\s|$)/;

let result = searchString(string, pattern);
// [[" format_abc", "abc"], null]
// The trailing `null` disappears if you add the `global` flag

Todavía tengo que comparar estas alternativas con las mencionadas anteriormente en las otras respuestas, pero dudo que este enfoque sea menos eficaz y menos seguro que los demás.

Respondido 23 ago 17, 23:08

Tu sintaxis probablemente no sea la mejor para conservar. FF / Gecko define RegExp como una extensión de Function.
(FF2 fue tan lejos como typeof(/pattern/) == 'function')

Parece que esto es específico de FF: IE, Opera y Chrome arrojan excepciones para él.

En su lugar, use cualquiera de los métodos mencionados anteriormente por otros: RegExp#exec or String#match.
Ofrecen los mismos resultados:

var regex = /(?:^|\s)format_(.*?)(?:\s|$)/;
var input = "something format_abc";

regex(input);        //=> [" format_abc", "abc"]
regex.exec(input);   //=> [" format_abc", "abc"]
input.match(regex);  //=> [" format_abc", "abc"]

Respondido el 11 de enero de 09 a las 12:01

No es necesario invocar el exec ¡método! Puede utilizar el método "coincidencia" directamente en la cadena. No olvides los paréntesis.

var str = "This is cool";
var matches = str.match(/(This is)( cool)$/);
console.log( JSON.stringify(matches) ); // will print ["This is cool","This is"," cool"] or something like that...

La posición 0 tiene una cadena con todos los resultados. La posición 1 tiene la primera coincidencia representada por paréntesis y la posición 2 tiene la segunda coincidencia aislada entre paréntesis. Los paréntesis anidados son complicados, ¡así que ten cuidado!

Respondido 11 ago 17, 19:08

Sin la bandera global, esto devuelve todas las coincidencias, con ella, solo obtendrás una grande, así que ten cuidado con eso. - Shadymilkman01

Un trazador de líneas que es práctico solo si tiene un solo par de paréntesis:

while ( ( match = myRegex.exec( myStr ) ) && matches.push( match[1] ) ) {};

Respondido 12 Jul 14, 16:07

Por qué no while (match = myRegex.exec(myStr)) matches.push(match[1]) - Willlma

Con es2018 ahora puedes String.match() con grupos con nombre, hace que su expresión regular sea más explícita de lo que estaba tratando de hacer.

const url =
  'https://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression?some=parameter';
const regex = /(?<protocol>https?):\/\/(?<hostname>[\w-\.]*)\/(?<pathname>[\w-\./]+)\??(?<querystring>.*?)?$/;
const { groups: segments } = url.match(regex);
console.log(segments);

y obtendrás algo como

{protocolo: "https", nombre de host: "stackoverflow.com", nombre de ruta: "preguntas / 432493 / cómo-accedes-a-los-grupos-coincidentes-en-una-expresión-regular-javascript", cadena de consulta: " algunos = parámetro "}

Respondido 11 Feb 19, 16:02

Usando el código:

console.log(arr[1]);  // prints: abc
console.log(arr[0]);  // prints:  format_abc

Editar: Safari 3, si importa.

Respondido el 11 de enero de 09 a las 07:01

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'Rs.200 is Debited to A/c ...2031 on 02-12-14 20:05:49 (Clear Bal Rs.66248.77) AT ATM. TollFree 1800223344 18001024455 (6am-10pm)';
var myRegEx = /clear bal.+?(\d+\.?\d{2})/gi;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);

function getMatches(string, regex, index) {
  index || (index = 1); // default to the first capturing group
  var matches = [];
  var match;
  while (match = regex.exec(string)) {
    matches.push(match[index]);
  }
  return matches;
}


// Example :
var myString = 'something format_abc something format_def something format_ghi';
var myRegEx = /(?:^|\s)format_(.*?)(?:\s|$)/g;

// Get an array containing the first capturing group for every match
var matches = getMatches(myString, myRegEx, 1);

// Log results
document.write(matches.length + ' matches found: ' + JSON.stringify(matches))
console.log(matches);

Respondido el 22 de junio de 17 a las 21:06

Su código funciona para mí (FF3 en Mac) incluso si estoy de acuerdo con Filo que la expresión regular probablemente debería ser:

/\bformat_(.*?)\b/

(Pero, por supuesto, no estoy seguro porque no conozco el contexto de la expresión regular).

contestado el 23 de mayo de 17 a las 13:05

es una lista separada por espacios, así que pensé que estaría bien. extraño que ese código no funcionara para mí (FF3 Vista) - apodo

Sí, realmente extraño. ¿Lo has probado solo en la consola de Firebug? Me refiero a una página por lo demás vacía. - PEZ

/*Regex function for extracting object from "window.location.search" string.
 */

var search = "?a=3&b=4&c=7"; // Example search string

var getSearchObj = function (searchString) {

    var match, key, value, obj = {};
    var pattern = /(\w+)=(\w+)/g;
    var search = searchString.substr(1); // Remove '?'

    while (match = pattern.exec(search)) {
        obj[match[0].split('=')[0]] = match[0].split('=')[1];
    }

    return obj;

};

console.log(getSearchObj(search));

Respondido el 27 de junio de 15 a las 19:06

Realmente no necesita un bucle explícito para analizar múltiples coincidencias; pase una función de reemplazo como segundo argumento como se describe en: String.prototype.replace(regex, func):

var str = "Our chief weapon is {1}, {0} and {2}!"; 
var params= ['surprise', 'fear', 'ruthless efficiency'];
var patt = /{([^}]+)}/g;

str=str.replace(patt, function(m0, m1, position){return params[parseInt(m1)];});

document.write(str);

La m0 El argumento representa la subcadena coincidente completa {0}, {1}, etc. m1 representa el primer grupo coincidente, es decir, la parte encerrada entre corchetes en la expresión regular que es 0 para el primer partido. Y position es el índice inicial dentro de la cadena donde se encontró el grupo coincidente, sin usar en este caso.

Respondido 16 Feb 19, 06:02

Podemos acceder al grupo coincidente en expresiones regulares usando una barra invertida seguida del número del grupo coincidente:

/([a-z])\1/

En el código \ 1 representado por el primer grupo ([az])

Respondido 22 Jul 19, 05:07

Solución de una línea:

const matches = (text,regex) => [...text.matchAll(regex)].map(([match])=>match)

Entonces puede usar de esta manera (debe usar / g):

matches("something format_abc", /(?:^|\s)format_(.*?)(?:\s|$)/g)

resultado:

[" format_abc"]

Respondido 07 Abr '20, 15:04

SOLO UTILICE RegExp. $ 1 ... $ n ésimo grupo, por ejemplo:

1.Para igualar la expresión regular del primer grupo $ 1

  1. Para igualar la expresión regular del segundo grupo $ 2

si usa 3 grupos en regex likey (tenga en cuenta el uso después de string.match (regex))

RegExp. $ 1 RegExp. $ 2 RegExp. $ 3

 var str = "The rain in ${india} stays safe"; 
  var res = str.match(/\${(.*?)\}/ig);
  //i used only one group in above example so RegExp.$1
console.log(RegExp.$1)

//easiest way is use RegExp.$1 1st group in regex and 2nd grounp like
 //RegExp.$2 if exist use after match

var regex=/\${(.*?)\}/ig;
var str = "The rain in ${SPAIN} stays ${mainly} in the plain"; 
  var res = str.match(regex);
for (const match of res) {
  var res = match.match(regex);
  console.log(match);
  console.log(RegExp.$1)
 
}

Respondido 13 Abr '20, 11:04

Obtener todas las ocurrencias grupales

let m=[], s = "something format_abc  format_def  format_ghi";

s.replace(/(?:^|\s)format_(.*?)(?:\s|$)/g, (x,y)=> m.push(y));

console.log(m);

Respondido 20 ago 19, 21:08

Yo eres como yo y deseo que regex devuelva un Objeto como este:

{
    match: '...',
    matchAtIndex: 0,
    capturedGroups: [ '...', '...' ]
}

luego recorta la función desde abajo

/**
 * @param {string | number} input
 *          The input string to match
 * @param {regex | string}  expression
 *          Regular expression 
 * @param {string} flags
 *          Optional Flags
 * 
 * @returns {array}
 * [{
    match: '...',
    matchAtIndex: 0,
    capturedGroups: [ '...', '...' ]
  }]     
 */
function regexMatch(input, expression, flags = "g") {
  let regex = expression instanceof RegExp ? expression : new RegExp(expression, flags)
  let matches = input.matchAll(regex)
  matches = [...matches]
  return matches.map(item => {
    return {
      match: item[0],
      matchAtIndex: item.index,
      capturedGroups: item.length > 1 ? item.slice(1) : undefined
    }
  })
}

let input = "key1:value1, key2:value2 "
let regex = /(\w+):(\w+)/g

let matches = regexMatch(input, regex)

console.log(matches)

respondido 05 mar '20, 05:03

Como dijo @cms en ECMAScript (ECMA-262) puede usar matchAll. Devuelve un iterador y al ponerlo en [... ] (operador de propagación) se convierte en una matriz. (esta expresión regular extrae las URL de los nombres de archivo)

let text = `<a href="http://myhost.com/myfile_01.mp4">File1</a> <a href="http://myhost.com/myfile_02.mp4">File2</a>`;

let fileUrls = [...text.matchAll(/href="(http\:\/\/[^"]+\.\w{3})\"/g)].map(r => r[1]);

console.log(fileUrls);

Respondido 18 ago 20, 14:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.