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

C++技术问询:如何移除输出文件中最后一个键值对后的逗号?

Fixing the Trailing Comma in Your Map Initialization Output

Hey there! Let's sort out that annoying trailing comma at the end of your map entries. The core issue right now is that you're writing lines one by one to the file without knowing which one will be the last. Here's a straightforward, reliable fix based on your existing code:

Approach: Collect All Lines First, Then Write With Adjustment

Instead of appending each line to the file immediately, gather all the generated map entry lines in a list first. Once you have all lines, you can easily modify the last one to remove the trailing comma before writing everything to the file.

Modified Code

First, update your analyze_file function to collect lines and handle the trailing comma removal. You can also remove the separate write_cpp_file function since we'll handle writing directly here:

#include <windows.h>
#include <queue>
#include <string>
#include <iostream>
#include <regex>
#include <fstream>
#include <iterator>
#include <stdio.h>
#include <vector> // Add this header for std::vector

// I think MS's names for some things are obnoxious.
const HANDLE HNULL = INVALID_HANDLE_VALUE;
const int A_DIR = FILE_ATTRIBUTE_DIRECTORY;

void analyze_file(std::string const &path, WIN32_FIND_DATA const &file) {
    std::string file_name = path + file.cFileName;
    std::cout << "processing file: " << file_name << "\n";
    std::ifstream empSalariesOld(file_name);
    
    if (empSalariesOld) {
        std::string line;
        std::regex open_comment("(.*)(<!--)(.*)");
        std::regex close_comment("(.*)(-->)(.*)");
        std::regex string_tag("(.*)(<string name=)(.*)");
        std::regex find1("<string name=");
        std::string replace1 = "{";
        std::regex find2("\">");
        std::string replace2 = "\",\"";
        std::regex find3("</string>");
        std::string replace3 = "\"},";
        
        // Collect all valid generated lines
        std::vector<std::string> generated_lines;

        while (getline(empSalariesOld, line)) {
            // Keep your original filtering logic
            if (!std::regex_match(line, open_comment) && !std::regex_match(line, close_comment) && std::regex_match(line, string_tag)) {
                std::string result = std::regex_replace(line, find1, replace1);
                result = std::regex_replace(result, find2, replace2);
                result = std::regex_replace(result, find3, replace3);
                
                // Only include lines from the target path (keep your original condition)
                if (path.find("values-en-rGB") != std::string::npos) {
                    generated_lines.push_back(result);
                }
            }
        }

        // Write the processed lines to file
        if (!generated_lines.empty()) {
            std::fstream output_file("./output/result.cpp", std::ios::out | std::ios::app);
            if (output_file) {
                for (size_t i = 0; i < generated_lines.size(); ++i) {
                    std::string current_line = generated_lines[i];
                    
                    // Remove trailing comma from the last line
                    if (i == generated_lines.size() - 1) {
                        if (!current_line.empty() && current_line.back() == ',') {
                            current_line.pop_back();
                        }
                    }
                    
                    output_file << current_line << std::endl;
                }
                output_file.close();
            }
        }
    }
    empSalariesOld.close();
}

// Rest of your functions (convert, create_output_folder, main) remain unchanged
void convert(std::string const &folder_name) {
    HANDLE finder; // for FindFirstFile
    WIN32_FIND_DATA file; // data about current file.
    std::priority_queue<std::string, std::vector<std::string>, std::greater<std::string> > dirs;
    dirs.push(folder_name); // start with passed directory
    do {
        std::string path = dirs.top();// retrieve directory to search
        dirs.pop();
        if (path[path.size()-1] != '\\') // normalize the name.
            path += "\\";
        std::string mask = path + "*"; // create mask for searching
        // traverse a directory. Search for sub-dirs separately, because we
        // don't want a mask to apply to directory names. "*.cpp" should find
        // "a\b.cpp", even though "a" doesn't match "*.cpp".
        //
        // First search for files:
        if (HNULL==(finder=FindFirstFile(mask.c_str(), &file))) continue;
        do {
            if (!(file.dwFileAttributes & A_DIR))
                analyze_file(path, file);
        } while (FindNextFile(finder, &file));
        FindClose(finder);
        // Then search for subdirectories:
        if (HNULL==(finder=FindFirstFile((path + "*").c_str(), &file))) continue;
        do {
            if ((file.dwFileAttributes & A_DIR) && (file.cFileName[0] != '.'))
                dirs.push(path + file.cFileName);
        } while (FindNextFile(finder, &file));
        FindClose(finder);
    } while (!dirs.empty());
}

void create_output_folder() {
    std::string command = "del /Q ";
    std::string path = "output\\*.cpp";
    system(command.append(path).c_str());
    CreateDirectory("output", NULL);
}

int main() {
    create_output_folder();
    convert("./Strings");
    std::cout << "finish convert" << "\n";
    return 0;
}

Key Changes Explained

  1. Added std::vector<std::string> generated_lines: This collects all the valid map entry lines instead of writing them immediately, so we can easily identify the last line.
  2. Moved the path check: The condition to only process values-en-rGB paths is now applied when adding lines to the collection, keeping your original filtering logic intact.
  3. Trailing comma removal: When writing lines, we check if we're on the last line. If so, we remove the trailing comma (only if it exists, to avoid errors from empty lines).
  4. Removed write_cpp_file: The file writing logic is integrated directly into analyze_file for simplicity and better control over the output.

Alternative Approaches (For Large Files)

If you're working with extremely large files where collecting all lines in memory isn't feasible, you could:

  • First pass: Count how many valid lines exist.
  • Second pass: Write all lines except the last one normally, then process and write the last line without the comma.

But for most use cases, the first approach is simpler and efficient enough.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:18:22