cadenas de análisis:extraer palabras y frases [JavaScript]
-
09-06-2019 - |
Pregunta
Necesito admitir frases exactas (entre comillas) en una lista de términos separados por espacios.Por lo tanto, ya no es suficiente dividir la cadena respectiva por el carácter de espacio.
Ejemplo:
input : 'foo bar "lorem ipsum" baz'
output: ['foo', 'bar', 'lorem ipsum', 'baz']
Me pregunto si esto podría lograrse con una única expresión regular, en lugar de realizar operaciones complejas de análisis o división y unión.
¡Cualquier ayuda sería muy apreciada!
Solución
var str = 'foo bar "lorem ipsum" baz';
var results = str.match(/("[^"]+"|[^"\s]+)/g);
...devuelve la matriz que estás buscando.
Tenga en cuenta, sin embargo:
- Se incluyen comillas delimitadoras, por lo que se pueden eliminar con
replace(/^"([^"]+)"$/,"$1")
sobre los resultados. - Los espacios entre las comillas permanecerán intactos.Entonces, si hay tres espacios entre
lorem
yipsum
, estarán en el resultado.Puedes solucionar este problema ejecutandoreplace(/\s+/," ")
sobre los resultados. - Si no hay cierre
"
despuésipsum
(es decir.una frase citada incorrectamente) terminarás con:['foo', 'bar', 'lorem', 'ipsum', 'baz']
Otros consejos
Prueba esto:
var input = 'foo bar "lorem ipsum" baz';
var R = /(\w|\s)*\w(?=")|\w+/g;
var output = input.match(R);
output is ["foo", "bar", "lorem ipsum", "baz"]
Tenga en cuenta que no hay comillas dobles adicionales alrededor de lorem ipsum
Aunque se supone que la entrada tiene comillas dobles en el lugar correcto:
var input2 = 'foo bar lorem ipsum" baz'; var output2 = input2.match(R);
var input3 = 'foo bar "lorem ipsum baz'; var output3 = input3.match(R);
output2 is ["foo bar lorem ipsum", "baz"]
output3 is ["foo", "bar", "lorem", "ipsum", "baz"]
Y no manejará comillas dobles escapadas (¿es eso un problema?):
var input4 = 'foo b\"ar bar\" \"bar "lorem ipsum" baz';
var output4 = input4.match(R);
output4 is ["foo b", "ar bar", "bar", "lorem ipsum", "baz"]
qué tal si,
output = /(".+?"|\w+)/g.exec(input)
luego pase la salida para perder las comillas.
alternativamente,
output = /"(.+?)"|(\w+)/g.exec(input)
luego haga un pase n de salida para perder las capturas vacías.
¡Muchas gracias por las rápidas respuestas!
He aquí un resumen de las opciones, para la posteridad:
var input = 'foo bar "lorem ipsum" baz';
output = input.match(/("[^"]+"|[^"\s]+)/g);
output = input.match(/"[^"]*"|\w+/g);
output = input.match(/("[^"]*")|([^\s"]+)/g)
output = /(".+?"|\w+)/g.exec(input);
output = /"(.+?)"|(\w+)/g.exec(input);
Para que conste, aquí está la abominación que se me ocurrió:
var input = 'foo bar "lorem ipsum" "dolor sit amet" baz';
var terms = input.split(" ");
var items = [];
var buffer = [];
for(var i = 0; i < terms.length; i++) {
if(terms[i].indexOf('"') != -1) { // outer phrase fragment -- N.B.: assumes quote is either first or last character
if(buffer.length === 0) { // beginning of phrase
//console.log("start:", terms[i]);
buffer.push(terms[i].substr(1));
} else { // end of phrase
//console.log("end:", terms[i]);
buffer.push(terms[i].substr(0, terms[i].length - 1));
items.push(buffer.join(" "));
buffer = [];
}
} else if(buffer.length != 0) { // inner phrase fragment
//console.log("cont'd:", terms[i]);
buffer.push(terms[i]);
} else { // individual term
//console.log("standalone:", terms[i]);
items.push(terms[i]);
}
//console.log(items, "\n", buffer);
}
items = items.concat(buffer);
//console.log(items);
'foo bar "lorem ipsum" baz'.match(/"[^"]*"|\w+/g);
aunque las comillas delimitadoras se incluyen
Una simple expresión regular servirá pero deja las comillas.p.ej.
'foo bar "lorem ipsum" baz'.match(/("[^"]*")|([^\s"]+)/g)
output: ['foo', 'bar', '"lorem ipsum"', 'baz']
editar:derrotado por shyamsundar, perdón por la doble respuesta
Uno que sea fácil de entender y una solución general.Funciona para todos los delimitadores y caracteres de "unión".También admite palabras 'unidas' que tengan más de dos palabras de longitud....es decir, listas como
"hello my name is 'jon delaware smith fred' I have a 'long name'"
....
Un poco como la respuesta de AC pero un poco más ordenada...
function split(input, delimiter, joiner){
var output = [];
var joint = [];
input.split(delimiter).forEach(function(element){
if (joint.length > 0 && element.indexOf(joiner) === element.length - 1)
{
output.push(joint.join(delimiter) + delimiter + element);
joint = [];
}
if (joint.length > 0 || element.indexOf(joiner) === 0)
{
joint.push(element);
}
if (joint.length === 0 && element.indexOf(joiner) !== element.length - 1)
{
output.push(element);
joint = [];
}
});
return output;
}
Si simplemente se pregunta cómo crear la expresión regular usted mismo, es posible que desee consultar Expresso (enlace expreso).Es una gran herramienta para aprender a crear expresiones regulares para saber lo que significa la sintaxis.
Cuando hayas creado tu propia expresión, podrás realizar una .match
en eso.
Esta puede ser una respuesta muy tardía, pero me interesa responder.
([\w]+|\"[\w\s]+\")
http://regex101.com/r/dZ1vT6/72
Ejemplo de javascript puro
'The rain in "SPAIN stays" mainly in the plain'.match(/[\w]+|\"[\w\s]+\"/g)
Salidas:
["The", "rain", "in", ""SPAIN stays"", "mainly", "in", "the", "plain"]
Solución ES6 que admite:
- Dividido por espacio excepto por comillas internas
- Eliminando comillas pero no para las comillas escapadas con barra invertida
- La cita escapada se convierte en cita
Código:
input.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
Producción:
[ 'foo', 'bar', 'lorem ipsum', 'baz' ]