You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现支持缩进感知的C++原始字符串字面量?

编译时实现缩进感知的原始字符串字面量(C17/C20)

针对你需要的编译时处理缩进感知原始字符串的需求,以下是两种适配C17和C20的方案:

C++17 constexpr编译时处理方案

利用C++17的constexpr特性,编写编译时函数计算最小缩进量并去除多余空格,完全在编译期完成处理,无运行时开销。

#include <string_view>
#include <algorithm>
#include <array>

template <size_t N>
constexpr auto dedent(const char (&str)[N]) {
    // 跳过开头的空行
    size_t start = 0;
    while (start < N && (str[start] == '\n' || str[start] == '\r')) {
        ++start;
    }

    // 计算所有非空行的最小缩进量
    size_t min_indent = static_cast<size_t>(-1);
    size_t pos = start;
    while (pos < N) {
        if (str[pos] == '\n') {
            ++pos;
            size_t indent = 0;
            while (pos < N && str[pos] == ' ') {
                ++indent;
                ++pos;
            }
            // 仅统计非空行的缩进
            if (pos < N && str[pos] != '\n' && str[pos] != '\r') {
                min_indent = std::min(min_indent, indent);
            }
        } else {
            ++pos;
        }
    }

    // 处理无缩进的情况(如单行字符串)
    if (min_indent == static_cast<size_t>(-1)) {
        min_indent = 0;
    }

    // 构建去缩进后的结果字符串
    std::array<char, N> result{};
    size_t out_pos = 0;
    pos = start;
    bool in_indent = false;
    size_t current_indent = 0;

    while (pos < N) {
        if (str[pos] == '\n') {
            result[out_pos++] = str[pos++];
            in_indent = true;
            current_indent = 0;
        } else if (in_indent && str[pos] == ' ') {
            if (current_indent < min_indent) {
                // 跳过最小缩进范围内的空格
                ++current_indent;
                ++pos;
            } else {
                // 保留超出最小缩进的空格
                result[out_pos++] = str[pos++];
                in_indent = false;
            }
        } else {
            in_indent = false;
            result[out_pos++] = str[pos++];
        }
    }

    // 去除末尾多余的换行和空格
    while (out_pos > 0 && (result[out_pos-1] == '\n' || result[out_pos-1] == ' ')) {
        --out_pos;
    }
    result[out_pos] = '\0';

    return std::string_view(result.data(), out_pos);
}

// 使用示例
#include <iostream>
int main() {
    constexpr auto str = dedent(R"(
       Hello
           World
    )");
    std::cout << "ref\n" << str;
    return 0;
}

C++20 consteval增强方案

C++20的consteval关键字可以强制函数完全在编译期执行,避免任何运行时 fallback 的可能,同时结合std::span简化代码逻辑:

#include <string_view>
#include <span>
#include <algorithm>
#include <array>

consteval std::string_view dedent(std::string_view str) {
    // 跳过开头的空行
    auto start = str.find_first_not_of("\n\r");
    if (start == std::string_view::npos) {
        return "";
    }
    str = str.substr(start);

    // 计算最小缩进量
    size_t min_indent = static_cast<size_t>(-1);
    size_t pos = 0;
    while (pos < str.size()) {
        if (str[pos] == '\n') {
            ++pos;
            size_t indent = 0;
            while (pos < str.size() && str[pos] == ' ') {
                ++indent;
                ++pos;
            }
            if (pos < str.size() && str[pos] != '\n' && str[pos] != '\r') {
                min_indent = std::min(min_indent, indent);
            }
        } else {
            ++pos;
        }
    }

    if (min_indent == static_cast<size_t>(-1)) {
        min_indent = 0;
    }

    // 构建结果缓冲区(可根据实际需求调整大小)
    std::array<char, 1024> buf{};
    size_t out_pos = 0;
    pos = 0;
    bool in_indent = false;
    size_t current_indent = 0;

    while (pos < str.size() && out_pos < buf.size() - 1) {
        if (str[pos] == '\n') {
            buf[out_pos++] = str[pos++];
            in_indent = true;
            current_indent = 0;
        } else if (in_indent && str[pos] == ' ') {
            if (current_indent < min_indent) {
                ++current_indent;
                ++pos;
            } else {
                buf[out_pos++] = str[pos++];
                in_indent = false;
            }
        } else {
            in_indent = false;
            buf[out_pos++] = str[pos++];
        }
    }

    // 去除末尾空白字符
    while (out_pos > 0 && (buf[out_pos-1] == '\n' || buf[out_pos-1] == ' ')) {
        --out_pos;
    }
    buf[out_pos] = '\0';

    return std::string_view(buf.data(), out_pos);
}

// 使用示例
#include <iostream>
int main() {
    constexpr auto str = dedent(R"(
       Hello
           World
    )");
    std::cout << "ref\n" << str;
    return 0;
}

额外说明

  • 上述方案默认仅处理空格缩进,若需要支持制表符,可以在代码中添加制表符转空格的逻辑后再计算最小缩进。
  • 缓冲区大小可根据实际使用场景调整,若需处理超长字符串,C++20支持constexpr std::string,可以替换std::array实现动态大小的编译期字符串构造。

内容的提问来源于stack exchange,提问作者tejas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 11:10:13