RegExp.exec का उपयोग करके स्ट्रिंग से सभी मैच निकालने के लिए RegEx


175

मैं निम्नलिखित प्रकार के स्ट्रिंग को पार्स करने की कोशिश कर रहा हूं:

[key:"val" key2:"val2"]

जहां मनमाने ढंग से कुंजी होती है: "वैल" जोड़े अंदर। मैं मुख्य नाम और मूल्य को हथियाना चाहता हूं। उन उत्सुक लोगों के लिए मैं कार्य योद्धा के डेटाबेस प्रारूप को पार्स करने की कोशिश कर रहा हूं।

यहाँ मेरा परीक्षण स्ट्रिंग है:

[description:"aoeu" uuid:"123sth"]

जिसका अर्थ यह है कि कोई भी चीज अंतरिक्ष से अलग एक कुंजी या मूल्य में हो सकती है, कॉलोन के आसपास कोई स्थान नहीं है, और मान हमेशा दोहरे उद्धरण चिह्नों में होते हैं।

नोड में, यह मेरा आउटपुट है:

[deuteronomy][gatlin][~]$ node
> var re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
> re.exec('[description:"aoeu" uuid:"123sth"]');
[ '[description:"aoeu" uuid:"123sth"]',
  'uuid',
  '123sth',
  index: 0,
  input: '[description:"aoeu" uuid:"123sth"]' ]

लेकिन description:"aoeu"इस पैटर्न से मेल भी खाता है। मुझे सभी मैच वापस कैसे मिल सकते हैं?


यह हो सकता है कि मेरा regex गलत है और / या मैं केवल जावास्क्रिप्ट में regex सुविधाओं का गलत तरीके से उपयोग कर रहा हूं। यह काम करने लगता है:> var s = "पंद्रह 15 है और आठ 8 है"; > var re = / \ d + / g; > var m = s.match (re); m = ['15', '8']
गैटलिन

6
जावास्क्रिप्ट अब एक .match () फ़ंक्शन है: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... इस तरह उपयोग किया:"some string".match(/regex/g)
Stefnotch

जवाबों:


237

re.exec(s)सभी मैचों को प्राप्त करने के लिए लूप में कॉल करना जारी रखें :

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';
var m;

do {
    m = re.exec(s);
    if (m) {
        console.log(m[1], m[2]);
    }
} while (m);

इसे इस JSFiddle के साथ आज़माएं: https://jsfiddle.net/7yS2V/


8
whileइसके बजाय क्यों नहीं do … while?
गम्बू

15
थोड़ी देर लूप का उपयोग करना एम को इनिशियलाइज़ करने में थोड़ा अजीब लगता है। आपको या तो लिखना है while(m = re.exec(s)), जो एक विरोधी पैटर्न आईएमओ है, या आपको लिखना होगा m = re.exec(s); while (m) { ... m = re.exec(s); }। मैं do ... if ... whileमुहावरे को पसंद करता हूं , लेकिन अन्य तकनीकें भी काम करेंगी।
लॉनसिआ

14
क्रोमियम में ऐसा करने से मेरा टैब क्रैश हो गया।
एजकैशबर्ग

47
@EdgeCaseBerg आपको gध्वज सेट करने की आवश्यकता है , अन्यथा आंतरिक पॉइंटर को आगे नहीं बढ़ाया जाता है। डॉक्स
टिम

12
एक और बिंदु यह है कि यदि रेगेक्स खाली स्ट्रिंग से मेल खा सकता है तो यह एक अनंत लूप होगा
फैबियोकोस्टा

139

str.match(pattern), यदि patternवैश्विक ध्वज है g, तो सभी मैचों को एक सरणी के रूप में लौटाएगा।

उदाहरण के लिए:

const str = 'All of us except @Emran, @Raju and @Noman was there';
console.log(
  str.match(/@\w*/g)
);
// Will log ["@Emran", "@Raju", "@Noman"]


