[原创](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种情况: 存在空白符 与 不存在空白符, 对输入流的操作是截然不同的. 希望这篇文章对大家有所帮助.

相关推荐
AAA.建材批发刘哥4 分钟前
02--C++ 类和对象上篇
开发语言·c++
橘颂TA11 分钟前
【Linux】从 “抢资源” 到 “优雅控场”:Linux 互斥锁的原理与 C++ RAII 封装实战(Ⅰ)
linux·运维·服务器·c++·算法
枫叶丹426 分钟前
【Qt开发】Qt系统(三)->事件过滤器
java·c语言·开发语言·数据库·c++·qt
坐怀不乱杯魂1 小时前
Linux - 缓存利用率
linux·c++·缓存
leiming61 小时前
c++ for_each算法
开发语言·c++·算法
_OP_CHEN1 小时前
【算法基础篇】(四十一)数论之约数问题终极攻略:从求单个约数到批量统计
c++·算法·蓝桥杯·数论·约数·算法竞赛·acm/icpc
草莓熊Lotso1 小时前
从冯诺依曼到操作系统:打通 Linux 底层核心逻辑
linux·服务器·c++·人工智能·后端·系统架构·系统安全
yuanmenghao1 小时前
自动驾驶中间件iceoryx - 内存与 Chunk 管理(一)
c++·vscode·算法·链表·中间件·自动驾驶·柔性数组
橘颂TA1 小时前
【剑斩OFFER】算法的暴力美学——面试题 01.02 :判定是否互为字符串重排
c++·算法·leetcode·职场和发展·结构与算法
HABuo1 小时前
【Linux进程(二)】操作系统&Linux的进程状态深入剖析
linux·运维·服务器·c语言·c++·ubuntu·centos