[原创](Modern C++)现代C++的输入流与“>>“的微妙关系 (包含字符流拆分技巧)

常用网名:猪头三

出生日期: 1981.XX.XX

QQ联系: 643439947

个人网站: 80x86汇编小站

编程生涯: 2001年~至今[共23年]

职业生涯: 21年

开发语言: C/C++、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python

开发工具: Visual Studio、Delphi、XCode、Eclipse、C++ Builder

技能种类: 逆向 驱动 磁盘 文件

研发领域: Windows应用软件安全/Windows系统内核安全/Windows系统磁盘数据安全/macOS应用软件安全

项目经历: 磁盘性能优化/文件系统数据恢复/文件信息采集/敏感文件监测跟踪/网络安全检测

[序言]

C++中, 输入流(如std::istringstream, std::wistringstream等)是用于从字符串或其他数据源提取数据的对象. ">>"操作符被称为提取运算符, 它可以与输入流一起使用, 从输入流中读取特定类型的值并存储到变量中.

[代码演示]

下面是一个示例代码片段, 展示了如何使用std::wistringstream从输入字符串提取多个字段.

cpp 复制代码
int main()
{
    // 需要按照空格符进行拆分字符串(有4个字段)
    std::wstring wstr_Demo = L"1 hello world 5.1";
    std::wistringstream class_wss(wstr_Demo);

    int     int_Value1;                    // 字段1
    std::wstring wstr_Value2, wstr_Value3; // 字段2 字段3
    double  double_Value4;                 // 字段4
    wchar_t whar_Delimiter;                // 分隔符

    // 提取字段1
    class_wss >> int_Value1;

    // ">>"操作符会忽略开头的空白符,直到遇到第一个非空白符为止。
    // 因此,在提取字段2和字段3时,">>"运算符会跳过中间的多个空格,只保留一个空格作为分隔符。
    class_wss >> wstr_Value2;
    class_wss >> wstr_Value3;

    // 提取字段4
    class_wss >> double_Value4;
}

通过多次使用">>"运算符, 可以依次提取所有的字段. 因为使用">>"运算符从输入流中提取数据时, 它会跳过开头的空白符(如空格、制表符、回车等)并读取下一个非空白符之后的数据, 读取完成之后, 如果遇到新的空白符, 就会停止读取. 此时输入流会自动移动到当前新的白符处. 如果要继续读取下一个字段数据, 那么只需要再次调用">>"运算符即可.

[利用流的工作原理优化代码写法]

使用">>"运算符可以方便地从输入流中连续不断地提取不同类型的值并将其存储到变量中, 因此,可以进一步简化代码:

cpp 复制代码
class_wss >> int_Value1 >> wstr_Value2 >> wstr_Value3 >> double_Value4;

这种写法被称为链式提取(chain extraction), 它利用了">>"运算符的返回值是输入流对象本身这一特性, 通过连续使用">>"运算符, 可以一次性地提取所有字段.

[处理无空白符的字符串]

如果字符串中没有空白符(例如"1:hello:world:5.1"), 此时使用">>"运算符将会失效, 在这种情况下, 可以使用std::getline()函数进行处理提取字段.

cpp 复制代码
int main()
{
    // 需要按照":"进行拆分字符串(有4个字段)
    std::wstring wstr_Demo = L"1:hello:world:5.1";
    std::wistringstream class_wss(wstr_Demo);

    // 通过std::getline来进行拆分
    std::wstring wstr_Value;
    std::vector<std::wstring> vector_Token;
    while (std::getline(class_wss, wstr_Value, L':'))
    {
        // 保存字段到vector容器
        vector_Token.push_back(wstr_Value);
    }
}

[高级方法: 使用std::setw()来控制流提取的宽度]

std::setw(n)是一个用来设置输出/输入流宽度的函数. 当表达式 out << std::setw(n) 或者 in >> std::setw(n)时, 它会将流out或者in的宽度参数精确地设置为n. 比如有一个字符串"1:10:ABCD:5.1", 为了提取"ABCD"这个字段, 可以用std::setw(4)来处理. (注意: 有些操作可能会重置宽度为零(例如,>>提取操作), 因此在进行多个操作时, 可能需要反复调用std::setw()来设置宽度) .

如下代码演示:

cpp 复制代码
int main()
{
    // 需要按照空格符进行拆分字符串(有4个字段)
    std::wstring wstr_Demo = L"1:10:ABCD:5.1";
    std::wistringstream class_wss(wstr_Demo);

    int     int_Value1, int_Value2; // 字段1 字段2
    std::wstring wstr_Value3;       // 字段3
    double  double_Value4;          // 字段4
    wchar_t whar_Delimiter;         // 分隔符

    // 提取字段1, 字段2, 字段3, 字段4 (注意在提取字段3之前, 用std::setw()函数设置了提取流的宽度.)
    class_wss >> int_Value1 >> whar_Delimiter >> int_Value2 >> whar_Delimiter >> std::setw(4) >> wstr_Value3 >> whar_Delimiter >> double_Value4;
 }

[总结]

通过上面的3个代码演示, 可以清楚的看到2种情况: 存在空白符 与 不存在空白符, 对输入流的操作是截然不同的. 希望这篇文章对大家有所帮助.

相关推荐
No0d1es4 小时前
电子学会青少年软件编程(C/C++)5级等级考试真题试卷(2024年6月)
c语言·c++·算法·青少年编程·电子学会·五级
DjangoJason6 小时前
C++ 仿RabbitMQ实现消息队列项目
开发语言·c++·rabbitmq
weixin_307779138 小时前
VS Code配置MinGW64编译GNU 科学库 (GSL)
开发语言·c++·vscode·算法
蒋星熠10 小时前
C++零拷贝网络编程实战:从理论到生产环境的性能优化之路
网络·c++·人工智能·深度学习·性能优化·系统架构
CHANG_THE_WORLD10 小时前
# C++ 中的 `string_view` 和 `span`:现代安全视图指南
开发语言·c++
雨落倾城夏未凉10 小时前
9.c++new申请二维数组
c++·后端
雨落倾城夏未凉10 小时前
8.被free回收的内存是立即返还给操作系统吗?为什么?
c++·后端
雨落倾城夏未凉10 小时前
6.new和malloc的区别
c++·后端
郝学胜-神的一滴11 小时前
深入理解QFlags:Qt中的位标志管理工具
开发语言·c++·qt·程序人生
INS_KF11 小时前
【C++知识杂记2】free和delete区别
c++·笔记·学习