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

相关推荐
冷眼看人间恩怨25 分钟前
【Qt笔记】QDockWidget控件详解
c++·笔记·qt·qdockwidget
红龙创客35 分钟前
某狐畅游24校招-C++开发岗笔试(单选题)
开发语言·c++
Lenyiin37 分钟前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
yuanbenshidiaos2 小时前
c++---------数据类型
java·jvm·c++
十年一梦实验室3 小时前
【C++】sophus : sim_details.hpp 实现了矩阵函数 W、其导数,以及其逆 (十七)
开发语言·c++·线性代数·矩阵
taoyong0013 小时前
代码随想录算法训练营第十一天-239.滑动窗口最大值
c++·算法
这是我583 小时前
C++打小怪游戏
c++·其他·游戏·visual studio·小怪·大型·怪物
fpcc3 小时前
跟我学c++中级篇——C++中的缓存利用
c++·缓存
呆萌很3 小时前
C++ 集合 list 使用
c++
诚丞成4 小时前
计算世界之安生:C++继承的文水和智慧(上)
开发语言·c++