मैं जावास्क्रिप्ट में रेगेक्स शाब्दिकों को कैसे संक्षिप्त कर सकता हूं?


145

क्या ऐसा कुछ करना संभव है?

var pattern = /some regex segment/ + /* comment here */
    /another segment/;

या मुझे नए RegExp()सिंटैक्स का उपयोग करना है और एक स्ट्रिंग को संक्षिप्त करना है? मैं शाब्दिक का उपयोग करना पसंद करूंगा क्योंकि कोड अधिक स्व-स्पष्ट और संक्षिप्त दोनों है।


2
अगर आप let regexSegment1 = String.raw`\s*hello\s*`
String.raw

जवाबों:


190

यहाँ नियमित अभिव्यक्ति शाब्दिक वाक्य रचना का उपयोग किए बिना एक नियमित अभिव्यक्ति बनाने का तरीका बताया गया है। इससे पहले कि यह एक नियमित अभिव्यक्ति वस्तु बन जाए, इससे आप मनमाने ढंग से स्ट्रिंग हेरफेर कर सकते हैं:

var segment_part = "some bit of the regexp";
var pattern = new RegExp("some regex segment" + /*comment here */
              segment_part + /* that was defined just now */
              "another segment");

यदि आपके पास दो नियमित अभिव्यक्ति शाब्दिक हैं, तो आप वास्तव में इस तकनीक का उपयोग करके उन्हें संक्षिप्त कर सकते हैं:

var regex1 = /foo/g;
var regex2 = /bar/y;
var flags = (regex1.flags + regex2.flags).split("").sort().join("").replace(/(.)(?=.*\1)/g, "");
var regex3 = new RegExp(expression_one.source + expression_two.source, flags);
// regex3 is now /foobar/gy

यह सिर्फ एक और दो के शाब्दिक नियमित अभिव्यक्ति के बजाय शाब्दिक तार होने की तुलना में अधिक चिंताजनक है।


2
ध्यान रखें कि इस दृष्टिकोण का उपयोग करते समय प्रत्येक खंड एक मान्य नियमित अभिव्यक्ति होना चाहिए। एक अभिव्यक्ति का निर्माण करना ऐसा new RegExp(/(/.source + /.*/.source + /)?/.source);प्रतीत नहीं होता है कि काम नहीं कर रहा है।
सैम

बैक-मैचिंग समूहों के मामले में यह समाधान काम नहीं करता है। उस मामले में काम करने वाले समाधान के लिए मेरा जवाब देखें।
मिकैल मेयर

यदि आपको एक चार से बचने की आवश्यकता है, तो डबल बैकस्लैश का उपयोग करें: नया रेगेक्सप ('\\ $' + "फ्लम")
जेफ लोरी

यदि आप "<regexp> .flags" के साथ हैं तो आप झंडे का उपयोग कर सकते हैं, इसलिए सैद्धांतिक रूप से आप उन्हें भी जोड़ सकते हैं।
बरुनामक

आप कहाँ expression_oneसे प्राप्त कर रहे हैं क्या आपका मतलब है regex1?
TallOrderDev

30

नियमित रूप से समसामयिक अभिव्यक्ति वस्तुओं को नियमित करने से कुछ प्रतिकूल प्रभाव पड़ सकते हैं। इसके बजाय RegExp.source का उपयोग करें :

var r1 = /abc/g;
var r2 = /def/;
var r3 = new RegExp(r1.source + r2.source, 
                   (r1.global ? 'g' : '') 
                   + (r1.ignoreCase ? 'i' : '') + 
                   (r1.multiline ? 'm' : ''));
console.log(r3);
var m = 'test that abcdef and abcdef has a match?'.match(r3);
console.log(m);
// m should contain 2 matches

यह आपको मानक RegExp झंडे का उपयोग करके पिछले RegExp से नियमित अभिव्यक्ति झंडे को बनाए रखने की क्षमता भी देगा।

jsFiddle


इसका उपयोग करके सुधार किया जा सकता हैRegExp.prototype.flags
दिमित्री परज़ित्स्की

19

मैं "eval" विकल्प से बिल्कुल सहमत नहीं हूँ।

var xxx = /abcd/;
var yyy = /efgh/;
var zzz = new RegExp(eval(xxx)+eval(yyy));

"// abcd // efgh //" देगा जो अभीष्ट परिणाम नहीं है।

जैसे स्रोत का उपयोग करना

var zzz = new RegExp(xxx.source+yyy.source);

