std::transform方法
std::transform 是 C++ 标准库算法中的一个非常有用的函数,它定义在头文件 中。这个函数用于将给定范围内的每个元素按照指定的操作进行转换,并将转换结果存储在另一个位置(可以是原始范围的另一个容器,或者完全不同的位置)。std::transform 提供了一个灵活的方式来对容器中的元素进行批量处理,而无需显式地遍历每个元素。
函数原型
std::transform 有几个重载版本,但最基本的原型如下:
cpp
template< class InputIt, class OutputIt, class UnaryOperation >
OutputIt transform( InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op );
template< class InputIt1, class InputIt2, class OutputIt, class BinaryOperation >
OutputIt transform( InputIt1 first1, InputIt1 last1, InputIt2 first2,
OutputIt d_first, BinaryOperation binary_op );
Unary Operation 版本:接受一个输入范围([first1, last1)),一个输出迭代器(d_first),和一个一元操作函数(unary_op)。对于输入范围内的每个元素,unary_op 都会被应用,并且结果会被写入到由 d_first 指定的输出位置。
Binary Operation 版本:类似于一元操作版本,但它接受两个输入范围([first1, last1) 和 [first2, first2 + (last1 - first1))),这两个范围必须等长。对于每对元素(来自两个输入范围),都会应用一个二元操作函数(binary_op),并将结果写入到输出位置。
示例
一元操作示例:将 std::vector 中的每个元素乘以 2。
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::vector<int> result(vec.size());
std::transform(vec.begin(), vec.end(), result.begin(),
[](int i) { return i * 2; });
for (int num : result) {
std::cout << num << ' ';
}
// 输出: 2 4 6 8 10
}
二元操作示例:将两个 std::vector 中对应位置上的元素相加。
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> vec1 = {1, 2, 3, 4, 5};
std::vector<int> vec2 = {5, 4, 3, 2, 1};
std::vector<int> result(vec1.size());
std::transform(vec1.begin(), vec1.end(), vec2.begin(), result.begin(),
[](int a, int b) { return a + b; });
for (int num : result) {
std::cout << num << ' ';
}
// 输出: 6 6 6 6 6
}
示例3:std::transform(fileExt.begin(), fileExt.end(),fileExt.begin(), ::toupper);
在 C++ 中,使用 std::transform 来对容器(如 std::string 或其他支持随机访问迭代器的容器)的元素进行转换时,需要注意几个关键点。首先,对于 std::string 来说,虽然它支持随机访问迭代器,但直接在其上原地(in-place)修改(即输出迭代器与输入迭代器相同)可能会导致未定义行为,因为 std::transform 在修改元素时可能会覆盖尚未处理的元素。
对于你的代码片段:
cpp
std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), ::toupper);
这里有几个问题:
原地修改:如上所述,直接在 std::string 上原地修改可能会不安全,因为 std::transform 在遍历元素时可能会覆盖当前迭代器之后的元素,而迭代器自身也可能因为容器的改变而变得无效。
::toupper 函数的适用性:::toupper 函数需要一个 int 类型的参数,并返回一个 int 类型的值。当用于字符时,它期望输入是 EOF 或无符号字符(在 unsigned char 范围内)的 int 表示。对于 std::string 中的 char 类型,如果 char 是有符号的(这在某些平台上是这样),直接传递 char 到 ::toupper 可能会导致未定义行为,因为负值的 char 会被解释为扩展的 ASCII 码或其他非预期的值。
为了安全地在 std::string 上应用 std::transform 来转换字符到大写,你可以使用以下方法之一:
方法 1:使用临时字符串
创建一个新的 std::string 来存储结果,然后可以将结果赋值回原字符串(如果需要)。
cpp
std::string fileExt = "example.txt";
std::string upperExt(fileExt.size(), '\0'); // 初始化大小,用 '\0' 填充
std::transform(fileExt.begin(), fileExt.end(), upperExt.begin(),
[](unsigned char c) { return std::toupper(static_cast<unsigned char>(c)); });
fileExt = upperExt; // 如果需要,将结果赋值回原字符串
注意这里使用了 unsigned char 来确保传递给 std::toupper 的是无符号值。
方法 2:使用标准库中的其他函数(如果适用)
对于 std::string,如果你只是想将所有字符转换为大写,可以使用 std::for_each 配合 std::toupper(但要注意类型转换问题),但更简单的方法是使用 C++17 引入的 std::string 的成员函数 std::transform(注意这不是算法 std::transform):
cpp
#include <algorithm>
#include <cctype> // 对于 std::toupper
#include <string>
std::string fileExt = "example.txt";
std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(),
[](unsigned char c) { return std::toupper(static_cast<unsigned char>(c)); });
这里直接在原字符串上操作是安全的,因为 std::string::transform 成员函数是为这种场景设计的。然而,注意这里仍然需要确保传递给 std::toupper 的是无符号值。
注意
确保你的编译器和 C++ 标准库支持你正在使用的特性(如 C++17 的 std::string::transform)。如果你使用的是较旧的编译器或标准库,你可能需要坚持使用第一种方法或寻找其他替代方案。
string方法
unsigned int found = fileI.find_last_of(“.”);
查找最后一个“.”所在的位置
std::string fileExt = fileI.substr(found+1);
截取到found+1位置
标签:std,begin,string,transform,c++,fileExt,include,方法 From: https://blog.csdn.net/weixin_45751713/article/details/140225364