簡體   English   中英

標記字符串,接受CPP中給定字符集之間的所有內容

[英]tokenizing string , accepting everything between given set of characters in CPP

我有以下代碼:

   int main()
{
  string s = "server ('m1.labs.teradata.com') username ('use\\')r_*5') password('u\" er 5') dbname ('default')";

    regex re("(\'[!-~]+\')");
    sregex_token_iterator i(s.begin(), s.end(), re, 1);
    sregex_token_iterator j;

    unsigned count = 0;
    while(i != j)
    {
        cout << "the token is  "<<*i<< endl;
        count++;
    }
    cout << "There were " << count << " tokens found." << endl;

  return 0;
}

使用上面的正則表達式,我想提取括號和單引號之間的字符串:,輸出應如下所示:

the token is   'm1.labs.teradata.com'
the token is   'use\')r_*5'
the token is   'u" er 5'
the token is   'default'
There were 4 tokens found.

基本上,正則表達式應該提取“('”和“''')之間的所有內容。 它可以是任何空格,特殊字符,引號或結束語。 我之前使用過以下正則表達式:

boost::regex re_arg_values("(\'[!-~]+\')");

但不是在接受空間。 請有人幫我解決這個問題。 提前致謝。

這是使用Spirit X3創建語法以實際解析此語法的示例。 我想解析成一個(key-> value)對的映射,這比盲目地假設名稱始終相同要有意義得多:

using Config = std::map<std::string, std::string>;
using Entry  = std::pair<std::string, std::string>;

現在,我們使用X3設置一些語法規則:

namespace parser {
    using namespace boost::spirit::x3;

    auto value  = quoted("'") | quoted('"');
    auto key    = lexeme[+alpha];
    auto pair   = key >> '(' >> value >> ')';
    auto config = skip(space) [ *as<Entry>(pair) ];
}

輔助函數as<>quoted是簡單的lambda:

template <typename T> auto as = [](auto p) { return rule<struct _, T> {} = p; };
auto quoted = [](auto q) { return lexeme[q >> *('\\' >> char_ | char_ - q) >> q]; };

現在我們可以將字符串直接解析為映射:

Config parse_config(std::string const& cfg) {
    Config parsed;
    auto f = cfg.begin(), l = cfg.end();
    if (!parse(f, l, parser::config, parsed))
        throw std::invalid_argument("Parse failed at " + std::string(f,l));
    return parsed;
}

和演示程序

int main() {
    Config cfg = parse_config("server ('m1.labs.teradata.com') username ('use\\')r_*5') password('u\" er 5') dbname ('default')");

    for (auto& setting : cfg)
        std::cout << "Key " << setting.first << " has value " << setting.second << "\n";
}

版畫

Key dbname has value default
Key password has value u" er 5
Key server has value m1.labs.teradata.com
Key username has value use')r_*5

現場演示

生活在Coliru

#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <map>

using Config = std::map<std::string, std::string>;
using Entry  = std::pair<std::string, std::string>;

namespace parser {
    using namespace boost::spirit::x3;

    template <typename T> auto as = [](auto p) { return rule<struct _, T> {} = p; };
    auto quoted = [](auto q) { return lexeme[q >> *(('\\' >> char_) | (char_ - q)) >> q]; };

    auto value  = quoted("'") | quoted('"');
    auto key    = lexeme[+alpha];
    auto pair   = key >> '(' >> value >> ')';
    auto config = skip(space) [ *as<Entry>(pair) ];
}

Config parse_config(std::string const& cfg) {
    Config parsed;
    auto f = cfg.begin(), l = cfg.end();
    if (!parse(f, l, parser::config, parsed))
        throw std::invalid_argument("Parse failed at " + std::string(f,l));
    return parsed;
}

int main() {
    Config cfg = parse_config("server ('m1.labs.teradata.com') username ('use\\')r_*5') password('u\" er 5') dbname ('default')");

    for (auto& setting : cfg)
        std::cout << "Key " << setting.first << " has value " << setting.second << "\n";
}

獎金

如果您想學習如何提取原始輸入,請嘗試

auto source = skip(space) [ *raw [ pair ] ]; 

像這樣:

using RawSettings = std::vector<std::string>;

RawSettings parse_raw_config(std::string const& cfg) {
    RawSettings parsed;
    auto f = cfg.begin(), l = cfg.end();
    if (!parse(f, l, parser::source, parsed))
        throw std::invalid_argument("Parse failed at " + std::string(f,l));
    return parsed;
}

int main() {
    for (auto& setting : parse_raw_config(text))
        std::cout << "Raw: " << setting << "\n";
}

哪些印刷品: Live on Coliru

Raw: server ('m1.labs.teradata.com')
Raw: username ('use\')r_*5')
Raw: password('u" er 5')
Raw: dbname ('default')

解決了一些語法和樣式問題:

  • 您需要在C字符串中轉義\\
  • 您輸入了" in " ,語法錯誤
#include <boost/regex.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>

int main() {
    std::string s = "server ('m1.labs.teradata.com') username ('use\')r_*5') password('u' er 5') dbname ('default')";

    boost::regex re(R"(('([^'\\]*(?:\\[\s\S][^'\\]*)*)'))");

    size_t count = 0;
    for (auto tok : boost::make_iterator_range(boost::sregex_token_iterator(s.begin(), s.end(), re, 1), {})) {
        std::cout << "Token " << ++count << " is " << tok << "\n";
    }
}

版畫

Token 1 is 'm1.labs.teradata.com'
Token 2 is 'use'
Token 3 is ') password('
Token 4 is ' er 5'
Token 5 is 'default'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM