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;
}
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;
Related
Here is the codeshare link of the exact input file: https://codeshare.io/5DBkgY
Ok, as you can see, there are 2 blank lines, (or tabs) between 8 and ROD. How would I skip that and continue with the program? I am trying to put each line into 3 vectors (so keys, lamp, and rod into one vector etc). Here is my code (but it does not skip the blank line).:
#include <string>
#include <iostream>
#include <sstream>
#include <vector>
#include <fstream>
using namespace std;
int main() {
ifstream objFile;
string inputName;
string outputName;
string header;
cout << "Enter image file name: ";
cin >> inputName;
objFile.open(inputName);
string name;
vector<string> name2;
string description;
vector<string> description2;
string initialLocation;
vector<string> initialLocation2;
string line;
if(objFile) {
while(!objFile.eof()){
getline(objFile, line);
name = line;
name2.push_back(name);
getline(objFile, line);
description = line;
description2.push_back(description);
getline(objFile, line);
initialLocation = line;
initialLocation2.push_back(initialLocation);
} else {
cout << "not working" << endl;
}
for (std::vector<string>::const_iterator i = name2.begin(); i != name2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = description2.begin(); i != description2.end(); ++i)
std::cout << *i << ' ';
for (std::vector<string>::const_iterator i = initialLocation2.begin(); i != initialLocation2.end(); ++i)
std::cout << *i << ' ';
#include <cstddef> // std::size_t
#include <cctype> // std::isspace()
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
bool is_empty(std::string const &str)
{
for (auto const &ch : str)
if (!std::isspace(static_cast<char unsigned>(ch)))
return false;
return true;
}
int main()
{
std::cout << "Enter image file name: ";
std::string filename;
std::getline(std::cin, filename); // at least on Windows paths containing whitespace
// are valid.
std::ifstream obj_file{ filename }; // define variables as close to where they're used
// as possible and use the ctors for initialization.
if (!obj_file.is_open()) { // *)
std::cerr << "Couldn't open \"" << filename << "\" for reading :(\n\n";
return EXIT_FAILURE;
}
std::vector<std::string> name;
std::vector<std::string> description;
std::vector<std::string> initial_location;
std::string line;
std::vector<std::string> *destinations[] = { &name, &description, &initial_location };
for (std::size_t i{}; std::getline(obj_file, line); ++i) {
if (is_empty(line)) { // if line only consists of whitespace
--i;
continue; // skip it.
}
destinations[i % std::size(destinations)]->push_back(line);
}
for (auto const &s : name)
std::cout << s << '\n';
for (auto const &s : description)
std::cout << s << '\n';
for (auto const &s : initial_location)
std::cout << s << '\n';
}
... initial_locations look like integers, though.
*) Better early exit if something bad happens. Instead of
if (obj_file) {
// do stuff
}
else {
// exit
}
-->
if(!obj_file)
// exit
// do stuff
makes your code easier to read and takes away one level of indentation for the most parts.
I am opening a csv file which contains entries in the form "key,value".
Task is to find a particular key and modify its corresponding value with another string. (key & value : both are strings).
int main()
{
std::fstream m_file;
m_file.open("input.csv", std::ios::in | std::ios::out);
m_file << "Star,Treks\n";
m_file << "Captain,America\n";
m_file << "Black,Cats\n";
m_file << "Ninja,Fighters\n";
std::string row;
std::string key = "Black";
std::string value = "Dreamers";
while (std::getline(m_file, row)) {
std::size_t pos = row.find(',');
std::string retrieved_key = row.substr(0, pos);
std::string retrieved_value = row.substr(pos + 1);
if (retrieved_key == key) {
std::size_t currentPos = m_file.tellg();
std::size_t row_length = row.length();
m_file.seekp(currentPos - row_length);
std::string newEntry = key + "," + value + "\n";
m_file << newEntry;
return 0;
}
}
getchar();
return 0;
}
This is the code I have written. But it does not work. It modifies the contents of the file as below :
Star,Treks
Captain,America
BlBlack,Dreamers
Fighters
You cannot modify files directly using seekg() and tellg() functions unless these have a fixed size format of the parts you want to change.
The usual way to do such things is to create an intermediary temp file to write your changes, and replace the original one with it after you're done.
Recipe:
#include <cstdlib>
#include <iostream>
#include <utility>
#include <string>
#include <fstream>
#include <vector>
#include <iterator>
#include <algorithm>
class pair : public std::pair<std::string, std::string>
{
public:
using std::pair<std::string, std::string>::pair;
bool operator==(pair const & rhs) const { return first == rhs.first; }
friend std::istream& operator>>(std::istream &is, pair &p)
{
std::getline(is, p.first, ',');
std::getline(is, p.second, '\n');
return is;
}
friend std::ostream& operator<<(std::ostream &os, pair const &p)
{
os << p.first << ',' << p.second << '\n';
return os;
}
};
int main()
{
char const *filename = "input.csv";
std::fstream file{ filename, std::ios::in };
if (!file) {
std::cerr << "Failed to open file \"" << filename << "\"!\n\n";
return EXIT_FAILURE;
}
std::vector<pair> data{
std::istream_iterator<pair>{ file },
std::istream_iterator<pair>{}
};
file.close();
auto it{ std::find(data.begin(), data.end(), pair{ "Black", "" }) };
if (it == data.end()) {
std::cerr << "Key not found!\n\n";
return EXIT_FAILURE;
}
it->second = "Dreamers";
file.open(filename, std::ios::out | std::ios::trunc);
if (!file) {
std::cerr << "Failed to open file \"" << filename << "\"!\n\n";
return EXIT_FAILURE;
}
for (auto const & entry : data)
file << entry;
}
Hello I'm having problem with dividing two doubles on C++, on a basic C++ it's working fine, for example
double DfirstNumber = 4.3;
double DsecondNumber = 2.0;
double DthirdNumber = DfirstNumber/DsecondNumber;
std::cout << DthirdNumber;
but not on the code below:
#include <iostream>
#include <fstream>
#include <string>
#include <Windows.h>
#include <regex>
std::string getLastLine(std::ifstream& in)
{
std::string line;
while (in >> std::ws && std::getline(in, line)) // skip empty lines
;
return line;
}
int main()
{
double DfirstNumber;
double DsecondNumber;
while(true){
std::ifstream file("C:\\Users\\Admin\\Documents\\myfile.txt");
if (file)
{
std::string line = getLastLine(file);
Sleep(1000);
try {
std::regex re("\\d*\\.\\d*");
std::sregex_iterator next(line.begin(), line.end(), re);
int i = 0;
std::string firstNumber;
std::string secondNumber;
while (i < 3) {
std::smatch match = *next;
if (i == 1) {
firstNumber = match.str();
DfirstNumber = std::stof(firstNumber);
}
if (i == 2) {
secondNumber = match.str();
DsecondNumber = std::stof(secondNumber);
}
next++;
i++;
}
}
catch (std::regex_error&) {
std::cout << "regex error";
}
double DthirdNumber = DsecondNumber) / DfirstNumber;
std::cout << DthirdNumber << std::endl;
}
else{
std::cout << "Can't Open the file.\n";
}
}
}
I'm getting every second a new line on myfile.txt so I had to check the last line of file, then using regular expression to get the desired datas and store them to C++ variables.
This is how myfile.txt looks
Hello Name Name0.00042Surname NameSurname Name0.00042$100.03
Hello Name Name0.00143Surname NameSurname Name0.00143$100.53
Hello Name Name0.00342Surname NameSurname Name0.00342$100.32
..............................................^1stNr^.^2ndNr^
... and another program just continues to extract lines like these every second!
Could anyone explain to me why is this happening, because if I'm trying to divide for example
DfirstNumber = 407.33
DsecondNumber = 0.015982
I'm not getting 25486.79764735327 but I'm getting 25489.8
I am trying to read every word a string. I want a string to go in and the first word to come out, then I'll process it, then the second, and so on. But the internet isn't helping me, I know it's probably right under my nose but I can't figure it out!
string lex(string filecontent) {
string t = filecontent;
getline(cin, t);
istringstream iss(t);
string word;
while (iss >> word) {
return word;
}
}
int main() {
string data = load_file(); // Returns a string of words
cout << data;
cout << lex(data);
getchar();
}
Right now this works... sort of it prints out a lot of random gibberish and crazy characters, The file I'm reading's output is ok I check this at cout << data and it is what I expect. Any ideas?
Here is the solution I think you are looking for:
int main() {
string data = load_file(); // Returns a string of words
istringstream iss(data);
while(iss)
{
string tok;
iss >> tok;
cout << "token: " << tok << endl;
//you can do what ever you want with the token here
}
}
Have a look at this, it should help you.
main.cpp
#include "stdafx.h"
#include "Utility.h"
int main() {
using namespace util;
std::string fileName( "sample.txt" );
if ( fileName.empty() ) {
std::cout << "Missing or invalid filename." << std::endl;
return RETURN_ERROR;
}
std::string line;
std::vector<std::string> results;
std::fstream fin;
// Try To Open File For Reading
fin.open( fileName.c_str(), std::ios_base::in );
if ( !fin.is_open() ) {
std::cout << "Can not open file(" << fileName << ") for reading." << std::endl;
return RETURN_ERROR;
}
// Read Line By Line To Get Data Contents Store Into String To Be Parsed
while ( !fin.eof() ) {
std::getline( fin, line );
// Parse Each Line Using Space Character As Delimiter
results = Utility::splitString( line, " " );
// Print The Results On Each Iteration Of This While Loop
// This Is Where You Would Parse The Data Or Store Results Into
// Class Objects, Variables Or Structures.
for ( unsigned u = 0; u < results.size(); u++ ) {
std::cout << results[u] << " ";
}
std::cout << std::endl;
}
// Close File Pointer
fin.close();
// Now Print The Full Vector Of Results - This Is To Show You That Each
// New Line Will Be Overwritten And That Only The Last Line Of The File Will
// Be Stored After The While Loop.
std::cout << "\n-------------------------------------\n";
for ( unsigned u = 0; u < results.size(); u++ ) {
std::cout << results[u] << " ";
}
Utility::pressAnyKeyToQuit();
return RETURN_OK;
} // main
sample.txt
Please help me parse this text file
It spans multiple lines of text
I would like to get each individual word
stdafx.h - Some of these include files may not be needed they are here for I have a larger solution that requires them.
#ifndef STDAFX_H
#define STDAFX_H
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <conio.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <vector>
#include <array>
#include <memory>
#include <queue>
#include <functional>
#include <algorithm>
// User Application Specific
// #include "ExceptionHandler.h" - One Of My Class Objects Not Used Here
namespace util {
enum ReturnCode {
RETURN_OK = 0,
RETURN_ERROR = 1,
}; // ReturnCode
extern const unsigned INVALID_UNSIGNED;
extern const unsigned INVALID_UNSIGNED_SHORT;
} // namespace util
#endif // STDAFX_H
stdafx.cpp
#include "stdafx.h"
namespace util {
const unsigned INVALID_UNSIGNED = static_cast<const unsigned>( -1 );
const unsigned INVALID_UNSIGNED_SHORT = static_cast<const unsigned short>( -1 );
} // namespace util
Utility.h
#ifndef UTILITY_H
#define UTILITY_H
namespace util {
class Utility {
public:
static void pressAnyKeyToQuit();
static std::string toUpper(const std::string& str);
static std::string toLower(const std::string& str);
static std::string trim(const std::string& str, const std::string elementsToTrim = " \t\n\r");
static unsigned convertToUnsigned(const std::string& str);
static int convertToInt(const std::string& str);
static float convertToFloat(const std::string& str);
static std::vector<std::string> splitString(const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty = true);
private:
Utility(); // Private - Not A Class Object
Utility(const Utility& c); // Not Implemented
Utility& operator=(const Utility& c); // Not Implemented
template<typename T>
static bool stringToValue(const std::string& str, T* pValue, unsigned uNumValues);
template<typename T>
static T getValue(const std::string& str, std::size_t& remainder);
}; // Utility
#include "Utility.inl"
} // namespace util
#endif // UTILITY_H
Utility.inl
// ----------------------------------------------------------------------------
// stringToValue()
template<typename T>
static bool Utility::stringToValue(const std::string& str, T* pValue, unsigned uNumValues) {
int numCommas = std::count(str.begin(), str.end(), ',');
if (numCommas != uNumValues - 1) {
return false;
}
std::size_t remainder;
pValue[0] = getValue<T>(str, remainder);
if (uNumValues == 1) {
if (str.size() != remainder) {
return false;
}
}
else {
std::size_t offset = remainder;
if (str.at(offset) != ',') {
return false;
}
unsigned uLastIdx = uNumValues - 1;
for (unsigned u = 1; u < uNumValues; ++u) {
pValue[u] = getValue<T>(str.substr(++offset), remainder);
offset += remainder;
if ((u < uLastIdx && str.at(offset) != ',') ||
(u == uLastIdx && offset != str.size()))
{
return false;
}
}
}
return true;
} // stringToValue
Utility.cpp
#include "stdafx.h"
#include "Utility.h"
namespace util {
// ----------------------------------------------------------------------------
// pressAnyKeyToQuit()
void Utility::pressAnyKeyToQuit() {
std::cout << "\nPress any key to quit" << std::endl;
_getch();
} // pressAnyKeyToQuit
// ----------------------------------------------------------------------------
// toUpper()
std::string Utility::toUpper( const std::string& str ) {
std::string result = str;
std::transform( str.begin(), str.end(), result.begin(), ::toupper );
return result;
} // toUpper
// ----------------------------------------------------------------------------
// toLower()
std::string Utility::toLower( const std::string& str ) {
std::string result = str;
std::transform( str.begin(), str.end(), result.begin(), ::tolower );
return result;
} // toLower
// ----------------------------------------------------------------------------
// trim()
// Removes Elements To Trim From Left And Right Side Of The str
std::string Utility::trim( const std::string& str, const std::string elementsToTrim ) {
std::basic_string<char>::size_type firstIndex = str.find_first_not_of( elementsToTrim );
if ( firstIndex == std::string::npos ) {
return std::string(); // Nothing Left
}
std::basic_string<char>::size_type lastIndex = str.find_last_not_of( elementsToTrim );
return str.substr( firstIndex, lastIndex - firstIndex + 1 );
} // trim
// ----------------------------------------------------------------------------
// getValue()
template<>
float Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stof( str, &remainder );
} // getValue <float>
// ----------------------------------------------------------------------------
// getValue()
template<>
int Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoi( str, &remainder );
} // getValue <int>
// ----------------------------------------------------------------------------
// getValue()
template<>
unsigned Utility::getValue( const std::string& str, std::size_t& remainder ) {
return std::stoul( str, &remainder );
} // getValue <unsigned>
// ----------------------------------------------------------------------------
// convertToUnsigned()
unsigned Utility::convertToUnsigned( const std::string& str ) {
unsigned u = 0;
if ( !stringToValue( str, &u, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to unsigned";
throw strStream.str();
}
return u;
} // convertToUnsigned
// ----------------------------------------------------------------------------
// convertToInt()
int Utility::convertToInt( const std::string& str ) {
int i = 0;
if ( !stringToValue( str, &i, 1 ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to int";
throw strStream.str();
}
return i;
} // convertToInt
// ----------------------------------------------------------------------------
// convertToFloat()
float Utility::convertToFloat(const std::string& str) {
float f = 0;
if (!stringToValue(str, &f, 1)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Bad conversion of [" << str << "] to float";
throw strStream.str();
}
return f;
} // convertToFloat
// ----------------------------------------------------------------------------
// splitString()
std::vector<std::string> Utility::splitString( const std::string& strStringToSplit, const std::string& strDelimiter, const bool keepEmpty ) {
std::vector<std::string> vResult;
if ( strDelimiter.empty() ) {
vResult.push_back( strStringToSplit );
return vResult;
}
std::string::const_iterator itSubStrStart = strStringToSplit.begin(), itSubStrEnd;
while ( true ) {
itSubStrEnd = search( itSubStrStart, strStringToSplit.end(), strDelimiter.begin(), strDelimiter.end() );
std::string strTemp( itSubStrStart, itSubStrEnd );
if ( keepEmpty || !strTemp.empty() ) {
vResult.push_back( strTemp );
}
if ( itSubStrEnd == strStringToSplit.end() ) {
break;
}
itSubStrStart = itSubStrEnd + strDelimiter.size();
}
return vResult;
} // splitString
} // namspace util
In my small utility library I have a function that will split a string that can use any delimiter that the user defines. It will search for the first occurrence of that character delimiter and it will save everything before it into a string and it will push that string into a vector of strings, and it will continue this for every occurrence of that character until it is finished parsing the full string that is passed to it. It will then return a vector of strings back to the user. This is very helpful when engaged in parsing text files or even just data types with long strings that need to be broken down. Now if there is a case where you are parsing a text file and lets say you need to have more than one word as a single string, this can be done but requires more work on your part. For example a text file might have personal record on a single line.
LastName, FirstName MiddleInitial Age Phone# Address
Cook, John S 33 1-888-323-4545 324 Complex Avenue
And you would want the 324 Complex Avenue to be in a single string also you don't want the comma stored after the last name. Your structure in code to store this info might look like this:
struct PersonalRecord {
std::string firstName;
std::string lastName;
char middleInitial;
unsigned age;
std::string phoneNumber;
std:string address;
};
What you would have to do is after you read this line in from your file on that same iteration of the while loop is you would have to do multiple parsing.
You would first start by using a temporary string and vector of strings and use the utility function splitString with the delimeter being the comma. So this would save 2 strings in the temp vector of strings the first being: Cook and the second being the rest of the line after the comma including the leading space. The reason you have the temp string and temp vector of strings is that you will need to pop values at when needed. So in this case we would have to do the following, but first how do we resolve the case with multiple words to one string? We can change the line of text in the text file to be enclosed with double quotes as such:
textfile
Cook, John S 33 1-888-323-4545 "324 Complex Avenue"
Evens, Sue A 24 1-888-323-6996 "128 Mission Rd"
Adams, Chris B 49 1-777-293-8234 "2304 Helms Drive"
Then parse it with this logic flow or algorithm.
main.cpp
#including "stdafx.h"
#including "Utility.h"
int main() {
using namespace util;
std::string strFilename( "personalRecord.txt" );
std::ifstream file;
std::string strLine;
std::vector<std::string> vTemp;
std::vector<std::string> vResult;
std::vector<PersonalRecord> vData;
// Open File For Reading
file.open( strFilename.c_str() );
// Check For Error Of Opening File
if ( !file.is_open() ) {
std::cout << "Error opening file (" << strFilename << ")" << std::endl;
return RETURN_ERROR;
}
// Continue Until End Of File
while( !file.eof() ) {
// Get Single Full Line Save To String
std::getline( file, strLine );
// Check For Comma
vTemp = Utility::splitString( strLine, ",");
// Save First String For Laster
std::string lastName = vTemp[0];
// Split String Using A Double Quote Delimiter Delimiter
vTemp = Utility::splitString( vTemp[1], "\"" );
// Check To See If vTemp Has More Than One String
if ( vTemp.size() > 1 ) {
// We Need To Use Pop Back To Account For Last Double Quote
vTemp.pop_back(); // Remove Last Double Quote
std::string temp = vTemp.back();
vTemp.pop_back(); // Remove Wanted String From vTemp.
// At This Point We Need To Parse vTemp Again Using Space Delimiter
vResult = Utility::splitString( vTemp[0], " " );
// Need To Account For Leading Space In Vector
vResult[0].erase();
// Need To Account For Last Space In Vector
vResult.pop_back();
// Now We Can Push Our Last String Back Into vResult
vResult.push_back( temp );
// Replace The First String " " With Our LastName
vResult[0] = lastName;
} else if ( vTemp.size() == 1 ) {
// Just Parse vTemp Using Space Delimiter
vResult = Utility::splitString( vTemp[0], " " );
}
// Print Out Results For Validity
for ( unsigned u = 0; u < vResult.size(); u++) {
std::cout << vResult.at(u) << " ";
}
std::cout << std::endl;
// Here Is Where You Would Populate Your Variables, Structures Or Classes On Each Pass Of The While Loop.
// With This Structure There Should Only Be 8 Entries Into Our vResult
PersonalRecord temp;
temp.lastName = vResult[0];
temp.firstName = vResult[1];
temp.middleInitial = vResult[2][0];
temp.age = Utility::convertToUnsigned( vResult[3] );
temp.phoneNumber = vResult[4];
temp.address = vResult[5];
vData.push_back( temp );
} // while
// Close File
file.close();
std::cout << std::endl << std::endl;
// Print Using Structure For Validity
std::cout << "---------------------------------------\n";
for ( unsigned u = 0; u < vData.size(); u++ ) {
std::cout << vData[u].lastName << " "
<< vData[u].firstName << " "
<< vData[u].middleInitial << " "
<< vData[u].age << " "
<< vData[u].phoneNumber << " "
<< vData[u].address << std::endl;
}
Utility::pressAnyKeyToQuit();
return RETURN_OK;
} // main
So both consideration and are has to be taken when parsing text or strings. You have to account for every single character including your carriage returns, spaces etc. So the format that the text file is written in has to be considered.
Yes the splitString() will also parse tabs, you would just have to use "\t" for tabs, etc. Just remember that it will make a split at every occurrence. So if you have a sentence that has a colon ":" in it, but then you decide to use the colon as your delimiter between values, it will split that sentence as well. Now you could have different rules for each line of text from the file and if you know what line you are on you can parse each line accordingly. This is why most people prefer to write their code to read and parse binary, because it is much easier to program, then writing a text parser.
I chose to use the PersonalRecord structure to show you how you can extract strings from a line of text and to convert them to basic types such as int, float or double by using some of my other functions in my Utility class. All methods in this class are declared as static and the constructor is private, so the class name acts as a wrapper or a namespace so to speak. You can not create an instance of a Utility util; // invalid object. Just include the header file and use the class name with the scope resolution operator :: to access any of the functions and make sure you are using the namespace util.
I want to open file , search for string , replace the string and then in the end print from that replaced string until the end.
So far I have opened the file using
fstream file ("demo.cpp");
Used
while (getline (file,line))
but using
string.find("something")
always give me line number 0, no matter which string I put in the arguments for find()
My question is, is there any other built in function which I can use in this situation or do I have to search through all lines, manually ?
To get a line number where the match occurs, you have to count the lines:
if (ifstream file("demo.cpp")) {
int line_counter = 0;
string line;
while (getline (file,line) {
line_counter++;
if (line.find("something") != string::npos) {
cout << 'Match at line ' << line_counter << endl;
}
}
} else {
cerr << "couldn't open input file\n";
}
You can use this replaceAll function on every line , and have your "replace in file function" built upon it.
I modified it to return a boolean if a replacement occurred :
bool replaceAll(std::string& str, const std::string& from, const std::string& to) {
if(from.empty())
return false;
size_t start_pos = 0;
bool res = false;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
res = true;
}
return res;
}
Then, what is left to you is :
Iterate over all the lines of the input file
Find and replace every occurrence of your string on the file
If a replacement occurred, write the line count
Write the replaced string on another file
The ReplaceInFile method :
void replaceInFile(const std::string& srcFile, const std::string& destFile,
const std::string& search, const std::string& replace)
{
std::ofstream resultFile(destFile);
std::ifstream file(srcFile);
std::string line;
std::size_t lineCount = 0;
// You might want to chech that the files are properly opened
while(getline(file,line))
{
++lineCount;
if(replaceAll(line, search, replace))
std::cout << "Match at line " << lineCount << " " << replace << std::endl;
resultFile << line << std::endl;
}
}
Example:
int main()
{
replaceInFile("sourceFile.txt", "replaced.txt", "match", "replace");
return 0;
}