2008-09-15 9 views
6

Je dois prendre en charge des expressions exactes (entre guillemets) dans une liste de termes séparés par des espaces. La séparation de la chaîne respective par le caractère espace n'est donc plus suffisante.parsings chaînes: extraction de mots et de phrases [JavaScript]

Exemple:

input : 'foo bar "lorem ipsum" baz' 
output: ['foo', 'bar', 'lorem ipsum', 'baz'] 

Je me demande si cela pourrait être réalisé avec un seul RegEx, plutôt que d'effectuer des opérations complexes ou analyse syntaxique dédoublé et rejoignons.

Toute aide serait grandement appréciée!

Répondre

12
var str = 'foo bar "lorem ipsum" baz'; 
var results = str.match(/("[^"]+"|[^"\s]+)/g); 

... retourne le tableau que vous recherchez.
Notez cependant:

  • citations bondissantes sont inclus, peut donc être éliminé avec replace(/^"([^"]+)"$/,"$1") sur les résultats.
  • Les espaces entre les guillemets resteront intacts. Donc, s'il y a trois espaces entre lorem et ipsum, ils seront dans le résultat. Vous pouvez résoudre ce problème en exécutant replace(/\s+/," ") sur les résultats.
  • S'il n'y a pas de fermeture " après ipsum (soit une phrase mal citée) vous vous retrouverez avec: ['foo', 'bar', 'lorem', 'ipsum', 'baz']
+1

Le seul problème est que toutes les citations sont dépouillées - à savoir des guillemets eux-mêmes ne sont pas consultables. –

0
'foo bar "lorem ipsum" baz'.match(/"[^"]*"|\w+/g); 

les citations de délimitation s'inclus si

0

Une expression régulière simple va faire, mais laisser les guillemets. par exemple.

'foo bar "lorem ipsum" baz'.match(/("[^"]*")|([^\s"]+)/g) 
output: ['foo', 'bar', '"lorem ipsum"', 'baz'] 

modifier: battu à par Shyamsundar, désolé pour la double réponse

1

que diriez-vous,

output = /(".+?"|\w+)/g.exec(input) 

puis faire une passe sur la sortie de perdre les guillemets.

alternativement,

output = /"(.+?)"|(\w+)/g.exec(input) 

puis effectuez une sortie passe n pour perdre les captures vides.

2

Essayez ceci:

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"] 

Remarque Il n'y a pas de double supplémentaire entre guillemets lorem ipsum

Bien qu'il suppose que l'entrée a les doubles guillemets au bon endroit:

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"] 

Et ne traitera pas échappé des guillemets doubles (est-ce un problème?):

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"] 
0

Si vous vous demandez juste comment construire la regex vous, vous pourriez vouloir vérifier Expresso (Expresso link) .C'est un excellent outil pour apprendre à construire des expressions régulières afin que vous sachiez ce que la syntaxe signifie. Lorsque vous avez construit votre propre expression, vous pouvez y ajouter un .match.

1

Merci beaucoup pour les réponses rapides!

Voici un résumé des options, pour la postérité:

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); 

Pour mémoire, voici l'abomination que j'étais venu avec:

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); 
0

Celui qui est facile à comprendre et à une solution générale . Fonctionne pour tous les délimiteurs et les caractères de 'jointure'. prend également en charge les mots « joints » qui sont plus de deux mots de longueur .... listes comme dire

"hello my name is 'jon delaware smith fred' I have a 'long name'" ....

Un peu comme la réponse par AC mais un peu plus propre ...

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; 
    } 
0

Cela pourrait être une réponse très tard, mais je suis intéressé à répondre

([\w]+|\"[\w\s]+\") 

http://regex101.com/r/dZ1vT6/72

exemple javascript pur

'The rain in "SPAIN stays" mainly in the plain'.match(/[\w]+|\"[\w\s]+\"/g) 

Sorties:

["The", "rain", "in", ""SPAIN stays"", "mainly", "in", "the", "plain"] 
0

solution ES6 soutien:

  • de Split par l'espace, sauf pour les citations à l'intérieur
  • supprimer les guillemets mais pas pour backslash citations
  • Échappé q uote devenir citation

code:

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 

Sortie:

[ 'foo', 'bar', 'lorem ipsum', 'baz' ] 
Questions connexes