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

相关推荐
博客180014 小时前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
郝学胜_神的一滴16 小时前
CMake 026:属性体系精讲、四大作用域全解 & 实战代码落地
c++·cmake
众少成多积小致巨1 天前
JNI (Java Native Interface) 技术手册中文参考指南
android·java·c++
clint4565 天前
C++进阶(1)——前景提要
c++
夜悊6 天前
C++代码示例:进制数简单生成工具
c++
郝学胜_神的一滴6 天前
CMake 021: IF 条件判据详诠
c++·cmake
_wyt0016 天前
洛谷 B3930 [GESP202312 五级] 烹饪问题 题解
c++·gesp
玖玥拾6 天前
C/C++ 数据结构(七)栈、容器适配器
c语言·数据结构·c++··容器适配器
один but you6 天前
constexpr函数
c++
凡人叶枫6 天前
Effective C++ 条款41:了解隐式接口和编译期多态
java·开发语言·c++·effective c++