C++ - 通过正则表达式分割字符串

33

我想要用regex来分割std::string

我在Stackoverflow上找到了一些解决方案,但大多数是通过单个空格来分割字符串或使用boost等外部库。

我无法使用boost。

我想要通过正则表达式"\\s+"来分割字符串。

我正在使用这个g++版本g++ (Debian 4.4.5-8) 4.4.5,而且我无法升级。


现在我正在使用这个函数来分割字符串:https://dev59.com/k3VC5IYBdhLWcg3wnCj6#236803 它只能按__单个字符__拆分。正则表达式格式是正确的,我已经在一个Java项目中使用了它。工作得很好。 - nothing-special-here
问题在于我不太懂C++... 我只想知道如何使用旧的C++标准(可能是C++03)拆分std::string。如果您有一些链接/代码,请粘贴它。:)谢谢! - nothing-special-here
你能展示输入和期望输出的示例吗? - melwil
使用boost可能是一个选项。 - Bernhard Barker
C++03没有正则表达式库,C++11有,但你的编译器不支持C++11。你需要使用现有的第三方正则表达式库或者自己编写一个。 - n. m.
显示剩余3条评论
4个回答

62
#include <regex>

std::regex rgx("\\s+");
std::sregex_token_iterator iter(string_to_split.begin(),
    string_to_split.end(),
    rgx,
    -1);
std::sregex_token_iterator end;
for ( ; iter != end; ++iter)
    std::cout << *iter << '\n';
< p > 这里关键是 < code > -1 :当构建迭代器时,迭代器指向匹配之前的文本,每次增加后,迭代器指向先前匹配之后的文本。 < p > 如果您没有 C++11,则可以使用 TR1 或(可能需要略微修改)Boost。

1
@Narek - 要么这样,要么添加显式模板参数:regex_token_iterator<std::string::iterator>sregex_token_iterator 更容易。已修复。谢谢。 - Pete Becker
cplusplus.com上的最后一个示例与此答案类似。 - solstice333

16

在回答@Pete Becker的基础上,我提供一个可以使用正则表达式分割文本的“resplit”函数示例:

#include <regex>

std::vector<std::string> resplit(const std::string &s, const std::regex &sep_regex = std::regex{"\\s+"}) {
  std::sregex_token_iterator iter(s.begin(), s.end(), sep_regex, -1);
  std::sregex_token_iterator end;
  return {iter, end};
}

这个的工作原理如下:

   string s1 = "first   second third    ";
   vector<string> v22 = resplit(s1);

   for (const auto & e: v22) {
       cout <<"Token:" << e << endl;
   }

   //Token:first
   //Token:second
   //Token:third


   string s222 = "first|second:third,forth";
   vector<string> v222 = resplit(s222, "[|:,]");

   for (const auto & e: v222) {
       cout <<"Token:" << e << endl;
   }

   //Token:first
   //Token:second
   //Token:third
   //Token:forth

13

如果您只想通过多个空格来拆分字符串,则无需使用正则表达式。编写自己的正则表达式库对于如此简单的事情来说过于复杂。

您在评论中提到的答案(Split a string in C++?),可以轻松更改以排除任何空元素(如果有多个空格)。

std::vector<std::string> &split(const std::string &s, char delim,std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        if (item.length() > 0) {
            elems.push_back(item);  
        }
    }
    return elems;
}


std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    split(s, delim, elems);
    return elems;
}

在将item推入elems向量之前检查item.length() > 0,这样如果您的输入包含多个定界符(例如空格),您就不会再获得额外的元素。


我们刚好在同一时间找到了相同的解决方法 :) 但你在 Stack Overflow 上贴出答案的速度更快(约10分钟)。+1并接受。 - nothing-special-here
2
你也应该同意这个事实,使用C++来分割字符串看起来更加过度,而在C#中,你只需要使用str.split(...) ;) - Lu4

2
string s = "foo bar  baz";
regex e("\\s+");
regex_token_iterator<string::iterator> i(s.begin(), s.end(), e, -1);
regex_token_iterator<string::iterator> end;
while (i != end)
   cout << " [" << *i++ << "]";

打印[foo] [bar] [baz]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接