15
खबरदार: मैच वस्तुओं से मेल नहीं खा रहे हैं, लेकिन मिलान तार। उदाहरण के लिए, इसमें समूहों की पहुँच नहीं है "All of us except @Emran:emran26, @Raju:raju13 and @Noman:noman42".match(/@(\w+):(\w+)/g)(जो वापस आ जाएगी ["@Emran:emran26", "@Raju:raju13", "@Noman:noman42"])
madprog

4
@madprog, सही, यह सबसे आसान तरीका है, लेकिन उपयुक्त नहीं है जब समूह मूल्य आवश्यक हैं।
अनीस

1
यह मेरे लिए काम नहीं कर रहा है। मुझे केवल पहला मैच मिला है।
एंथनी रॉबर्ट्स

7
@AnthonyRoberts को आपको "g" ध्वज जोड़ना होगा। /@\w/gयाnew RegExp("@\\w", "g")
अरुणा हेराथ

88

सभी मैचों के माध्यम से लूप करने के लिए, आप replaceफ़ंक्शन का उपयोग कर सकते हैं :

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';

s.replace(re, function(match, g1, g2) { console.log(g1, g2); });

मुझे लगता है कि यह बहुत जटिल है। हालाँकि, एक साधारण काम करने के विभिन्न तरीकों के बारे में जानना अच्छा है (मैं आपके जवाब को वोट देता हूं)।
अरासॉफ्ट

24
यह उल्टा कोड है। आप किसी भी सार्थक अर्थ में "प्रतिस्थापित" नहीं कर रहे हैं। यह केवल एक अलग उद्देश्य के लिए कुछ फ़ंक्शन का शोषण कर रहा है।
ल्यूक मौरर

6
@dewewad अगर इंजीनियर सिर्फ बॉक्स के बाहर बिना सोचे-समझे नियमों का पालन कर रहे थे, तो हम अभी अन्य ग्रहों पर जाने के बारे में भी नहीं सोच रहे होंगे ;-)
क्रिस्टोफ़

1
@dudewad क्षमा करें, मैं यहाँ आलसी भाग को देखने में विफल हूँ। यदि ठीक उसी विधि को "बदलें" के बजाय "प्रक्रिया" कहा जाता था, तो आप इसके साथ ठीक होंगे। मुझे डर है कि आप शब्दावली पर अटक गए हैं।
क्रिस्टोफ

1
@ श्रीस्तोफे मैं निश्चित रूप से शब्दावली पर अटका नहीं हूं। मैं साफ कोड पर अटका हुआ हूं। एक उद्देश्य के लिए एक उद्देश्य के लिए उपयोग की जाने वाली चीजों का उपयोग करना एक कारण के लिए "हैकी" कहलाता है। यह भ्रामक कोड बनाता है जिसे समझना मुश्किल है और अधिक बार प्रदर्शन-वार नहीं होता है। तथ्य यह है कि आप इस सवाल का जवाब एक रेगेक्स के बिना में और खुद को यह एक अमान्य जवाब देता है, क्योंकि ओपी रेगेक्स के साथ यह करने के लिए पूछ रहा है। मुझे यह महत्वपूर्ण लगता है, हालांकि, इस समुदाय को एक उच्च स्तर पर रखने के लिए, यही कारण है कि मैंने जो कहा, उसके अनुसार मैं खड़ा हूं।
दुबेवाद

56

यह एक उपाय है

var s = '[description:"aoeu" uuid:"123sth"]';

var re = /\s*([^[:]+):\"([^"]+)"/g;
var m;
while (m = re.exec(s)) {
  console.log(m[1], m[2]);
}

यह कानून के जवाब पर आधारित है, लेकिन कम है।

ध्यान दें कि `g 'ध्वज को आंतरिक सूचक को चालानों में आगे ले जाने के लिए सेट किया जाना चाहिए।


17
str.match(/regex/g)

एक सरणी के रूप में सभी मैचों को देता है।

यदि, किसी रहस्यमय कारण से, आपको अतिरिक्त जानकारी की आवश्यकता होती execहै, तो पिछले उत्तरों के विकल्प के रूप में, आप इसे एक लूप के बजाय एक पुनरावर्ती कार्य के साथ कर सकते हैं जो निम्नानुसार है (जो कूलर भी दिखता है)।

function findMatches(regex, str, matches = []) {
   const res = regex.exec(str)
   res && matches.push(res) && findMatches(regex, str, matches)
   return matches
}

// Usage
const matches = findMatches(/regex/g, str)

जैसा कि पहले टिप्पणियों में कहा गया है, gप्रत्येक निष्पादन में पॉइंटर को आगे बढ़ाने के लिए रेगेक्स परिभाषा के अंत में होना महत्वपूर्ण है ।


1
हाँ। पुनरावर्ती सुरुचिपूर्ण और कूलर लग रहा है। Iterative लूप सीधे आगे हैं, बनाए रखने और डिबग करने में आसान हैं।
एंडी एन

11

हम अंत में एक अंतर्निहित matchAllफ़ंक्शन देखना शुरू कर रहे हैं , विवरण और संगतता तालिका के लिए यहां देखें । यह मई 2020 तक दिखता है, क्रोम, एज, फ़ायरफ़ॉक्स, और Node.js (12+) समर्थित हैं लेकिन IE, सफारी और ओपेरा नहीं। ऐसा लगता है कि दिसंबर 2018 में इसका मसौदा तैयार किया गया था इसलिए इसे सभी ब्राउज़रों तक पहुंचने के लिए कुछ समय दिया जाए, लेकिन मुझे विश्वास है कि यह वहां पहुंच जाएगा।

अंतर्निहित matchAllफ़ंक्शन अच्छा है क्योंकि यह एक पुनरावृत्ति देता है । यह हर मैच के लिए ग्रुप कैप्चरिंग भी देता है! तो आप जैसे काम कर सकते हैं

// get the letters before and after "o"
let matches = "stackoverflow".matchAll(/(\w)o(\w)/g);

for (match of matches) {
    console.log("letter before:" + match[1]);
    console.log("letter after:" + match[2]);
}

arrayOfAllMatches = [...matches]; // you can also turn the iterable into an array

यह भी ऐसा लगता है जैसे हर मैच ऑब्जेक्ट उसी प्रारूप का उपयोग करता है जैसे match()। इसलिए प्रत्येक वस्तु मैच और कब्जा समूहों की एक सरणी, तीन अतिरिक्त गुण के साथ है index, inputऔर groups। तो ऐसा लगता है:

[<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>]

अधिक जानकारी के लिए के बारे में matchAllवहाँ भी एक है गूगल के डेवलपर्स पेज । इसमें पॉलीफिल / शिम भी उपलब्ध हैं।


मैं वास्तव में इसे पसंद करता हूं, लेकिन यह अभी तक फ़ायरफ़ॉक्स 66.0.3 में काफी उतरा नहीं है। Caniuse के पास इसके बारे में अभी तक समर्थन सूची नहीं है। मैं इसके लिए तत्पर हूं। मैं इसे क्रोमियम 74.0.3729.108 में काम कर रहा हूँ।
लोनी बेस्ट

1
@LonnieBest हाँ, आप MDN पृष्ठ की संगतता अनुभाग देख सकते हैं जिसे मैंने जोड़ा था। ऐसा लगता है कि फ़ायरफ़ॉक्स ने संस्करण 67 में इसका समर्थन करना शुरू कर दिया है। फिर भी यदि आप किसी उत्पाद को शिप करने की कोशिश कर रहे हैं तो इसका उपयोग करने की अनुशंसा नहीं करेंगे। पॉलीफ़िल / शिम उपलब्ध हैं, जिन्हें मैंने अपने उत्तर में जोड़ा है
woojoo666

10

Agus के कार्य के आधार पर, लेकिन मैं मैच के मूल्यों को वापस पसंद करता हूं:

var bob = "&gt; bob &lt;";
function matchAll(str, regex) {
    var res = [];
    var m;
    if (regex.global) {
        while (m = regex.exec(str)) {
            res.push(m[1]);
        }
    } else {
        if (m = regex.exec(str)) {
            res.push(m[1]);
        }
    }
    return res;
}
var Amatch = matchAll(bob, /(&.*?;)/g);
console.log(Amatch);  // yeilds: [&gt;, &lt;]

8

Iterables अच्छे हैं:

const matches = (text, pattern) => ({
  [Symbol.iterator]: function * () {
    const clone = new RegExp(pattern.source, pattern.flags);
    let match = null;
    do {
      match = clone.exec(text);
      if (match) {
        yield match;
      }
    } while (match);
  }
});

एक लूप में उपयोग:

for (const match of matches('abcdefabcdef', /ab/g)) {
  console.log(match);
}

या यदि आप एक सरणी चाहते हैं:

[ ...matches('abcdefabcdef', /ab/g) ]

1
टाइपो: if (m)होना चाहिएif (match)
बोटजे

Arrays पहले से ही चलने योग्य हैं, इसलिए सभी प्रकार के मैचों को वापस करने वाले भी पुनरावृत्तियाँ लौटा रहे हैं। क्या बेहतर है यदि आप किसी कंसोल को लॉग करते हैं तो ब्राउज़र वास्तव में सामग्री को प्रिंट कर सकता है। लेकिन सांत्वना एक सामान्य iterable लॉगिंग आप बस [वस्तु वस्तु] {...}
StJohn3D

सभी सरणियाँ चलने योग्य हैं, लेकिन सभी पुनरावृत्तियाँ सरणियाँ नहीं हैं। यदि आप नहीं जानते कि फोन करने वाले को क्या करने की आवश्यकता होगी, तो यह चलने योग्य है। उदाहरण के लिए, यदि आप चाहते हैं कि पहला मैच एक चलने योग्य हो और अधिक कुशल हो।
sdgfsdh

आपका सपना एक वास्तविकता बन रहा है, ब्राउज़र एक अंतर्निर्मित matchAllरिटर्न के लिए समर्थन को रोल कर रहे हैं : एक
पुन

1
मैं इस जवाब के बाद मेल-मिलाप लागू कर रहा हूं। मैंने ब्राउज़र जेएस के लिए कुछ कोड लिखे जो इसे समर्थन करते थे, लेकिन नोड वास्तव में नहीं था। यह मेल खाने के लिए समान रूप से व्यवहार करता है, इसलिए मुझे सामान को फिर से लिखना नहीं पड़ा है - चीयर्स!
user37309

8

यदि आपके पास ES9 है

(मतलब अगर आपका सिस्टम: क्रोम, नोड.ज, फ़ायरफ़ॉक्स, इत्यादि एक्मास्क्रिप्ट 2019 या उसके बाद का समर्थन करते हैं)

नए का उपयोग करेंyourString.matchAll( /your-regex/ )

यदि आपके पास ES9 नहीं है

यदि आपके पास एक पुरानी प्रणाली है, तो यहां आसान प्रतिलिपि और चिपकाने के लिए एक फ़ंक्शन है

function findAll(regexPattern, sourceString) {
    let output = []
    let match
    // make sure the pattern has the global flag
    let regexPatternWithGlobal = RegExp(regexPattern,"g")
    while (match = regexPatternWithGlobal.exec(sourceString)) {
        // get rid of the string copy
        delete match.input
        // store the match data
        output.push(match)
    } 
    return output
}

उदाहरण का उपयोग:

console.log(   findAll(/blah/g,'blah1 blah2')   ) 

आउटपुट:

[ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ]

5

यहाँ मैच प्राप्त करने के लिए मेरा कार्य है:

function getAllMatches(regex, text) {
    if (regex.constructor !== RegExp) {
        throw new Error('not RegExp');
    }

    var res = [];
    var match = null;

    if (regex.global) {
        while (match = regex.exec(text)) {
            res.push(match);
        }
    }
    else {
        if (match = regex.exec(text)) {
            res.push(match);
        }
    }

    return res;
}

// Example:

var regex = /abc|def|ghi/g;
var res = getAllMatches(regex, 'abcdefghi');

res.forEach(function (item) {
    console.log(item[0]);
});

जब आप वैश्विक ध्वज जोड़ना भूल जाते हैं तो यह समाधान अनंत छोरों को रोकता है।
user68311

2

ES9 के बाद से, सभी मैचों को प्राप्त करने का एक सरल, बेहतर तरीका है, साथ में कैप्चर समूहों और उनके सूचकांक के बारे में जानकारी:

const string = 'Mice like to dice rice';
const regex = /.ice/gu;
for(const match of string.matchAll(regex)) {
    console.log(match);
}

// ["चूहे", सूचकांक: 0, इनपुट: "चूहे जैसे चूहे चावल", समूह: अपरिभाषित]

// ["पासा", सूचकांक: 13, इनपुट: "चूहे जैसे चूहे चावल", समूह: अपरिभाषित]

// ["चावल", सूचकांक: १,, इनपुट: "चूहे जैसे चूहे चावल", समूह: अपरिभाषित]

यह वर्तमान में क्रोम, फ़ायरफ़ॉक्स, ओपेरा में समर्थित है। जब आप इसे पढ़ते हैं, उसके आधार पर, इसके वर्तमान समर्थन को देखने के लिए इस लिंक को देखें।


उत्तम! लेकिन फिर भी यह ध्यान रखना ज़रूरी है कि रेगेक्स का एक ध्वज होना चाहिए gऔर इसे lastIndexआह्वान से पहले 0 पर रीसेट किया जाना चाहिए matchAll
एन। कुद्रीवत्सेव

1

इसे इस्तेमाल करो...

var all_matches = your_string.match(re);
console.log(all_matches)

यह सभी मैचों की एक सरणी लौटाएगा ... यह ठीक काम करेगा .... लेकिन याद रखें कि यह समूह को ध्यान में नहीं रखेगा..यह सिर्फ पूर्ण मैच लौटाएगा ...


0

मैं निश्चित रूप से String.match () फ़ंक्शन का उपयोग करने और इसके लिए एक प्रासंगिक RegEx बनाने की सलाह दूंगा। मेरा उदाहरण स्ट्रिंग्स की एक सूची के साथ है, जो अक्सर कीवर्ड और वाक्यांशों के लिए उपयोगकर्ता इनपुट को स्कैन करते समय आवश्यक होता है।

    // 1) Define keywords
    var keywords = ['apple', 'orange', 'banana'];

    // 2) Create regex, pass "i" for case-insensitive and "g" for global search
    regex = new RegExp("(" + keywords.join('|') + ")", "ig");
    => /(apple|orange|banana)/gi

    // 3) Match it against any string to get all matches 
    "Test string for ORANGE's or apples were mentioned".match(regex);
    => ["ORANGE", "apple"]

उम्मीद है की यह मदद करेगा!


0

यह वास्तव में आपके अधिक जटिल मुद्दे के साथ मदद करने वाला नहीं है, लेकिन मैं इसे वैसे भी पोस्ट कर रहा हूं क्योंकि यह उन लोगों के लिए एक सरल समाधान है जो आपके साथ वैश्विक खोज नहीं कर रहे हैं।

मैंने स्पष्ट होने के उत्तर में रेगेक्स को सरल किया है (यह आपकी सटीक समस्या का समाधान नहीं है)।

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

// We only want the group matches in the array
function purify_regex(reResult){

  // Removes the Regex specific values and clones the array to prevent mutation
  let purifiedArray = [...reResult];

  // Removes the full match value at position 0
  purifiedArray.shift();

  // Returns a pure array without mutating the original regex result
  return purifiedArray;
}

// purifiedResult= ["description", "aoeu"]

यह टिप्पणियों की वजह से अधिक क्रियात्मक दिखता है, यह वही है जो टिप्पणियों के बिना दिखता है

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

function purify_regex(reResult){
  let purifiedArray = [...reResult];
  purifiedArray.shift();
  return purifiedArray;
}

ध्यान दें कि जो भी समूह मेल नहीं खाते हैं उन्हें सरणी में सूचीबद्ध किया जाएगा undefined

यह समाधान ईएस 6 स्प्रेड ऑपरेटर का उपयोग करके रेगेक्स विशिष्ट मानों की सरणी को शुद्ध करता है। यदि आप IE11 का समर्थन चाहते हैं तो आपको अपना कोड बेबेल के माध्यम से चलाना होगा ।


0

यहां थोड़ी देर लूप के बिना एक लाइन समाधान है

आदेश परिणामी सूची में संरक्षित है।

संभावित डाउनसाइड्स हैं

  1. यह प्रत्येक मैच के लिए रेगेक्स को क्लोन करता है।
  2. परिणाम अपेक्षित समाधानों की तुलना में एक अलग रूप में है। आपको उन्हें एक बार और संसाधित करने की आवश्यकता होगी।
let re = /\s*([^[:]+):\"([^"]+)"/g
let str = '[description:"aoeu" uuid:"123sth"]'

(str.match(re) || []).map(e => RegExp(re.source, re.flags).exec(e))

[ [ 'description:"aoeu"',
    'description',
    'aoeu',
    index: 0,
    input: 'description:"aoeu"',
    groups: undefined ],
  [ ' uuid:"123sth"',
    'uuid',
    '123sth',
    index: 0,
    input: ' uuid:"123sth"',
    groups: undefined ] ]

0

मेरा अनुमान है कि अगर अतिरिक्त या लापता स्थानों जैसे किनारे के मामले होंगे, तो कम सीमाओं वाली यह अभिव्यक्ति भी एक विकल्प हो सकती है:

^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$

यदि आप अभिव्यक्ति का पता लगाना / सरल / संशोधित करना चाहते हैं, तो इसे regex101.com के ऊपरी दाएँ पैनल पर समझाया गया है । यदि आप चाहें, तो आप इस लिंक में भी देख सकते हैं कि यह कुछ नमूना आदानों के साथ कैसे मेल खाता है।


परीक्षा

const regex = /^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$/gm;
const str = `[description:"aoeu" uuid:"123sth"]
[description : "aoeu" uuid: "123sth"]
[ description : "aoeu" uuid: "123sth" ]
 [ description : "aoeu"   uuid : "123sth" ]
 [ description : "aoeu"uuid  : "123sth" ] `;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

RegEx सर्किट

jex.im नियमित अभिव्यक्ति की कल्पना करता है:

यहां छवि विवरण दर्ज करें


-5

यहाँ मेरा जवाब है:

var str = '[me nombre es] : My name is. [Yo puedo] is the right word'; 

var reg = /\[(.*?)\]/g;

var a = str.match(reg);

a = a.toString().replace(/[\[\]]/g, "").split(','));

3
आपके इनपुट स्ट्रिंग ( str) में गलत प्रारूप (बहुत अधिक हार्ड ब्रैकेट) हैं। आप केवल कुंजी को पकड़ते हैं, न कि मूल्य को। आपके कोड में सिंटैक्स त्रुटि है और निष्पादित नहीं करता है (अंतिम कोष्ठक)। यदि आप पहले से ही स्वीकार किए गए उत्तर के साथ "पुराने" प्रश्न का उत्तर देते हैं, तो सुनिश्चित करें कि आप अधिक ज्ञान और बेहतर उत्तर जोड़ते हैं, फिर पहले से ही स्वीकार किए जाते हैं। मुझे नहीं लगता कि आपका जवाब ऐसा करता है।
साफ किया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.