【问题标题】:What is an efficient method for extracting data from a string into a Map?将字符串中的数据提取到 Map 中的有效方法是什么?
【发布时间】:2017-10-08 10:46:24
【问题描述】:

这是用 C++ 编写的。假设我有一个看起来像这样的字符串"[05]some words here [13]some more words here [17]and so on"

我想将此字符串拆分为Map<int, std::string>,其中数字作为键,直到下一个代码的文本作为值。括号将被完全忽略。

到目前为止,我一直在使用标准库和 SDL(我正在制作一个小游戏),但我愿意安装 boost 或任何其他有帮助的库。

我的第一个想法是要么使用一些 Boosts Regex 函数来进行某种正则表达式查找和替换,要么简单地将其转换为一个字符数组,遍历每个字符,查找括号并记录里面的数字,但这似乎好像它效率低下,特别是因为我确信在 C++ 中可能有一种流行的方法来做到这一点。

【问题讨论】:

  • 一个遍历每个字符的 char 数组......这将是低效的。为什么效率低下?!

标签: c++ regex string dictionary


【解决方案1】:

您可以通过 '[' 字符拆分字符串并将部分收集到向量中。然后对于向量的每个元素,将其分成两部分(在“]”之前和之后)。首先转换为数字并将所有内容放入地图中。这一切都将是标准的标准方法。

【讨论】:

    【解决方案2】:

    您可以为此使用regex_token_iterator。基本思路如下:

    #include <iostream>
    #include <map>
    #include <string>
    #include <vector>
    #include <regex>
    
    using namespace std;
    
    map<int, string> extract( const std::string & s )
    {
        map<int, string> m; 
        static const regex r( "\\s*\\[(\\d+)\\]" );
        sregex_token_iterator tok( s.begin(), s.end(), r, { -1, 1 } );
        tok++;  // Skip past the first end-of-sequence iterator.
    
        for( sregex_token_iterator end; tok != end; )
        {
            int num = stoi( *tok, nullptr, 10 );
            if( ++tok != end )
            {
                m.emplace( make_pair( num, *tok++ ) );
            }
        }
        return m;
    }
    
    int main()
    {
        auto m = extract("[05]some words here [13]some more words here [17]and so on");
        for( auto & p : m ) cout << p.first << ": '" << p.second << "'" << endl;
        return 0;
    }
    

    这里是搜索和提取模式\s*\[(\d+)\]\s*,这意味着它将删除方括号前后的所有空格,并创建一个匹配组以匹配至少一个数字。

    通过在迭代器上使用 {-1, 1},我们要求迭代序列在匹配之前提供所有文本,然后是匹配组 1。

    输出:

    5: 'some words here'
    13: 'some more words here'
    17: 'and so on'
    

    工作示例是here

    【讨论】:

    • 谢谢你,感谢你的例子,我能够了解如何使用 regex_token_iterator!
    【解决方案3】:

    您可以使用substr()find_first_of() 从字符串中提取实际数据,如下所示:

    #include <string>
    #include <iostream>
    #include <map>
    
    using std::string;
    using std::cout;
    using std::endl;
    using std::map;
    
    
    map<int,string> StrToMap(const string& str)
    {
        map<int, string> temMap;
    
        for (int i(0); i < str.size(); ++i){
            if ( str[i] == '[' ){
                string tempIdx = str.substr(i+1, str.find_first_of("]",i)-i-1 );
                int a = i+str.find_first_of("]",i)-i+1;
                int b = str.find_first_of("[",a)-1;
                if ( b < 0 )
                    b = str.size();
                string tempStr = str.substr(a, b-a);
                int idx = std::stoi(  tempIdx );
                temMap[idx] = tempStr; 
            }
        }
    
        return temMap;
    }
    
    
    int main(int argc, char* argv[])
    {
       map<int, string> temMap = StrToMap("[05]some words here [13]some more words here [17]and so on");
    
      for (std::map<int, string>::const_iterator it=temMap.begin(); it!=temMap.end(); ++it)
        std::cout << it->first << " " << it->second << '\n';
    
        return 0;
    }
    

    结果是

    5 some words here
    13 some more words here
    17 and so on
    

    【讨论】:

    • 感谢您向我展示了我的方式错误。根据我的测试,你的方法是最快的,这与我的预期相反!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 2020-10-24
    • 2016-11-03
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多