ब्रेसिज़ से वेक्टर बनाने के लिए Regex

मैं एक std :: string को चालू करना चाहता हूं जैसे कि:

"{1, 2}, {one, two}, {123, onetwothree}"

std :: जोड़े के std :: जोड़े के std :: vector में std :: स्ट्रिंग्स जो कुछ ऐसा दिखाई देगा:

std::vector> v = {{"1", "2"}, {"one", "two"}, {"123", "onetwothree"}};
// where, for instance
v[0] == std::make_pair("1", "2");//etc.

ऐसा लगता है कि मूल std :: स्ट्रिंग को std :: regex का उपयोग करके सबसे आसानी से पार्स किया जा सकता है, लेकिन मैं एक regex विशेषज्ञ (या नौसिखिया) नहीं हूं, अकेले एक std: : regex विशेषज्ञ। यहां एक नुस्खा के लिए कोई विचार?

1
"{1, {2, 3} {{a, b}}}" के बारे में क्या?
जोड़ा लेखक Kerrek SB, स्रोत
अभी, मैं मैन्युअल रूप से ऐसा करने के लिए std :: string की स्वयं की खोज विधियों का उपयोग कर रहा हूं। एक रेगेक्स व्यक्ति नहीं होने के कारण, यह शुरू करने के लिए एक अच्छा मामला प्रतीत होता था, लेकिन मुझे मिले उदाहरणों में एक एकल ब्रेस मैच की सामग्री लौटती है, लेकिन ब्रेस मैचों के कई मैचों के माध्यम से पुनरावृत्ति नहीं होती है।
जोड़ा लेखक DiB, स्रोत
प्रारूप के लिए, यह "{पहला, दूसरा}, {तीसरा, चौथा}, आदि के साथ बहुत सख्त है।" यह स्ट्रिंग्स के जोड़े की एक सूची है, अगर इससे अधिक स्पष्ट हो जाता है।
जोड़ा लेखक DiB, स्रोत
ठीक। यह समझ आता है। मैं पार्सिंग बोझ को मानक पुस्तकालय में स्थानांतरित करके कुछ स्थिरता खरीदने की उम्मीद कर रहा था, लेकिन शायद मेरा अधिक पुनरावृत्ति वर्तमान समाधान सबसे अच्छा है? ताजा दृश्य के लिए धन्यवाद!
जोड़ा लेखक DiB, स्रोत
मुझे नहीं पता कि आप एक ही रेगेक्स में पूरी स्ट्रिंग को पार्स करना चाहते हैं। पीसीआरई की कुछ और आर्केन विशेषताओं का उपयोग करना संभव हो सकता है, लेकिन यह अनिवार्य रूप से कोड से आपके प्रोग्राम की जटिलता को रेगेक्स में धक्का देता है, और यह एक अच्छी बात नहीं है। एक समय में ब्रेसिज़ की एक जोड़ी को पार्स करना और उस पर लूपिंग शायद अधिक क्लीनर कोड के लिए तैयार करेगी।
जोड़ा लेखक Tim Pierce, स्रोत
और आपने अभी तक क्या प्रयास किया है?
जोड़ा लेखक ScarletAmaranth, स्रोत
मुझे सी ++ के बारे में निश्चित नहीं है, लेकिन आम तौर पर रेगेक्स पुस्तकालय ऐसी चीजों को पार्स करने की अनुमति नहीं देते हैं। आप आमतौर पर केवल सब्सट्रिंग की निरंतर संख्या निकाल सकते हैं।
जोड़ा लेखक zch, स्रोत
इससे मदद मिल सकती है: cplusplus.com/reference/regex/regex_search
जोड़ा लेखक Zac Howland, स्रोत
\ {([^ {},] +), \ s * ([^ {},]) \} संभवतः वह रेगेक्स है जिसे आप ढूंढ रहे हैं, आप कर सकते हैं जो qwrrty ने कहा संरचना। जब आप स्ट्रिंग फॉर्म पर जाते हैं तो अपनी बैकस्लैश को दोगुना करना सुनिश्चित करें।
जोड़ा लेखक FrankieTheKneeMan, स्रोत

2 उत्तर

Currently, doesn't work well with GCC, here is a boost version, compiled with -lboost_regex.

boost capture fits this case, but it's by default not enabled.

Here is the original post: Boost C++ regex - how to get multiple matches

#include 
#include 
#include 

using namespace std;

int main()
{
  string str = "{1, 2}, {one, two}, {123, onetwothree}";

  boost::regex pair_pat("\\{[^{}]+\\}");
  boost::regex elem_pat("\\s*[^,{}]+\\s*");

  boost::sregex_token_iterator end;

  for(boost::sregex_token_iterator iter(str.begin(), str.end(), pair_pat, 0);
      iter != end; ++iter) {

    string pair_str = *iter;
    cout << pair_str << endl;

    for (boost::sregex_token_iterator it(pair_str.begin(), pair_str.end(), elem_pat, 0);
         it != end; ++it)
      cout << *it << endl;
  }

  return 0;
}
3
जोड़ा

मिलान पैटर्न बहुत सरल है: "\ {\ s * (\ w +) \ s * \, \ s * (\ w +) \ s * \}" इसलिए हमें बस सभी मैचों को लूप करने और इकट्ठा करने की आवश्यकता है। सी ++ 11 यह बहुत सीधे आगे बनाता है। इसे एक शॉट दें:

std::string str = "{1, 2}, {one, two}, {123, onetwothree}";
std::vector> pairs;
std::regex exp(R"(\{\s*(\w+)\s*\,\s*(\w+)\s*\})");
std::smatch sm;
std::string::const_iterator cit = str.cbegin();
while (std::regex_search(cit, str.cend(), sm, exp)) {
    if (sm.size() == 3)//3 = match, first item, second item
        pairs.emplace_back(sm[1].str(), sm[2].str());
   //the next line is a bit cryptic, but it just puts cit at the remaining string start
    cit = sm[0].second;
}

संपादित करें: यह कैसे काम करता है पर स्पष्टीकरण: यह एक समय में एक पैटर्न से मेल खाता है, प्रत्येक मैच के बाद शेष को इंगित करने के लिए निरंतर पुनरावर्तक का उपयोग करके:

{1, 2}, {one, two}, {123, onetwothree}
^ iterator cit
-- regex_search matches "{1, 2}" sm[1] == "1", sm[2] == "2"

{1, 2}, {one, two}, {123, onetwothree}
      ^ iterator cit
-- regex_search matches "{one, two}" sm[1] == "one", sm[2] == "two"

{1, 2}, {one, two}, {123, onetwothree}
                  ^ iterator cit
-- regex_search matches "{123, onetwothree}" sm[1] == "123", sm[2] == "onetwothree"

{1, 2}, {one, two}, {123, onetwothree}
                                      ^ iterator cit
-- regex_search returns false, no match
1
जोड़ा
मैंने यह कैसे बताया कि यह कैसे काम करता है पर एक स्पष्टीकरण जोड़ा - रेगेक्स एन मैचों से मेल नहीं खा रहा है, बल्कि पहला मैच है। फिर हम शेष पर पुनरावृत्त करने के लिए एक पुनरावर्तक का उपयोग करते हैं। इसे लूप में करने से हमें हर मैच मिल जाता है।
जोड़ा लेखक Sam Cristall, स्रोत
मैंने इसे अंदर रखा और यह वैसे ही काम करता था जैसा मैं चाहता था। मुझे लगता है कि यहां मेरा सबसे बड़ा सवाल यह समझने में है कि रेगेक्स कैसे एन-मैचों की तलाश करना जानता है। मैं खोजों और अन्य टिप्पणियों के आधार पर अन्य विचारों के साथ खेल रहा था, और मुझे मिलान किए गए {} के बाहरी सेट से अधिक कठिन समय मिल रहा था।
जोड़ा लेखक DiB, स्रोत
आह! तो रेगेक्स एक समय में सिर्फ एक से मेल खाता है, लेकिन यह स्ट्रिंग इटरेटर है जो स्ट्रिंग को आगे बढ़ने वाले किसी भी मैचों की तलाश में है। वहां अतिरिक्त स्पष्टीकरण के लिए धन्यवाद। (मुझे यह देखना चाहिए था कि इटेटरेटर का अधिक बारीकी से उपयोग कैसे किया जा रहा था!)
जोड़ा लेखक DiB, स्रोत
ऐसा लगता है कि std :: regex_token_iterator क्या करता है
जोड़ा लेखक Cubbi, स्रोत