2010-10-27 17 views
19

tengo actualmente esta expresión regular para dividir cadenas por todos los espacios en blanco, a menos que sea en un segmento citado:dividir una cadena por espacios en blanco, manteniendo los segmentos citados, permitiendo que escapó cotizaciones

keywords = 'pop rock "hard rock"'; 
keywords = keywords.match(/\w+|"[^"]+"/g); 
console.log(keywords); // [pop, rock, "hard rock"] 

Sin embargo, también quiero que se ser posible tener cotizaciones en palabras clave, así:

keywords = 'pop rock "hard rock" "\"dream\" pop"'; 

esto debería devolver

[pop, rock, "hard rock", "\"dream\" pop"] 

¿Cuál es la forma más fácil de lograr esto?

Respuesta

21

Puede cambiar su expresión regular para:

keywords = keywords.match(/\w+|"(?:\\"|[^"])+"/g); 

En lugar de [^"]+ tienes (?:\\"|[^"])+ que debe explicarse por sí mismo - permitir \" u otro carácter, pero no una cotización sin escapar.

Una nota importante es que si quieres la cadena para incluir una barra literal, que debe ser:

keywords = 'pop rock "hard rock" "\\"dream\\" pop"'; //note the escaped slashes. 

Además, hay una ligera discrepancia entre \w+ y [^"]+ - por ejemplo, que coincidirá con la palabra "ab*d", pero no ab*d (sin las comillas). Considere el uso de [^"\s]+ en su lugar, que coincidirá con espacios no.

+1

le sugiero que utilice '' \\ en lugar de '\\" 'porque las barras invertidas se pueden escapar también, y usted no me gustaría. señorita '" foo \\\\ "'. –

+0

@Tim - idea interesante al principio, pero no estoy seguro de que sea necesario - ¿''^^ no manejaría estos casos? ¿Me estoy perdiendo algo? – Kobi

+1

Considere esto: En la cadena '" \\ "" foo "' (solo dos backlashes para mayor claridad), el primer '" 'se correspondería con el literal' "' al comienzo de la expresión regular. Entonces el '[^"] 'coincidiría con el primero \. Entonces, el '\" 'restante sería emparejado por' \\ "' (porque viene primero en la alternancia). Entonces '[^"] 'coincidiría con el espacio y' '' (al final de la expresión regular) coincidiría con la cita de apertura de '" foo "', interrumpiendo el análisis sintáctico. –

0

Si la respuesta de Kobi funciona bien para la cadena ejemplo, no cuando hay más de un caracteres de escape sucesivos (barras invertidas) entre comillas como Tim Pietzcker notaron en los comentarios. Para hacer frente a estos casos, el patrón puede escribirse así (por el método match):

(?=\S)[^"\s]*(?:"[^\\"]*(?:\\[\s\S][^\\"]*)*"[^"\s]*)* 

demo

Dónde (?=\S) asegura que hay al menos un carácter no-espacio en blanco en la posición actual desde el siguiente, que describe todas las subcadenas permitidas (incluidos espacios en blanco entre comillas) es totalmente opcional.

Detalles:

(?=\S) # followed by a non-whitespace 
[^"\s]* #"# zero or more characters that aren't a quote or a whitespace 
(?: # when a quoted substring occurs: 
    "  #"# opening quote 
    [^\\"]* #"# zero or more characters that aren't a quote or a backslash 
    (?: # when a backslash is encountered: 
     \\ [\s\S] # an escaped character (including a quote or a backslash) 
     [^\\"]* #"# 
    )* 
    "   #"# closing quote 
    [^"\s]* #"# 
)* 
+0

¿Podría agregar la intención de cada parte en inglés sencillo? – Timo

+0

@Timo: agregué los detalles del patrón. –

0

me gustaría señalar que tenía la misma expresión regular como usted,

/\w+|"[^"]+"/g 

pero que aún no ha trabajado en la citada cadena vacía como:

"" "hello" "" "hi" 

así que tuve que cambiar el + cuantificador por *.

str.match(/\w+|"[^"]*"/g); 

Lo que está bien: esto me dio.

(ex: https://regex101.com/r/wm5puK/1)

1

ES6 solución de soporte:

  • dividida por el espacio a excepción de las citas dentro
  • Eliminación de cotizaciones pero no para la barra invertida cotizaciones escapado
  • escapado cita cita convertida
  • Puede poner citas en cualquier lugar

Código:

keywords.match(/\\?.|^$/g).reduce((p, c) => { 
     if(c === '"'){ 
      p.quote ^= 1; 
     }else if(!p.quote && c === ' '){ 
      p.a.push(''); 
     }else{ 
      p.a[p.a.length-1] += c.replace(/\\(.)/,"$1"); 
     } 
     return p; 
    }, {a: ['']}).a 

Salida:

[ 'pop', 'rock', 'hard rock', '"dream" pop' ] 
Cuestiones relacionadas