سلاسل التحليل:استخراج الكلمات والعبارات [جافا سكريبت]

StackOverflow https://stackoverflow.com/questions/64904

  •  09-06-2019
  •  | 
  •  

سؤال

أحتاج إلى دعم العبارات الدقيقة (المضمنة بين علامتي اقتباس) في قائمة مصطلحات مفصولة بمسافات.وبالتالي فإن تقسيم السلسلة المعنية بواسطة حرف المسافة لم يعد كافيًا بعد الآن.

مثال:

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

أتساءل عما إذا كان من الممكن تحقيق ذلك باستخدام RegEx واحد، بدلاً من إجراء عمليات تحليل معقدة أو عمليات تقسيم وإعادة الانضمام.

سيكون موضع تقدير كبير أي مساعدة!

هل كانت مفيدة؟

المحلول

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

...تقوم بإرجاع المصفوفة التي تبحث عنها.
لكن لاحظ:

  • تم تضمين علامات الاقتباس المحيطة، لذا يمكن إزالتها باستخدام replace(/^"([^"]+)"$/,"$1") على النتائج.
  • ستبقى المسافات بين علامتي الاقتباس سليمة.لذلك، إذا كان هناك ثلاث مسافات بينهما lorem و ipsum, ، سيكونون في النتيجة.يمكنك إصلاح هذا عن طريق التشغيل replace(/\s+/," ") على النتائج.
  • إذا لم يكن هناك إغلاق " بعد ipsum (أي.عبارة مقتبسة بشكل غير صحيح) سينتهي بك الأمر بـ: ['foo', 'bar', 'lorem', 'ipsum', 'baz']

نصائح أخرى

جرب هذا:

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

لاحظ أنه لا توجد علامات اقتباس مزدوجة إضافية حول لوريم إيبسوم

على الرغم من أنه يفترض أن الإدخال يحتوي على علامات الاقتباس المزدوجة في المكان الصحيح:

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

ولن يتعامل مع علامات الاقتباس المزدوجة التي تم تجاوزها (هل هذه مشكلة؟):

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

ماذا عن،

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

ثم قم بتمرير الإخراج لتفقد علامات الاقتباس.

بالتناوب،

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

ثم قم بإجراء إخراج n لتفقد اللقطات الفارغة.

شكرا جزيلا على الاستجابات السريعة!

فيما يلي ملخص للخيارات للأجيال القادمة:

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

للعلم، هذا هو الرجس الذي توصلت إليه:

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

يتم تضمين علامات الاقتباس المحيطة بالرغم من ذلك

التعبير العادي البسيط سيفي بالغرض ولكن اترك علامتي الاقتباس.على سبيل المثال

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

يحرر:لقد تعرض للضرب من قبل شيامسوندار، آسف على الإجابة المزدوجة

حل سهل الفهم وحل عام.يعمل مع كافة المحددات وأحرف "الانضمام".يدعم أيضًا الكلمات "المنضمة" التي يزيد طولها عن كلمتين....أي قوائم مثل

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

يشبه إلى حد ما إجابة AC ولكن أكثر إتقانًا قليلاً ...

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

إذا كنت تتساءل فقط عن كيفية إنشاء التعبير العادي بنفسك، فقد ترغب في الاطلاع على Expresso (رابط اكسبريسو).إنها أداة رائعة لتعلم كيفية إنشاء تعبيرات عادية حتى تعرف ما يعنيه بناء الجملة.

عندما تنتهي من بناء التعبير الخاص بك، يمكنك إجراء .match عليه.

قد تكون هذه إجابة متأخرة جدًا، لكني مهتم بالإجابة

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

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

مثال جافا سكريبت النقي

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

النواتج:

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

دعم حل ES6:

  • مقسمة حسب المسافة باستثناء علامات الاقتباس الداخلية
  • إزالة علامات الاقتباس ولكن ليس من أجل علامات الاقتباس المائلة العكسية
  • الاقتباس الهارب يصبح اقتباسًا

شفرة:

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

انتاج:

[ 'foo', 'bar', 'lorem ipsum', 'baz' ]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top