- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我读了The most elegant way to iterate the words of a string并享受答案的简洁性。现在我想对 string_view 做同样的事情。问题是,stringstream
不能接受 string_view
:
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
int main() {
using namespace std;
string_view sentence = "And I feel fine...";
istringstream iss(sentence); // <== error
copy(istream_iterator<string_view>(iss),
istream_iterator<string_view>(),
ostream_iterator<string_view>(cout, "\n"));
}
那么有没有办法做到这一点?如果不是,那么这样的事情不是惯用的推理是什么?
最佳答案
按分隔符拆分并返回 vector<string_view>
.
设计用于在 .csv
中快速拆分行文件。
在 MSVC 2017 v15.9.6
下测试和 Intel Compiler v19.0
用 C++17
编译(这是 string_view
所必需的)。
#include <string_view>
std::vector<std::string_view> Split(const std::string_view str, const char delim = ',')
{
std::vector<std::string_view> result;
int indexCommaToLeftOfColumn = 0;
int indexCommaToRightOfColumn = -1;
for (int i=0;i<static_cast<int>(str.size());i++)
{
if (str[i] == delim)
{
indexCommaToLeftOfColumn = indexCommaToRightOfColumn;
indexCommaToRightOfColumn = i;
int index = indexCommaToLeftOfColumn + 1;
int length = indexCommaToRightOfColumn - index;
// Bounds checking can be omitted as logically, this code can never be invoked
// Try it: put a breakpoint here and run the unit tests.
/*if (index + length >= static_cast<int>(str.size()))
{
length--;
}
if (length < 0)
{
length = 0;
}*/
std::string_view column(str.data() + index, length);
result.push_back(column);
}
}
const std::string_view finalColumn(str.data() + indexCommaToRightOfColumn + 1, str.size() - indexCommaToRightOfColumn - 1);
result.push_back(finalColumn);
return result;
}
注意生命周期:a string_view
不应该比 parent 活得更长string
它是进入的窗口。如果父string
超出范围,那么 string_view
是什么指向是无效的。在这种特殊情况下,API 设计很难出错,因为输入/输出都是 string_view
这些都是进入父字符串的窗口。这最终在内存复制和 CPU 使用方面变得相当高效。
请注意,如果使用 string_view
唯一的缺点是失去隐式空终止。所以使用支持 string_view
的函数,例如lexical_cast
Boost 中用于将字符串转换为数字的函数。
我用它来快速解析 .csv 文件。为了获取 .csv 文件中的每一行,我使用了 istringstream
和 getLine()
这是非常快的(单核上每秒约 2GB 或每秒 1,200,000 行)。
单元测试。使用 Google Test用于测试(我使用 vcpkg 安装)。
// Google Test integrates into VS2017 if ReSharper is installed.
#include "gtest/gtest.h" // Can install using vcpkg
// In main(), call:
// ::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
TEST(Strings, Split)
{
{
const std::string str = "A,B,C";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 3);
EXPECT_TRUE(tokens[0] == "A");
EXPECT_TRUE(tokens[1] == "B");
EXPECT_TRUE(tokens[2] == "C");
}
{
const std::string str = ",B,C";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 3);
EXPECT_TRUE(tokens[0] == "");
EXPECT_TRUE(tokens[1] == "B");
EXPECT_TRUE(tokens[2] == "C");
}
{
const std::string str = "A,B,";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 3);
EXPECT_TRUE(tokens[0] == "A");
EXPECT_TRUE(tokens[1] == "B");
EXPECT_TRUE(tokens[2] == "");
}
{
const std::string str = "";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 1);
EXPECT_TRUE(tokens[0] == "");
}
{
const std::string str = "A";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 1);
EXPECT_TRUE(tokens[0] == "A");
}
{
const std::string str = ",";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 2);
EXPECT_TRUE(tokens[0] == "");
EXPECT_TRUE(tokens[1] == "");
}
{
const std::string str = ",,";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 3);
EXPECT_TRUE(tokens[0] == "");
EXPECT_TRUE(tokens[1] == "");
EXPECT_TRUE(tokens[2] == "");
}
{
const std::string str = "A,";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 2);
EXPECT_TRUE(tokens[0] == "A");
EXPECT_TRUE(tokens[1] == "");
}
{
const std::string str = ",B";
auto tokens = Split(str, ',');
EXPECT_TRUE(tokens.size() == 2);
EXPECT_TRUE(tokens[0] == "");
EXPECT_TRUE(tokens[1] == "B");
}
}
关于c++ - 惯用地拆分 string_view,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48012539/
假设我们有一个 string_view 和另一个 string_view,它是第一个 string_view 的子集: using namespace std; // just to shorten
我正在使用一个使用 boost::string_view 的 boost 库。但是,我想在我的代码中使用 std::string_view。 问:在这两者之间进行转换的最佳方式是什么? 目前我正在使用
std::string_view::remove_prefix() 和 std::string_view::remove_suffix() 都是 c 中的 constexpr 成员函数++17;但是,
我已经从 Bjarne Stroustrup 的 A Tour of C++ 中复制代码来测试字符串 View ,但我不断收到错误: error: no matching function for c
除了 std::string_view 方法之外,std::string_view 是否比 char* 有任何优势? 如果没有使用 string_view 的方法,是否有任何理由将 char* 重构为
我有这个循环: for (const std::string_view resource : resources) { ... } 由此资源被定义为 inline const std::string_
我有这个循环: for (const std::string_view resource : resources) { ... } 由此资源被定义为 inline const std::string_
而一个 span可以从一个范围构建,一个 string_view不能从一系列字符构造。 因此,例如,需要以下代码: // assume chars_span is a span of chars st
void Foo1(string_view view) { ... } string str = "one two three"; Foo1("one two three"); // Implicit
我有一个字符串,其中包含用 , 字符分隔的数字序列。为了将序列中的值读入数组,我创建了以下 GCC 10 拒绝编译的代码: #include #include #include #include
我在使用 Boost 1.70 时发现了一个相当令人费解的问题,有时 boost::string_view 似乎指向另一个字符串。 这是创建 boost::string_view 的函数调用,如下所示
在以下场景中使用 std::string_view: struct A : public std::exception{ A (const char* c) : v_(c){} con
我正在尝试尽可能多地使用 std::string_view 来包装 C 字符串,但是,每当我正在包装的 C 字符串被动态分配时,我都依赖于此图案: char *cs = get_c_string();
我读了The most elegant way to iterate the words of a string并享受答案的简洁性。现在我想对 string_view 做同样的事情。问题是,strin
我有以下代码: #include class Foo { public: Foo(std::string_view) {} }; 当我这样做时,一切都可以正常编译(使用 clang v8,C
根据一篇文章(here 和 there),这段代码是一个错误的免费示例: #include #include #include int main() { std::string s = "H
string_view 是 C++ 库基础 TS(N3921) 中的一项提议功能,添加到 C++17 据我所知,它是一种代表某种字符串“概念”的类型,它是任何类型的容器的 View ,可以将可视内容存
考虑以下代码: #include #include int main() { std::optional opt { "abc" }; std::cout { std::stri
在 std::string_view 上匹配正则表达式工作正常。但是当我返回匹配的子字符串时,它们会因为某种原因而消失。 std::string_view 参数在函数作用域结束时被销毁,但它指向的内存
This reference指出第二个示例产生了一个悬空指针。如何在第二个表达式中创建悬挂指针而不是在第一个表达式中? std::string_view good("a string literal"
我是一名优秀的程序员,十分优秀!