5

Ultimately I'm trying to turn this:

var msg = '-m "this is a message" --echo "another message" test arg';

into this:

[
    '-m',
    'this is a message',
    '--echo',
    'another message',
    'test',
    'arg'
]

I'm not quite sure how to parse the string to get the desired results. This is what I have so far:

var msg = '-m "this is a message" --echo "another message" test arg';

// remove spaces from all quoted strings.
msg = msg.replace(/"[^"]*"/g, function (match) {
    return match.replace(/ /g, '{space}');
});

// Now turn it into an array.
var msgArray = msg.split(' ').forEach(function (item) {
    item = item.replace('{space}', ' ');
});

I think that will work, but man does that seem like a fickle and backwards way of accomplishing what I want. I'm sure you guys have a much better way than creating a placeholder string before the split.

CatDadCode
  • 58,507
  • 61
  • 212
  • 318
  • Having nested quotes with regex might not be the best option, recursion is not very friendly with regex. – elclanrs Mar 14 '13 at 21:27
  • 1
    You could split by quotes, then split every alternate item. – Asad Saeeduddin Mar 14 '13 at 21:36
  • I'm not allowing nested quotes, that's why I exclude matches with quotes in the middle `[^"]*`, otherwise that expression would match the entire string between the first and last quote. – CatDadCode Mar 14 '13 at 21:38
  • 1
    I m surprised to see that the question this one is marked as duplicate of does not have an answer. So, is it a duplicate ? – GameAlchemist Mar 20 '13 at 17:35
  • 1
    Yeah I wouldn't consider my question a duplicate of the one linked, but oh well. – CatDadCode Mar 21 '13 at 03:52
  • This is definitely not a duplicate of the linked question, as this is javascript and the other is java. However, it is a duplicate of http://stackoverflow.com/questions/4031900/split-a-string-by-whitespace-keeping-quoted-segments-allowing-escaped-quotes and http://stackoverflow.com/questions/16261635/javascript-split-string-by-space-but-ignore-space-in-quotes-notice-not-to-spli – Kelly Jun 24 '15 at 19:57
  • It's also over two years old, lol. And your second link was posted *after* this question, making it the duplicate in that case. – CatDadCode Jun 24 '15 at 20:06

3 Answers3

5

with exec(), you can allready take the strings without the quotes :

var test="once \"upon a time\"  there was   a  \"monster\" blue";

function parseString(str) {
    var re = /(?:")([^"]+)(?:")|([^\s"]+)(?=\s+|$)/g;
    var res=[], arr=null;
    while (arr = re.exec(str)) { res.push(arr[1] ? arr[1] : arr[0]); }
    return res;
}

var parseRes= parseString(test);
// parseRes now contains what you seek
CatDadCode
  • 58,507
  • 61
  • 212
  • 318
GameAlchemist
  • 18,995
  • 7
  • 36
  • 59
  • Thank you for this. I was wondering if there was a better way to get the quoted values without the quotes, but didn't want to be pedantic and drag this question out. This is exactly what I wanted. – CatDadCode Mar 15 '13 at 02:43
4

Instead of a split, you could match:

var msg = '-m "this is a message" --echo "another message" test arg';
var array = msg.match(/"[^"]*"|[^\s"]+/g);
console.log(array);

produces:

[ '-m',
  '"this is a message"',
  '--echo',
  '"another message"',
  'test',
  'arg' ]
Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
1

It is hard to guess what you would prefer as a solution, but one approach would be to split by quotes (this assumes no nested quotes), then to split every alternate item by spaces:

result = [];
msg.split("\"").map(function(v, i ,a){
    if(i % 2 == 0) {
        result = result.concat(v.split(" ").filter(function(v){
            return !v;
        }));
    } else {
        result.push(v);
    }
});

Here is a demonstration: http://jsfiddle.net/eL7cc/

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139