"/ abcdefgh /" देगा और यह सही है।

तार्किक रूप से EVALUATE की कोई आवश्यकता नहीं है, आप अपना विस्तार जानते हैं। आपको बस इसके स्रोत की आवश्यकता है या यह कैसे लिखा जाता है कि इसके मूल्य की आवश्यकता नहीं है। झंडे के लिए, आपको बस RegExp के वैकल्पिक तर्क का उपयोग करने की आवश्यकता है।

मेरी स्थिति में, मैं ^ और $ के अंक में कई अभिव्यक्ति में इस्तेमाल किया जा रहा हूं, जिसे मैं एक साथ समेटने की कोशिश कर रहा हूं! उन भावों को व्याकरण फिल्टर कार्यक्रम के पार इस्तेमाल किया जाता है। अब मैं PREPOSITIONS के मामले को संभालने के लिए उनमें से कुछ का उपयोग नहीं करना चाहता। मुझे शुरुआत और समाप्ति ^ (और / या) $ :) चीयर्स, एलेक्स को हटाने के लिए स्रोतों को "स्लाइस" करना पड़ सकता है।


मुझे स्रोत-संपत्ति का उपयोग पसंद है। यदि आप - मेरी तरह - jslint का उपयोग करें तो यह आपको कुछ इस तरह से नाग कर देगा:var regex = "\.\..*"
Nils-o-mat

7

समस्या यदि regexp में बैक-मिलान समूह जैसे \ 1 हैं।

var r = /(a|b)\1/  // Matches aa, bb but nothing else.
var p = /(c|d)\1/   // Matches cc, dd but nothing else.

फिर सिर्फ सूत्रों के विपरीत काम नहीं करेगा। वास्तव में, दो का संयोजन है:

var rp = /(a|b)\1(c|d)\1/
rp.test("aadd") // Returns false

समाधान: पहले हम पहले रेगेक्स में मिलान समूहों की संख्या की गणना करते हैं, फिर दूसरे में प्रत्येक बैक-मैचिंग टोकन के लिए, हम मिलान समूहों की संख्या से इसे बढ़ाते हैं।

