# i、文件流构建字符串

1
2
3
std::ostringstream oss;
oss << v.major << "." << v.minor << "." << v.patch;
string str = oss.str();

# i、文件流分割字符串:

1
2
3
4
5
6
7
//对于给定的以空格分割的字符串“A boy is standing outside”
string word;
stringstream out(str);
vector<string> words;
while(out >> word){
words.push_back(word);
}

关于流的更多细节,见:C++ 的流

# i、将整型 int 转化为字符串 string :

1
2
//利用函数 to_string,将 int 转化为 string
str += to_string(cur->val);

# i、将字符串 string 转化为整型 int:

1
2
3
stoi(str);
//or
atoi(str.c_str());

# i、string 取子串:

1
2
//注意第二个参数指的是子串的长度,而不是子串尾部的位置
string cur = s.substr(vec[0], vec[1] - vec[0] + 1);

利用这个,我们可以灵活组织新的字符串而不影响原有字符串。场景举例:
当我们想要将某个字符串的后缀进行更换、但不希望影响原有字符串,则可以取子串后拼接:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <string>

int main() {
std::string encryptedFile = "xxx.bin";

// 创建一个新的字符串,替换 ".bin" 为 ".txt"
std::string decryptedFile = encryptedFile.substr(0, encryptedFile.length() - 4) + ".txt";
// 输出修改后的文件名
std::cout << decryptedFile << std::endl;
return 0;
}

# i、string 查找子串:

1
2
3
4
string str = "Hello, World!";
if (str.find(subStr) != std::string::npos) {
//xxx
}

# i、string 查找前后缀:

1
2
3
4
5
6
7
8
//比如:/home/pcai/how/DeptheyeSDK/PointCloud/3DToF/boards/DepthEyeDual/cameraPairing.conf
size_t lastSlashPos = exePath.rfind('/');
if(lastSlashPos != std::string::npos) {
std::string prefixPath = exePath.substr(0, lastSlashPos);
std::cout << "prefixPath = " << prefixPath << std::endl;
std::string postfixPath = exePath.substr(lastSlashPos + 1);
std::cout << "postfixPath = " << postfixPath << std::endl;
}

# i、string 删除元素:

1
2
3
4
5
string str = " hello world   ";
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
//这里删除所有 str 中所有的空格
//std::remove 的作用仅仅是把所有的空格移动到字符串末尾,并返回最终有效的尾部 pos
//erase 的作用则是删除从最终有效的末尾到实际末尾的所有空格

# i、C++ 延时

1
2
3
4
5
6
#include <iostream>
#include <thread>
#include <chrono>

std::this_thread::sleep_for(std::chrono::seconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(500));

# i、partial_sum 求前缀和:

1
2
3
4
#include <algorithm>
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::vector<int> prefixSum(numbers.size()+1);
std::partial_sum(numbers.begin(), numbers.end(), prefixSum.begin()+1);

# i、Ctrl C 中断函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <csignal>

void ST_HandleSig(int signal) { //处理 Ctrl C 中断
std::cout << "Received signal: " << signal << std::endl;
}

int main() {
std::signal(SIGINT, ST_HandleSig); //注册中断函数

while (true) {
// Your game loop or other code here
} return 0;
}

//============================不太方便的C语言版本================================//
// void ST_HandleSig(int signo)
// {
// if(signo == SIGINT)
// {
// printf("catch Ctrl + C, exit normally\n");
// g_bExit = true;
// }
// }

// int main() {
// //注册中断函数
// struct sigaction sigAction;
// sigAction.sa_handler = ST_HandleSig;
// sigemptyset(&sigAction.sa_mask);
// sigAction.sa_flags = 0;
// sigaction(SIGINT, &sigAction, NULL);

// while (true) {
// // Your game loop or other code here
// } return 0;
// }

# i、读取固定格式数据表

该语法糖可用于读写寄存器,利用 vector 和 tuple:

1
2
3
4
5
6
7
8
9
std::vector<std::tuple<int, int>> reg_table = {
{0x1006, 0x08},
{0x1007, 0x00},
{0x1040, 0x00},
};

