在C++中标记字符串
在本文中,我们将研究如何标记C++字符串。
其他语言使用string.split()有一个非常简单的解决方案。
不幸的是,本机C++不支持此方法,因此我们将向您介绍不同的方法。
方法1:转换为C字符串并使用strtok()
对于熟悉C的人来说,最明显的方法是将C++的string转换为字符数组(" C string"),然后在C字符串上使用strtok()。
由于strtok()
是本机C标记器,因此这是一种可能的方式。
#include <iostream> #include <string> //C++ Strings #include <string.h> //For C-style strtok() using namespace std; void c_style_tokenizer(string inp, char* delim) { //Tokenizes the input string and prints the output //It does not return anything, since this is just for //illustration const char* c_string = inp.c_str(); //Tokenize the C string using the delimiter char* token = strtok((char*)c_string, delim); while (token) { printf("Token: %s\n", token); //Get next token token = strtok(NULL, delim); } } int main() { //Convert the string delimiter to a char* before passing //it to the function, since strtok() does not support string arguments string input = "Hello from theitroad"; cout << "Input String: " << input << endl; c_style_tokenizer(input, (char*) " "); return 0; }
输出
Input String: Hello from theitroad Token: Hello Token: from Token: theitroad
如您所见,的确,在使用string.c_str()转换为C字符串并使用strtok()处理它之后,我们得到了标记化的输出!
但是,此方法容易出现某些缓冲区溢出错误,因为strtok()
要求输入字符串的终止符为\ 0。
由于某些原因,如果我们的输入字符串不包含它,则可能会导致错误。
另外,如果您的程序使用多个线程,则此方法可能会失败,因为strtok()
使用全局变量来跟踪当前位置。
由于潜在的警告,我们将介绍一些更合适的方法。
方法2:使用正则表达式令牌迭代器(推荐)
另一种方法是使用<regex>头文件中包含的sregex_token_iterator。
这是现代C++的推荐方法,因为它使用了一些STL方法。
如果要解析空格,则首先使用正则表达式字符串" \ s +"构造一个" regex"对象,这意味着要连续捕获至少一个或者多个空格:
regex reg("\s+");
我们需要在" \ s +"中转义反斜杠,因此最终的字符串变为" \ s +"。
现在我们有了正则表达式模式,可以在执行正则表达式匹配之后使用regex_token_iterator
并使用迭代器构造字符串的<vector>了。
//Courtesy: https://stackoverflow.com/a/27468529 #include <iostream> #include <regex> #include <string> using namespace std; int main() { string str("Hello from theitroad"); //Regex for tokenizing whitespaces regex reg("\s+"); //Get an iterator after filtering through the regex sregex_token_iterator iter(str.begin(), str.end(), reg, -1); //Keep a dummy end iterator - Needed to construct a vector //using (start, end) iterators. sregex_token_iterator end; vector<string> vec(iter, end); for (auto a : vec) { cout << a << endl; } }
现在,您可以将标记化的字符串作为向量。
这也非常方便,因为您可以按需获得琴弦!
输出
Hello from theitroad
尽管这是一种可靠的方法,但是如果您使用的是大字符串,则必须小心,因为正则表达式会影响性能,并且效率不是最高。
方法3:使用<boost>库
如果您当前的要求允许使用诸如<boost>之类的外部库,则可以使用这种方法。
我们可以在这里使用boost :: algorithm :: split
函数来标记我们的输入字符串。
//Courtesy - https://stackoverflow.com/a/59552 #include <vector> #include <boost/algorithm/string.hpp> int main() { auto s = "a,b, c ,,e,f,"; std::vector<std::string> fields; boost::split(fields, s, boost::is_any_of(",")); for (const auto& field : fields) std::cout << "\"" << field << "\"\n"; return 0; }
输出
"a" "b" " c " "" "e" "f" ""
在解析逗号之后,这确实为我们提供了标记化的输出。