使用标准库用 strtok 替换循环 [英] Replace a loop with strtok by using Standard Library
问题描述
我有一个 strtok 解决的问题(从字符串中拆分子字符串)但是我意识到 strtok 是不安全的.我想使用 C++ 标准库的一些更现代的部分.
I have a problem that strtok solves (split substrings from a string) but I realize that strtok is not safe. I want to use some more modern parts of the C++ standard library.
我应该用什么代替?
static int ParseLine(std::string line,
std::string seps,
int startIdx,
std::vector<CNode>& collection)
{
if (startIdx > collection.size())
{
throw std::invalid_argument("the start index is out of range");
}
char buf[2000];
strcpy_s(buf, line.c_str());
auto idx = startIdx;
for (auto objectType = strtok(buf, seps.c_str()); objectType != nullptr; idx++)
{
if (idx == collection.size())
{
collection.push_back(CNode(idx));
}
collection[idx].SetObjectType(objectType);
objectType = strtok(nullptr, seps.c_str());
}
return (idx - 1);
}
这里是一个完整的示例,它与_CRT_SECURE_NO_WARNINGS:
Here a complete sample that compiles with _CRT_SECURE_NO_WARNINGS:
#include <string>
#include <vector>
#include <iostream>
class CObject
{
std::string _objectType;
public:
CObject() : _objectType("n/a") {}
void SetObjectType(std::string objectType) { _objectType = objectType; }
std::string GetObjectType() const { return _objectType; }
};
class CNode
{
int _id;
CObject _object;
public:
explicit CNode(int id) : _id(id) {}
void SetObjectType(std::string objectType) { _object.SetObjectType(objectType); }
std::string GetObjectType() const { return _object.GetObjectType(); }
};
// Update the collection of nodes with the object types found in the line specified.
// Return the number of elements in the collection.
static int ParseLine(std::string line, std::string seps, int startIdx, std::vector<CNode>& collection)
{
if (startIdx > collection.size())
{
throw std::invalid_argument("the start index is out of range");
}
char buf[2000];
strcpy_s(buf, line.c_str());
auto idx = startIdx;
for (auto objectType = strtok(buf, seps.c_str()); objectType != nullptr; idx++)
{
if (idx == collection.size())
{
collection.push_back(CNode(idx));
}
collection[idx].SetObjectType(objectType);
objectType = strtok(nullptr, seps.c_str());
}
return (idx - 1);
}
int main()
{
std::string seps = ".";
// 2 3 4 5 6 7 8 9
std::string line = "abc.def.ghi.klm.nop.qrs.tuv.wxyz";
std::vector<CNode> collection { CNode(0), CNode(1), CNode(2) , CNode(3) , CNode(4) , CNode(5) };
auto startAt = 2;
try
{
auto collection_size = ParseLine(line, seps, startAt, collection);
std::cout << collection_size << std::endl;
for (auto value : collection)
{
std::cout << value.GetObjectType() << std::endl;
}
}
catch (std::invalid_argument& e)
{
std::cout << " out of range exception " << e.what() << std::endl;
}
return 0;
}
推荐答案
这里有两个分割分隔字符串的例子.
Here are two examples of splitting a delimited string.
第一个将 std::getline
与字符串流一起使用,指定分隔符而不是使用默认的换行符.此技术只能使用单字符分隔符.
The first uses std::getline
with a string stream, specifying a separator character instead of using the default newline character. Only single-character separators may be used with this technique.
第二个示例使用了
库,它允许使用任意长度的分隔符,并且让您更好地控制如何识别分隔符.请注意,点字符必须在正则表达式规范中转义,因为在正则表达式语言中,."用作通配符.
The second example uses the <regex>
library, which allows separators of arbitrary length and also gives you more control over how a separator is recognized. Note that the dot character must be escaped in the regex specification, because in the regex language, "." acts as a wildcard.
#include <iostream>
#include <sstream>
#include <vector>
#include <regex>
std::vector<std::string> GetlineSplit(std::string const& line) {
static const char sep = '.';
std::istringstream liness{line};
std::vector<std::string> fields;
for(std::string field; std::getline(liness, field, sep); ) {
fields.push_back(field);
}
return fields;
}
std::vector<std::string> RegexSplit(std::string const& line) {
std::regex seps("\\."); // the dot character needs to be escaped in a regex
std::sregex_token_iterator rit(line.begin(), line.end(), seps, -1);
return std::vector<std::string>(rit, std::sregex_token_iterator());
}
int main() {
std::string line = "abc.def.ghi.klm.nop.qrs.tuv.wxyz";
std::cout << "getline split result:\n";
auto fields_getline = GetlineSplit(line);
for(const auto& field : fields_getline) {
std::cout << field << '\n';
}
std::cout << "\nregex split result:\n";
auto fields_regex = RegexSplit(line);
for(const auto& field : fields_regex) {
std::cout << field << '\n';
}
}
这篇关于使用标准库用 strtok 替换循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!