parsings strings: extracting words and phrases [JavaScript]

前端 未结 10 680
没有蜡笔的小新
没有蜡笔的小新 2020-12-01 19:20

I need to support exact phrases (enclosed in quotes) in an otherwise space-separated list of terms. Thus splitting the respective string by the space-character is not suffic

相关标签:
10条回答
  • 2020-12-01 19:38

    ES6 solution supporting:

    • Split by space except for inside quotes
    • Removing quotes but not for backslash escaped quotes
    • Escaped quote become quote

    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
    

    Output:

    [ 'foo', 'bar', 'lorem ipsum', 'baz' ]
    
    0 讨论(0)
  • Try this:

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

    Note there are no extra double quotes around lorem ipsum

    Although it assumes the input has the double quotes in the right place:

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

    And won't handle escaped double quotes (is that a problem?):

    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 讨论(0)
  • 2020-12-01 19:45

    Thanks a lot for the quick responses!

    Here's a summary of the options, for posterity:

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

    For the record, here's the abomination I had come up with:

    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 讨论(0)
  • 2020-12-01 19:51

    One that's easy to understand and a general solution. Works for all delimiters and 'join' characters. Also supports 'joined' words that are more than two words in length.... ie lists like

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

    A bit like the answer by AC but a bit neater...

    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 讨论(0)
  • 2020-12-01 19:52

    how about,

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

    then do a pass on output to lose the quotes.

    alternately,

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

    then do a pass n output to lose the empty captures.

    0 讨论(0)
  • 2020-12-01 19:54

    This might be a very late answer, but I am interested in answering

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

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

    Pure javascript example

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

    Outputs:

    ["The", "rain", "in", ""SPAIN stays"", "mainly", "in", "the", "plain"]
    
    0 讨论(0)
提交回复
热议问题