C++20: 像Python一样逐行读取文本文件并支持切片操作

概要

逐行读取文本文件,并提取其中连续的几行,这对于 Python 来说是小菜一碟。 C++ 则很笨拙, 语言不自带这些。 这次我来拯救 C++ boys & girls, 在 C++20 环境下,山寨一个 Python 下的逐行读文本文件、支持 slice 操作的代码,包含基础设施的实现和调用实例代码。

问题是什么?

data.csv

csv 复制代码
0,11,336,23,370
0,5,370,16,404
1,370,404,410,419
1,435,376,444,402
2,249,409,280,446
2,579,441,632,472
python 复制代码
filepath = "data.csv"

with open(filepath, "r") as f:
    # print('type(f):', type(f))
    lines = f.readlines()
    for line in lines[1:3]:
        print(line.strip())

    print('---')

    for line in lines[3:]:
        print(line.strip())

对于上述文本文件和 Python 代码, 用 C++20 实现一个等效的代码:

  • 基础设施代码,不限制行数
  • 调用代码,尽可能和 Python 代码长得像, 比如都是10行以内,切片操作也尽可能的直观

逐行读取文件 - C++ 实现

这个功能比较好实现,返回 vector 就可以了。文件读取使用的是 std::fstream,基于 RAII 思想创建和释放。对于每一行文本的读取,使用 std::getline() 来完成。

cpp 复制代码
#include <fstream>
#include <vector>
#include <string>

class TextIOWrapper
{
public:
    TextIOWrapper(const std::string& filepath)
    {
        ifs.open(filepath);
    }

    ~TextIOWrapper()
    {
        ifs.close();
    }

    std::string readline()
    {
        std::string line;
        std::getline(ifs, line);
        return line;
    }

    std::vector<std::string> readlines()
    {
        std::vector<std::string> lines;
        std::string line;
        while (std::getline(ifs, line))
        {
            lines.emplace_back(line);
        }
        return lines;
    }

private:
    std::ifstream ifs;
};

切片操作 - 基于C++20的实现

对于切片操作: Python 中的 [start:end], C++ 里并不支持; std::ranges 使用的管道操作符 |,可以用作这个目的。

std::ranges 笨拙的地方在于,只提供了 std::ranges::views::drop(start)std::ranges::views::take(end-start) 这样的基础操作,从来不考虑调用者用起来多费劲。。。那么我们自行封装一个:

cpp 复制代码
namespace views {
    auto slice(size_t start, size_t end) {
        return std::ranges::views::drop(start) | std::ranges::views::take(end - start);
    }
    auto slice(size_t start) {
        return std::ranges::views::drop(start);
    }
}

调用代码 - C++

cpp 复制代码
#include <iostream>

int main()
{
    const std::string filepath = "data.csv";
    TextIOWrapper fin(filepath);

    auto lines = fin.readlines();

    for (auto line : lines | views::slice(1, 3))
    {
        std::cout << line << std::endl;
    }

    printf("---\n");

    for (auto line : lines | views::slice(3))
    {
        std::cout << line << std::endl;
    }

    return 0;
}

完整代码

https://github.com/zchrissirhcz/clumsy/commit/9273ccaf50c31a5b0c2190713dd696c7d0d200f4

总结

本文从简洁的 Python 读取文本文件和切片的代码出发,以相同简洁的调用代码为目标,使用常规的 C++ 封装方式实现了返回文件所有行或单独一行的操作;然后基于 C++20 的 std::ranges 实现了类似 Python 中的切片操作, 并给出了示例代码来展示正确性。

参考

https://stackoverflow.com/questions/50549611/slicing-a-vector-in-c

相关推荐
测试员周周5 小时前
【AI测试智能体】为什么传统测试方法对智能体失效?
开发语言·人工智能·python·功能测试·测试工具·单元测试·测试用例
dfdfadffa6 小时前
如何用模块化方案组织一个可扩展的前端组件库项目
jvm·数据库·python
2301_812539676 小时前
SQL中如何高效实现分组数据的批量更新_利用窗口函数与JOIN
jvm·数据库·python
RSTJ_16256 小时前
PYTHON+AI LLM DAY THREETY-NINE
开发语言·人工智能·python
2501_901200536 小时前
如何实现SQL存储过程存储过程参数标准化_统一命名规范
jvm·数据库·python
运气好好的6 小时前
Golang怎么用embed嵌入SQL文件_Golang如何将SQL迁移文件嵌入Go程序统一管理【技巧】
jvm·数据库·python
AC赳赳老秦7 小时前
政企内网落地:OpenClaw 离线环境深度适配方案,无外网场景下本地化模型对接与全功能使用
java·大数据·运维·python·自动化·deepseek·openclaw
星越华夏7 小时前
python 将相对路径变成绝对路径
python
l1t7 小时前
mingw和Linux中的gcc和llvm编译器编译的pocketpy执行同一个python脚本的不同效果
linux·运维·python
砚底藏山河7 小时前
股票数据API接口:如何获取股票历历史分时KDJ数据
java·python·maven