Entonces, para aclararlo, digamos que tengo esta cadena:
command [stuff] [stuff [inside] this] "string" "another [thing] string"
Dentro de mi código quiero tomar todas las cosas entre comillas y ponerlas en una matriz y tomar todas las cosas dentro de la mayoría de los corchetes exteriores (todo dentro de los corchetes exteriores) y ponerlos en su propia matriz. Al igual que:
const string = `command [stuff] [stuff [inside] this] "string" "another [thing] string"`; let quotations = ["string", "another [thing] string"] let brackets = ["stuff", "stuff [inside] this"] // I do not want to include any brackets found inside of quotation marksHe intentado hacer una expresión regular que haga esto, pero tengo muchos problemas para entender cómo lo configuraría. Encontré estas dos expresiones regulares que encuentran las cosas entre comillas y corchetes, pero no son 100% lo que estoy buscando:
// JavaScript Regex const regexStrings = /(["'])(?:(?=(\\?))\2.)*?\1/g; const regexBrackets = /\[(.*?)\]/g;Aquí hay un intento.
La expresión regular para las comillas intentará encontrar las que no sean comillas entre comillas.
La expresión regular para los corchetes primero intentará hacer coincidir las comillas que no están entre comillas, y luego las cosas entre corchetes.
Luego filtra las coincidencias que comienzan con una cita.
No hay recursividad, por lo que es solo 1 nivel de corchetes opcionales entre corchetes.
const string = `command [stuff] [stuff [inside] this] "string" "another [thing] string"`; // JavaScript Regex const regexStrings = /"[^"]*"|'[^']'/g; const regexBrackets = /"[^"]*"|'[^']'|(\[[^\[\]]*(?:\[[^\[\]]*\])?[^\[\]]*\])/g; let quotations = string.match(regexStrings) .map(x=>x.replace(/^["']|["']$/g,'')); let brackets = string.match(regexBrackets).filter(x=>!/^["']/.test(x)); console.log(quotations); console.log(brackets);Para obtener los corchetes anidados de varios niveles, aquí hay un tokenizador adicional.
function getQuotesAndBrackets(str) { const re = /(["'])(?:\\.|.)*?\1|[\[\]]|[^"'\[\]]+/g; let quoted = []; let bracketed = []; let token = ''; let cnt = 0; let m; let nest = ""; while(m = re.exec(str)) { token = m[0][0]; if(cnt==0 && /["']/.test(token)) { quoted.push(m[0]) } else if(token === '[') { nest += token; cnt += 1 } else if(token === ']') { nest += token; if(cnt > 1) { cnt -= 1 } else { bracketed.push(nest); nest = ""; cnt = 0 } } else if(cnt > 0) { nest += m[0] } } return {"quotes":quoted, "brackets":bracketed}; } // TEST const string = `all "the [quoted]" [ stuff [inside ["this"] [bracketed] ] ] "thing" [['blah']]`; let quotes_and_brackets = getQuotesAndBrackets(string); console.log(quotes_and_brackets);No hay soporte para la recursividad en la sintaxis de expresiones regulares de JavaScript, por lo que deberá agregar algo de código para hacer frente a una profundidad arbitraria de anidamiento de corchetes.
Por lo tanto, optaría por dividir la cadena en:
'"[][ o ]Luego use un contador de profundidad para realizar un seguimiento de la profundidad de los corchetes para que sepa cuándo construir una subcadena de corchetes concatenando los tokens en el camino.
Aquí hay un fragmento, usando una cadena de entrada un poco más compleja que la que proporcionaste:
function solve(str) { let tokens = str.match(/(['"])((\\.|.)*?)\1|[^[\]'"]+|./g); let brackets = []; let quotations = []; let bracket = ""; let depth = 0; for (let token of tokens) { if (token[0] === '"' || token[0] === "'") { quotations.push(token.slice(1, -1)); } else if (token === "[") { depth++; } else if (token === "]") { depth--; if (depth < 0) throw "Unbalanced brackets"; if (!depth) { brackets.push(bracket.slice(1)); bracket = ""; } } if (depth) bracket += token; } if (depth) throw "Unbalanced brackets"; return {quotations, brackets}; } const string = String.raw`command [stuff] [stuff [inside [very inside with "escaped \" bracket:]" ]] this] "string" "another [thing] string"`; console.log(solve(string));Supongamos que la cadena dada es la siguiente.
'command [stuff] [stuff [inside] this] "string" "another [thing] string"' bbbbb bbbbbbbbbbbbbbbbbbb dddddd dddddddddddddddddddddd Deseamos extraer los valores marcados con bbb... (entre corchetes) a una matriz y los valores marcados con ddd... (entre comillas dobles) a una segunda matriz. Esto se puede hacer en dos pasos.
Paso 1: extraiga todas las cadenas entre comillas dobles y reemplace esas coincidencias, incluidas las comillas dobles circundantes, con cadenas vacías
Reemplace las coincidencias de la siguiente expresión regular (con el indicador g establecido) con cadenas vacías. 1
"([^"]*)"eso regresará
'command [stuff] [stuff [inside] this] ' bbbbb bbbbbbbbbbbbbbbbbbbque usaremos en el segundo paso, como se muestra a continuación.
Además, el contenido del grupo de captura 1 será 'string' y 'another [thing] string' , que debemos guardar.
Esta expresión dice: "haga coincidir una comilla doble seguida de cero o más caracteres que no sean una comilla doble, seguida de una comilla doble, con la cadena delimitada por las comillas dobles guardada para capturar el grupo 1".
Paso 2: extraiga todas las cadenas delimitadas con corchetes que no están dentro de una cadena delimitada con corchetes
Podemos obtener las cadenas de interés ( 'stuff' y 'stuff [inside] this' ) haciendo coincidir la expresión regular
(?<=\[)[^\[\]]*(?:\[[^\[\]]*\])?[^\[\]]*(?=\])Esta expresión se puede descomponer de la siguiente manera.
(?<=\[) # positive lookbehind asserts match is preceded by '[' [^\[\]]* # match 0+ chars other than '[' and ']' (?: # begin non-capture group \[ # match '[' [^\[\]]* # match 0+ chars other than '[' and ']' \] # match ']' )? # end non-capture group and make it optional [^\[\]]* # match 0+ chars other than '[' and ']' (?=\]) # positive lookahead asserts match is followed by ']'Tenga en cuenta que esta expresión no funciona con más de un nivel de anidamiento, como
'[stuff [inside [stuff] like] this]' bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbLa expresión regular que he dado podría modificarse para manejar hasta cualquier número dado de niveles de anidamiento extendiendo el enfoque que he tomado, pero se vuelve difícil de manejar para más de tres niveles de anidamiento.
1. Alternativamente, podríamos escribir "(.*?)" . Hacer .* perezoso ( ? ) evita que la coincidencia engulla caracteres, incluidas las comillas dobles, hasta que se alcance la última comilla doble de la cadena. Si tuviéramos que usar ".*" (una coincidencia codiciosa ) obtendríamos la coincidencia única, '"string" "another [thing] string'" .