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!

¿Fue útil?

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 y ipsum, estarán en el resultado.Puedes solucionar este problema ejecutando replace(/\s+/," ") sobre los resultados.
  • Si no hay cierre " después ipsum (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' ]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top