使用标准库将循环替换为 strtok
Replace a loop with strtok by using Standard Library
我有一个strtok解决的问题(从字符串中拆分子字符串(,但是我意识到 strtok 并不安全。我想使用C++标准库中一些更现代的部分。
我应该改用什么?
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:
#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;
}
下面是拆分分隔字符串的两个示例。
第一种将std::getline
与字符串流一起使用,指定分隔符而不是使用默认换行符。 此技术只能使用单字符分隔符。
第二个示例使用 <regex>
库,该库允许任意长度的分隔符,还可以更好地控制如何识别分隔符。 请注意,点字符必须在正则表达式规范中进行转义,因为在正则表达式语言中,"." 充当通配符。
#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';
}
}
我有一个只有静态方法的实用程序类,因为您无法创建此实用程序类的实例。我将其用于处理字符串的各种方法,从转换到删除空格、拆分、更改大小写等。下面是一个从此类中拆分字符串的函数:
实用性.h
class Utility {
public:
static std::vector<std::string> splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty = true );
private:
Utility();
};
效用.cpp
#include "Utility.h"
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit,
const std::string& strDelimiter,
const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
} // splitString
此实用程序方法工作所需的库包括<vector>
、<string>
和<algorithm>
,它们在几乎所有应用程序中都常用。
要使用这个函数,我们可以做一个简单的测试,如下所示:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "Utility.h"
int main() {
std::string someLongString2( "Hello World How Are You" );
std::vector<std::string> singleWords;
singleWords = Utility::splitString( someLongString, " " );
// Space is the delimiter and now each individual word
// from the long string are now each a new string stored
// in this vector. You can use any character for your delimiter.
// Also this function is not limited to having a single character
// as its delimiter. You can use a series of characters or specific
// words as your delimiter. Such as a comma followed by a space.
std::string someLongString2( "Hello, World, How, Are, You" );
singleWords.clear();
singleWords = Utility::splitString( someLongString2, ", " );
return 0;
} // main
<</div>
div class="answers"> 下面是使用标准库替换strtok的解决方案(使用收到的答案(:
std::vector<std::string> SplitLine(std::string const& line, std::string seps)
{
std::regex regxSeps(seps); // the dot character needs to be escaped in a regex
std::sregex_token_iterator rit(line.begin(), line.end(), regxSeps, -1);
return std::vector<std::string>(rit, std::sregex_token_iterator());
}
static int ParseLine(std::string line, std::string seps, size_t startIdx, std::vector<CNode>& collection)
{
if (startIdx > collection.size())
{
throw std::invalid_argument("the start index is out of range");
}
auto objectTypes = SplitLine(line, seps);
auto idx = startIdx;
for (const auto& objectType : objectTypes)
{
if (idx == collection.size())
{
collection.push_back(CNode(idx));
}
collection[idx++].SetObjectType(objectType);
}
return (idx - 1);
}
int main()
{
std::string seps = "\."; // the dot character needs to be escaped in a regex
...
}
相关文章:
- 模板参数替换失败,并且未完成隐式转换
- 如何用转义符替换字符串中的所有特殊字符
- 为什么除非添加括号,否则构造函数上的模板替换会失败?
- 在一个读写器队列中,我可以用volatile替换原子吗
- 用符号版本替换对函数的所有调用
- 如何通过替换顺序代码的while循环来添加OpenMP for循环
- 替换基于地图的所有引用
- 按平均值替换数组中的元素
- 我可以在这里替换什么,因为我不能在 C# 中使用隐式变量的 lambda 函数?
- 如何将字节数组元素替换为修改的十六进制 ASCII 符号?
- 初始化 std::vector 替换为单大括号而不是双大括号
- 删除/替换C++字符串中的多字符 (ÿû)
- 将 malloc 替换为数组
- 如何替换此示例代码片段中已弃用的handler_type_t或 boost::asio::handler_type?
- 如何在C++中用'\'替换''来处理转义序列?
- 替换密码:哪一个?
- 替换 C++17 中移除的绑定 1st
- 将 Boost MPL 容器替换为 C++17 功能
- C++:如何用单个命令替换复杂的迭代?
- 使用标准库将循环替换为 strtok