function concatenate(r1, r2) {
  var count = function(r, str) {
    return str.match(r).length;
  }
  var numberGroups = /([^\\]|^)(?=\((?!\?:))/g; // Home-made regexp to count groups.
  var offset = count(numberGroups, r1.source);    
  var escapedMatch = /[\\](?:(\d+)|.)/g;        // Home-made regexp for escaped literals, greedy on numbers.
  var r2newSource = r2.source.replace(escapedMatch, function(match, number) { return number?"\\"+(number-0+offset):match; });
  return new RegExp(r1.source+r2newSource,
      (r1.global ? 'g' : '') 
      + (r1.ignoreCase ? 'i' : '')
      + (r1.multiline ? 'm' : ''));
}

परीक्षा:

var rp = concatenate(r, p) // returns  /(a|b)\1(c|d)\2/
rp.test("aadd") // Returns true

2
हां (हालांकि मैं इसे यहां संशोधित नहीं करूंगा)। यह फ़ंक्शन साहचर्य है, इसलिए आप निम्नलिखित कोड का उपयोग कर सकते हैं:function concatenateList() { var res = arguments[0]; for(var i = 1; i < arguments.length; i++) { res = concatenate(res, arguments[i]); } return res; }
Mikaël मेयर

3

यथासंभव शाब्दिक वाक्य-विन्यास का उपयोग करना बेहतर होगा। यह छोटा है, अधिक सुपाठ्य है, और आपको भागने के उद्धरण या डबल-एस्केप बैकलैश की आवश्यकता नहीं है। "जावास्क्रिप्ट पैटर्न" से, स्टॉयन स्टेफानोव 2010।

लेकिन न्यू का उपयोग करना एकमात्र तरीका हो सकता है।

मैं eval से बचना होगा। यह सुरक्षित नहीं है।


1
मुझे लगता है कि जटिल नियमित अभिव्यक्तियाँ टूटने पर अधिक उपयुक्त होती हैं और प्रश्न की तरह टिप्पणी की जाती हैं।
सैम

3

प्राप्त कराना:

  • आप जानते हैं कि आप अपने regexp में क्या करते हैं;
  • आपके पास एक पैटर्न बनाने के लिए कई रेगेक्स टुकड़े हैं और वे एक ही ध्वज का उपयोग करेंगे;
  • आप अपने छोटे पैटर्न विखंडू को एक सरणी में अलग करने के लिए अधिक पठनीय पाते हैं;
  • आप अगले भाग के लिए या बाद में स्वयं के लिए प्रत्येक भाग पर टिप्पणी करने में सक्षम होना चाहते हैं;
  • आप नेत्रहीन अपने रेगेक्स को सरल करना पसंद करते हैं, जैसे /this/gकि new RegExp('this', 'g');
  • शुरू से एक टुकड़े में रखने के बजाय एक अतिरिक्त चरण में रेगेक्स को इकट्ठा करना आपके लिए ठीक है;

तो आप इस तरह से लिखना पसंद कर सकते हैं:

var regexParts =
    [
        /\b(\d+|null)\b/,// Some comments.
        /\b(true|false)\b/,
        /\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|length|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/,
        /(\$|jQuery)/,
        /many more patterns/
    ],
    regexString  = regexParts.map(function(x){return x.source}).join('|'),
    regexPattern = new RegExp(regexString, 'g');

फिर आप कुछ ऐसा कर सकते हैं:

string.replace(regexPattern, function()
{
    var m = arguments,
        Class = '';

    switch(true)
    {
        // Numbers and 'null'.
        case (Boolean)(m[1]):
            m = m[1];
            Class = 'number';
            break;

        // True or False.
        case (Boolean)(m[2]):
            m = m[2];
            Class = 'bool';
            break;

        // True or False.
        case (Boolean)(m[3]):
            m = m[3];
            Class = 'keyword';
            break;

        // $ or 'jQuery'.
        case (Boolean)(m[4]):
            m = m[4];
            Class = 'dollar';
            break;

        // More cases...
    }

    return '<span class="' + Class + '">' + m + '</span>';
})

मेरे विशेष मामले में (एक कोड-मिरर-जैसे संपादक), एक बड़े रेगेक्स का प्रदर्शन करना बहुत आसान है, बजाय एक रिप्लेसमेंट की तरह हर बार जब मैं अभिव्यक्ति को लपेटने के लिए एक html टैग के साथ प्रतिस्थापित करता हूं, तो अगला पैटर्न होगा html टैग को प्रभावित किए बिना लक्ष्य करना कठिन हो सकता है (और अच्छे दिखावे के बिना जो दुर्भाग्य से जावास्क्रिप्ट में समर्थित नहीं है):

.replace(/(\b\d+|null\b)/g, '<span class="number">$1</span>')
.replace(/(\btrue|false\b)/g, '<span class="bool">$1</span>')
.replace(/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/g, '<span class="keyword">$1</span>')
.replace(/\$/g, '<span class="dollar">$</span>')
.replace(/([\[\](){}.:;,+\-?=])/g, '<span class="ponctuation">$1</span>')

2

आप कुछ ऐसा कर सकते हैं:

function concatRegex(...segments) {
  return new RegExp(segments.join(''));
}

खंड अलग-अलग तर्कों के रूप में पारित किए गए तार (रेगेक्स शाब्दिक के बजाय) होंगे।


1

नहीं, शाब्दिक तरीका समर्थित नहीं है। आपको RegExp का उपयोग करना होगा।


1

2 पैरा के साथ कंस्ट्रक्टर का उपयोग करें और '' / 'के साथ समस्या से बचें।

var re_final = new RegExp("\\" + ".", "g");    // constructor can have 2 params!
console.log("...finally".replace(re_final, "!") + "\n" + re_final + 
    " works as expected...");                  // !!!finally works as expected

                         // meanwhile

re_final = new RegExp("\\" + "." + "g");              // appends final '/'
console.log("... finally".replace(re_final, "!"));    // ...finally
console.log(re_final, "does not work!");              // does not work

1

आप रेगेक्स स्रोत को शाब्दिक और RegExp वर्ग दोनों से प्राप्त कर सकते हैं:

var xxx = new RegExp(/abcd/);
var zzz = new RegExp(xxx.source + /efgh/.source);

1

मेरे लिए आसान तरीका होगा सूत्रों का कहना है, पूर्व:

a = /\d+/
b = /\w+/
c = new RegExp(a.source + b.source)

सी मूल्य में परिणाम होगा:

/ \ D + \ w + /


-2

मैं उपयोग करना पसंद eval('your expression')करता हूं क्योंकि यह /प्रत्येक छोर पर नहीं जोड़ता है /जो ='new RegExp'करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.