Search code examples
c++stringfilefstream

remove the last occurrence of character in string in file c++


I have a function which reads each line in a file (using ifstream), modifies that line and then writes to a file with many "{key,value}," (by using fstream), I need to remove the last comma in that file, but after searching, I still have no idea to do this.

Does anyone have any suggestion please ?

current output file:

//bein file
std::map <std::string, std::string> my_map = 
...
    {key,value},
    {key,value},
    {last_key,last_value},
};
//some comment

expected output(remove the last comma):

//bein file
std::map <std::string, std::string> my_map = 
...
    {key,value},
    {key,value},
    {last_key,last_value}
};
//some comment

my code is here:

#include <windows.h>
#include <queue>
#include <string>
#include <iostream>
#include <regex> 
#include <fstream>
#include <iterator> 
#include <stdio.h>

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



std::string write_cpp_file(std::string path, std::string line, std::string file_name)
{
    std::string result = "output\\values.cpp";
    if  (path.find("values-en-rGB") != std::string::npos) {
        std::fstream file("./output/result.cpp", std::ios::out | std::ios::app);
        if  (file)
        {
            file << line << std::endl;
            file.close();
        }
    }
    return result;
}

void analyze_file(std::string const &path, WIN32_FIND_DATA const &file) { 
    //std::cout << "path: " << path << "\n";
    //std::cout << "file name: " << file.cFileName << "\n";
    std::string file_name = path+file.cFileName;
    std::cout << "processing file: " << file_name << "\n";

    std::ifstream empSalariesOld(file_name);
    //ofstream empSalariesNew("EmpSalariesNew.txt");

    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 = "\"},";

        std::string result;

        while (getline(empSalariesOld, line))
        {
            if (!std::regex_match(line, open_comment) && 
                !std::regex_match(line, close_comment) && 
                std::regex_match(line, string_tag) ) 
            {
                result = std::regex_replace(line, find1, replace1);
                result = std::regex_replace(result, find2, replace2);
                result = std::regex_replace(result, find3, replace3);
                std::string cpp_file = write_cpp_file(path, result, file_name);
            } 
        }
    }

    empSalariesOld.close();
    //empSalariesNew.close();

}

//process each file in folder/subfolder
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;
}

Solution

  • You can do the following do a first write to file without any , outside the loop. Then for the others write inside the loop you print the , at the beginning of the line:

        if (getline(empSalariesOld, line))
        {
             if (!std::regex_match(line, open_comment) && 
                !std::regex_match(line, close_comment) && 
                std::regex_match(line, string_tag) ) 
            {
                result = std::regex_replace(line, find1, replace1);
                result = std::regex_replace(result, find2, replace2);
                result = std::regex_replace(result, find3, replace3);
                //remove the first char which is the comma
                result = result.substr(1, result.size()-1)
                std::string cpp_file = write_cpp_file(path, result, file_name);
            } 
        }
    
        while (getline(empSalariesOld, line))
        {
            if (!std::regex_match(line, open_comment) && 
                !std::regex_match(line, close_comment) && 
                std::regex_match(line, string_tag) ) 
            {
                result = std::regex_replace(line, find1, replace1);
                result = std::regex_replace(result, find2, replace2);
                result = std::regex_replace(result, find3, replace3);
                std::string cpp_file = write_cpp_file(path, result, file_name);
            } 
        }
    

    I am guessing you are putting the comma in replace3. You can:

        std::string replace1 = ",\n{"; \\put the comma at beginning of line then got to the next line
        ...
        std::string replace3 = "\"}"
    

    And since you are putting the new line in replace1 you should remove it from new file:

     file << line;