for(auto item : reg_table) {
std::cout << std::get<0>(item) << ":" << std::get<1>(item) << std::endl;
}

这里当然也可以在 vector 内部嵌套使用 vector,形成二维数组,但没有 tuple 灵活:

对于这个特定的数据结构,使用 std::vector<std::vector<int>> 存储也是可以的,但使用 std::tuple 更能准确地反映每个元素包含三个不同类型的数据。在这种情况下,每个元素都包含一个地址(整数),一个值 1(整数),和一个值 2(整数)。使用 std::tuple 可以更清晰地表示这个数据结构的含义。

如果使用 std::vector<std::vector<int>> ,则需要确保每个内部 std::vector 都包含三个整数,并且在访问数据时需要小心确保每个内部 std::vector 的大小都是 3。这可能会导致代码更容易出错,并且不如 std::tuple 那样清晰。

综上所述,选择使用 std::tuple 可以提高代码的可读性和清晰度,以及更准确地表示每个元素的结构。

例如:

1
2
3
4
5
6
7
8
9
std::vector<std::tuple<int, char, int>> reg_table = {
{0x1006, 'a', 0x08},
{0x1007, 'g', 0x00},
{0x1040, 'h', 0x00},
};

for(auto item : reg_table) {
std::cout << std::get<0>(item) << ":" << std::get<1>(item) << ":" << std::get<2>(item) << std::endl;
}

对于这种情况,tuple 更方便灵活,可以使用不同的数据类型,而 vector 则会限制每个元素都归属于同一种类型。

对于 tuple 元素的访问,可以通过 get 函数(如上所示),也可以利用 C++17 的 结构化绑定 语法进行优化:

1
2
3
4
5
6
7
8
std::tuple<int, double, std::string> myTuple(42, 3.14, "Hello");

// 使用结构化绑定
auto [intValue, doubleValue, stringValue] = myTuple;

std::cout << "整数值: " << intValue << std::endl;
std::cout << "双精度值: " << doubleValue << std::endl;
std::cout << "字符串值: " << stringValue << std::endl;

于是前面的代码可以优化成:

1
2
3
4
5
6
7
8
9
10
std::vector<std::tuple<int, char, int>> reg_table = {
{0x1006, 'a', 0x08},
{0x1007, 'g', 0x00},
{0x1040, 'h', 0x00},
};

for(auto item : reg_table) {
auto [addr, ch, val] = item;
std::cout << addr << ":" << ch << ":" << val << std::endl;
}

# i、剥取文件名

1
2
3
4
5
6
7
8
9
10
11
12
13
std::string getFilename(const std::string inputFile) {
std::string fileName = inputFile;
size_t lastSlashPos = inputFile.rfind('/');
size_t lastBackslashPos = inputFile.rfind('\\');
size_t lastSeparatorPos = std::max((lastSlashPos == std::string::npos) ? 0 : lastSlashPos,
(lastBackslashPos == std::string::npos) ? 0 : lastBackslashPos);

if (lastSeparatorPos != 0) {
fileName = inputFile.substr(lastSeparatorPos + 1);
std::cout << "File Name: " << fileName << std::endl;
}
return fileName;
}

这里函数的输入是某个文件的路径,可能的形式为 /path/to/myfolder/file.txt../../file.binfile.txt ,该函数的作用则是剥取最后的文件名。(这里考虑了 \/ 两种文件分隔符形式,注意这里的 \\ 为转义)。

# i、获取可执行程序的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
auto getExePath = [](){
std::string exePath(100, ' ');
if (readlink("/proc/self/exe", const_cast<char*>(exePath.c_str()), exePath.size()) != -1) {
// std::cout << "Executable path: " << exePath << std::endl;
size_t lastSlashPos = exePath.rfind('/');
if(lastSlashPos != std::string::npos) {
std::string prefixPath = exePath.substr(0, lastSlashPos);
return prefixPath;
} else {
std::cout << "split prefixPath error" << std::endl;
return std::string();
}
} else {
std::cout << "getExePath error" << std::endl;
return std::string();
}
};

更新于

请我喝杯咖啡吧~

Rick 微信支付

微信支付

Rick 支付宝

支付宝