analisi delle stringhe:estrazione di parole e frasi [JavaScript]
-
09-06-2019 - |
Domanda
Devo supportare le frasi esatte (racchiuse tra virgolette) in un elenco di termini altrimenti separati da spazi.Pertanto la suddivisione della rispettiva stringa in base al carattere spazio non è più sufficiente.
Esempio:
input : 'foo bar "lorem ipsum" baz'
output: ['foo', 'bar', 'lorem ipsum', 'baz']
Mi chiedo se ciò possa essere ottenuto con una singola RegEx, piuttosto che eseguire complesse operazioni di analisi o divisione e ricongiungimento.
Qualsiasi aiuto sarebbe molto apprezzato!
Soluzione
var str = 'foo bar "lorem ipsum" baz';
var results = str.match(/("[^"]+"|[^"\s]+)/g);
...restituisce l'array che stai cercando.
Nota, tuttavia:
- Le virgolette di delimitazione sono incluse, quindi possono essere rimosse con
replace(/^"([^"]+)"$/,"$1")
sui risultati. - Gli spazi tra le virgolette rimarranno intatti.Quindi, se ci sono tre spazi in mezzo
lorem
Eipsum
, saranno nel risultato.Puoi risolvere questo problema correndoreplace(/\s+/," ")
sui risultati. - Se non c'è chiusura
"
Dopoipsum
(cioè.una frase citata in modo errato) ti ritroverai con:['foo', 'bar', 'lorem', 'ipsum', 'baz']
Altri suggerimenti
Prova questo:
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"]
Nota che non ci sono virgolette doppie aggiuntive attorno a lorem ipsum
Anche se presuppone che l'input contenga le virgolette doppie al posto giusto:
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"]
E non gestirà le virgolette doppie con escape (è 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"]
che ne dite di,
output = /(".+?"|\w+)/g.exec(input)
quindi esegui un passaggio sull'output per perdere le virgolette.
in alternativa,
output = /"(.+?)"|(\w+)/g.exec(input)
quindi esegui un passaggio n output per perdere le acquisizioni vuote.
Grazie mille per le risposte rapide!
Ecco un riepilogo delle opzioni, per i posteri:
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);
Per la cronaca, ecco l'abominio che avevo inventato:
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);
le virgolette di delimitazione vengono però incluse
Una semplice espressione regolare basterà lasciare le virgolette.per esempio.
'foo bar "lorem ipsum" baz'.match(/("[^"]*")|([^\s"]+)/g)
output: ['foo', 'bar', '"lorem ipsum"', 'baz']
modificare:battuto da shyamsundar, scusa per la doppia risposta
Uno che sia facile da capire e una soluzione generale.Funziona con tutti i delimitatori e i caratteri di "unione".Supporta anche parole "unite" lunghe più di due parole....cioè elenchi come
"hello my name is 'jon delaware smith fred' I have a 'long name'"
....
Un po' come la risposta di AC ma un po' più ordinata...
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;
}
Se ti stai chiedendo come costruire da solo la regex, potresti dare un'occhiata a Expresso (Collegamento espresso).È un ottimo strumento per imparare a creare espressioni regolari in modo da sapere cosa significa la sintassi.
Quando hai costruito la tua espressione, puoi eseguire a .match
su di essa.
Questa potrebbe essere una risposta molto tardiva, ma sono interessato a rispondere
([\w]+|\"[\w\s]+\")
http://regex101.com/r/dZ1vT6/72
Esempio puro Javascript
'The rain in "SPAIN stays" mainly in the plain'.match(/[\w]+|\"[\w\s]+\"/g)
Uscite:
["The", "rain", "in", ""SPAIN stays"", "mainly", "in", "the", "plain"]
Soluzione ES6 che supporta:
- Diviso per spazio tranne che per le virgolette interne
- Rimozione delle virgolette ma non delle virgolette con escape barra rovesciata
- La citazione sfuggita diventa citazione
Codice:
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
Produzione:
[ 'foo', 'bar', 'lorem ipsum', 'baz' ]