Skip to content

JSON Repair — C++ source

Fix broken JSON - trailing commas, single quotes, unquoted keys, comments, Python constants, BOM and truncated documents - and get clean pretty-printed JSON plus a list of every repair applied. Runs entirely in your browser.

This is the C++ implementation — the same logic the interactive tool runs, in a shareable, citable form.

// JSON repair pipeline — C++ (C++20) port of the json-repair tool: excerpt
// of the 7-pass pipeline in typescript.ts / go.go (quote, Python-constant,
// trailing comma, truncation repair passes). Regex passes use std::regex; an
// unterminated single-quoted string is left for the truncation pass's scan.
#include <cctype>
#include <iostream>
#include <regex>
#include <string>
#include <vector>
namespace json_repair {
// Single-quoted strings -> double-quoted: escape inner double quotes,
// collapse \' to ', keep every other escape; double-quoted copy verbatim.
inline std::string single_to_double_quotes(const std::string &text) {
    static const std::regex sq("'(?:[^'\\\\]|\\\\.)*'");
    std::string out, body;
    size_t last = 0;
    for (std::sregex_iterator it(text.begin(), text.end(), sq), end; it != end; ++it) {
        body = it->str().substr(1, it->length() - 2);
        body = std::regex_replace(body, std::regex("\\\\'"), "'");
        body = std::regex_replace(body, std::regex("\""), "\\\"");
        out += text.substr(last, it->position() - last) + "\"" + body + "\"";
        last = it->position() + it->length();
    }
    return out + text.substr(last);
}
// Transform only the segments outside double-quoted strings.
template <typename F>
inline std::string outside_strings(const std::string &text, F map) {
    static const std::regex strings("\"(?:[^\"\\\\]|\\\\.)*\"");
    std::string out;
    size_t last = 0;
    for (std::sregex_iterator it(text.begin(), text.end(), strings), end; it != end; ++it) {
        out += map(text.substr(last, it->position() - last)) + it->str();
        last = it->position() + it->length();
    }
    return out + map(text.substr(last));
}
inline std::string fix_python_constants(const std::string &text) {
    return outside_strings(text, [](const std::string &s) {
        const std::regex t("\\bTrue\\b"), f("\\bFalse\\b"), n("\\bNone\\b");
        return std::regex_replace(std::regex_replace(std::regex_replace(s, t, "true"), f, "false"), n, "null");
    });
}
// Commas followed only by whitespace and a closing } or ] — dropped.
inline std::string strip_trailing_commas(const std::string &text) {
    return outside_strings(text, [](const std::string &s) {
        return std::regex_replace(s, std::regex(",(\\s*[}\\]])"), "$1"); });
}
// Recover truncated JSON: close an unterminated string, drop a dangling
// comma, give a dangling colon a null value, then close open brackets.
inline std::string close_truncated(const std::string &text) {
    std::vector<char> stack;
    bool in_string = false;
    for (size_t i = 0; i < text.size(); i++) {
        char c = text[i];
        if (in_string) {
            if (c == '\\' && i + 1 < text.size()) i++; // skip the escaped char
            else if (c == '"') in_string = false;
        } else if (c == '"') in_string = true;
        else if (c == '{' || c == '[') stack.push_back(c);
        else if (c == '}' || c == ']') { if (!stack.empty()) stack.pop_back(); }
    }
    std::string out = in_string ? text + "\"" : text;
    while (!out.empty() && (out.back() == ',' || std::isspace(static_cast<unsigned char>(out.back())))) out.pop_back();
    if (!out.empty() && out.back() == ':') out += " null";
    for (auto it = stack.rbegin(); it != stack.rend(); ++it) out += *it == '{' ? '}' : ']';
    return out;
}
// The canonical repair() also reports which passes fired and pretty-prints.
inline std::string repair(const std::string &text) {
    std::string work = text;
    for (auto pass : {single_to_double_quotes, fix_python_constants, strip_trailing_commas, close_truncated}) work = pass(work);
    return work;
}
} // namespace json_repair
// {"name": "Ada", admin: true, tags: ["x", "y"]}
int main() {
    std::cout << json_repair::repair("{'name': 'Ada', admin: True, tags: ['x', 'y',],") << "\n";
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →