sometimes when you copy code from a document it gets line numbers and strange quotes. I've written a script to remove those initial numbers but it is very hard to find a way to remove those strange quotes ‘’“” so I've included my full code. It reads in a file and puts out a formatted file. But the compiler warns that these quotes are multi characters, which I guess means non standard ascii chars. It kinda works but it's not a great solution. Any help appreciated:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string replaceChar(string str, char ch1, char ch2);
// Main
int main(int argc, char *argv[]) {
string line;
fstream stri, stro;
// ifstream in
stri.open(argv[1], ios::in);
if(stri.fail()){
cerr << "File failed to open for input" << endl;
return 1;
}
// ofstream out
stro.open("file_out.txt", ios::out);
if(stro.fail()){
cerr << "File failed to open for output" << endl;
return 1;
}
// Read - Write
//stri.get(c);
getline(stri, line, '\n');
while(!stri.eof()){
// Remove numbers
line.erase(0,3);
//line.replace( line.begin(), line.end(), "‘", "\'" );
//line.replace( line.begin(), line.end(), "’", "\'" );
//line.replace( line.begin(), line.end(), "“", "\'" );
//line.replace( line.begin(), line.end(), "”", "\'" );
line = replaceChar(line, '‘','\'');
line = replaceChar(line, '’','\'');
line = replaceChar(line, '“','\"');
line = replaceChar(line, '”','\"');
stro << line << endl;
getline(stri, line, '\n');
}
// Close files
stri.close();
stro.close();
// Output
cout << "File Edited Ok!";
//cout << count -1 << " characters copied."<< endl;
}
string replaceChar(string str, char ch1, char ch2) {
for (int i = 0; i < str.length(); ++i) {
if (str[i] == ch1)
str[i] = ch2;
}
return str;
}
Ok, it ain't pretty, but it works. Anyone want to refine searching for one of those damned strange quote marks be my guest!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// Function Declaration
bool replace(string& str, const string& from, const string& to);
bool checkMyLine(string line);
// Main
int main(int argc, char *argv[]) {
// line to edit
string line;
fstream stri, stro;
// ifstream in
stri.open(argv[1], ios::in);
if(stri.fail()){
cerr << "File failed to open for input" << endl;
return 1;
}
// ofstream out
stro.open("file_out.txt", ios::out);
if(stro.fail()){
cerr << "File failed to open for output" << endl;
return 1;
}
// Read - Write
while(getline(stri, line, '\n')){
// Remove numbers at start of each line followed by space, eg: "001: "
int i;
for(i = 0;i < line.length();i++)
{
if(line[i] == ' ') break;
}
line.erase(0,i+1);
//Replace Odd Chars
for(int i=0;i<line.length();i++)
{
replace(line, "\u2018","\u0027"); // replaces ‘
replace(line, "\u2019","\u0027"); // replaces ’
replace(line, "\u201C","\u0022"); // replaces “
replace(line, "\u201D","\u0022"); // replaces ”
}
// Write to file
stro << line << endl;
}
// Close files
stri.close();
stro.close();
// Output Message
cout << "File Edited Ok!";
}// End of Main
//
bool replace(string& str, const string& from, const string& to)
{
size_t start_pos = str.find(from);
if(start_pos == string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
What kind of script did you write to remove the leading numbers?
Do you have access to sed or tr? They exist for just this kind of problem.
sed -e 's/[‘’“”]//g'
No need to re-invent the wheel
Related
So, what I am trying to do is, read from a file and write into another.
std::ifstream fs;
fs.open ("/Users/aditimalladi/CLionProjects/file/log.txt");
string str_file;
std::ofstream fs2;
fs2.open ("/Users/aditimalladi/CLionProjects/file/log-copy.txt ");
if(!fs || !fs2)
{
std::cout<<"ERROR";
exit(0);
}
string str;
while(getline(fs,str))
{
while(true) {
std::cout<<"\n This is the string \n"<<str<<std::endl;
size_t index = str.find("≠", index);
if (index == std::string::npos) break;
str.replace(index, 1, "-");
index += 1;
std::cout<<"\n This is the new replaced string \n"<<str<<std::endl;
}
fs2 << str << std::endl;
}
fs.close();
fs2.close();
What my end goal is to be able to read a line and replace that line in the same file after making some changes.But first I want this basic program to work before I move forward.
A problem in the snippet you posted is that you are trying to replace a string "≠", which contains non-ASCII character that can be encoded with multiple bytes. So those lines:
size_t index = str.find("≠", index);
if (index == std::string::npos)
break;
str.replace(index, 1, "-");
// note this ^^^
Will replace only the first byte of the encoding, leaving the others.
You could use the correct size of the string to be replaced or rewrite your program using the regular expression library:
#include <iostream>
#include <string>
#include <fstream>
#include <regex>
int main()
{
std::ifstream fs {"/Users/aditimalladi/CLionProjects/file/log.txt"};
std::ofstream fs2 {"/Users/aditimalladi/CLionProjects/file/log-copy.txt"};
if(!fs || !fs2)
{
std::cerr << "Error, can't open files";
exit(1);
}
std::regex a {"≠"};
std::string line;
while ( std::getline(fs, line) )
{
fs2 << std::regex_replace(line, a, "is not equal to") << '\n';
}
}
I've read the lines from a textfile and i want to check if that line contains the $ sign.
That's what i got so far:
int main() {
ifstream data_store;
string line;
data_store.open("c:\\test.txt");
while (!data_store.eof())
{
getline(data_store, line);
if (line.find("$"))
cout << "1: " << line << endl;
}
data_store.close();
system("PAUSE");
return 0;
}
Furthermore how can i output them to a file ?
To check if a line contains something using std::string::find to need to check the returned value from find to make sure it is a valid return. To do that we compare it against std::string::npos as that is what find() will return if it does not find anything. This is the reason it finds every line as std::string::npos is still considered true when evaluated as a bool. So refactoring your code you would have:
while (getline(data_store, line))
{
if (line.find("$") != std::string::npos)
cout << "1: " << line << endl;
}
I also changed the while loop as using eof is not how to control a while loop. for more information on that see Why is “while ( !feof (file) )” always wrong?
As far as outputting the string to a file see: How to write std::string to file?
It's a minor thing, but a variant of #NathanOliver's solution, is to use a for loop:
ifstream data_store("c:\\test.txt");
for ( string line; getline(data_store, line); ) {
if ( line.find("$") != string::npos )
cout << "1: " << line << endl;
}
// ...
The benefit here is that line is now local only to the loop, which is what it should be since that is the only place it is used.
I did it yesterday forgot to update.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
bool contains_number(const string &c);
int main()
{
int count = 0;
{
string line1[100];
ifstream myfile("D:/Users/Jarvan/Desktop/test.txt");
int a = 0;
if (!myfile)
{
cout << "Error opening output file" << endl;
system("pause");
return -1;
}
while (!myfile.eof())
{
getline(myfile, line1[a], '\n');
if (contains_number(line1[a]))
{
count += 1;
cout << line1[a] << "\n";
}
else cout << "\n";
}
}
cout << count <<endl;
system("pause");
return 0;
}
bool contains_number(const string &c)
{
return (c.find_first_of("$") != string::npos);
}
This program is supposed to tell the user how many words and lines are in their program (text file only). The two functions that I have written both work, except the num_of_lines function is counting one more line than is correct every time and the num_of_words function is off by about 300 words every time. Not sure what I am doing wrong here. Any help will be greatly appreciated, thanks. I copy and pasted an output after my code and compared it to wc.
#include <iostream>
#include <fstream>
#include <cctype>
#define die(errmsg) {cerr << errmsg << endl; exit(1);}
using namespace std;
int num_of_words(string name)
{
int cnt2 = 0;
ifstream iwords;
iwords.open(name);
string w;
if(iwords.is_open())
{
while(iwords >> w)
{
cnt2++;
}
}
else cerr <<"can not open" + name << endl;
iwords.close();
return(cnt2);
}
int num_of_lines(string name)
{
int cnt3 = 0;
string line;
ifstream ilines;
ilines.open(name);
if(ilines.is_open())
{
while(getline(ilines, line))
{
cnt3++;
}
}
else cerr <<"can not open" + name << endl;
ilines.close();
return(cnt3);
}
int main(int argc, char **argv)
{
int num_of_lines(string name);
if(argc == 1)die("usage: mywc your_file");
string file;
file = argv[1];
ifstream ifs;
ifs.open(file);
if(ifs.is_open())
{
int b;
b = num_of_words(file);
cout <<"Words: " << b << endl;
}
else
{
cerr <<"Could not open: " << file << endl;
exit(1);
}
ifs.close();
return(0);
}
Zacharys-MBP:c++ Zstow$ my sample.txt
Chars: 59526
Words: 1689
Lines: 762
Zacharys-MBP:c++ Zstow$ wc sample.txt
761 2720 59526 sample.txt
Zacharys-MBP:c++ Zstow$
Most files (especially programs) will end in a new line. You may not see this in your editor but it is probably there. You will have to check the last line to see if it actually contains any content, or if it is empty.
The istream operator (>>) will detect any group of characters between whitespace to be a "word." So if you're parsing programs, you may have:
for(int i=1; i<73; i++)
The istream operator will see 4 words: [for(int, i=1;, i<73;, i++)]
I want to read data from stream, which has specific format, such as:
"number:name_that_can_contain_spaces:string,string,string..." without quotes where ... means that I dont know how many strings are there separated with commas and strings can have spaces before and after it but not in the middle of string, I want to stop reading at new line
I only come up with using getline() and store each line into string, but I dont know how to continue, if there is something like strtok(line, ":",":",",","\n") which would parse it for me or I have to parse it myself character by character
example of valid line format is:
54485965:abc abc abc: some string, next string , third string\n
parsed result would be:
int 54485965
string "abc abc abc"
string "some string"
string "next string"
string "third string"
You can read line with std::getline and then split it with std::string::find and std::string::substr. In the code below we read line from file data, then find : (so everything before it becomes number which we parse into int with std::stoi) and throw away first part. Similar we do it with name. And in the end we fill std::list with strings separated by ,.
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <exception>
#include <stdexcept>
struct entry {
std::string name;
int number;
std::list<std::string> others;
};
int main(int argc, char** argv) {
std::ifstream input("data");
std::list<entry> list;
std::string line;
while(std::getline(input, line)) {
entry e;
std::string::size_type i = 0;
/* get number from line */
i = line.find(":");
if(i != std::string::npos) {
e.number = stoi(line.substr(0, i));
line = line.substr(i + 1);
} else {
throw std::runtime_error("error reading file");
}
/* get name from line */
i = line.find(":");
if(i != std::string::npos) {
e.name = line.substr(0, i);
line = line.substr(i + 1);
} else {
throw std::runtime_error("error reading file");
}
/* get other strings */
do {
i = line.find(",");
e.others.push_back(line.substr(0, i));
line = line.substr(i + 1);
} while(i != std::string::npos);
list.push_back(e);
}
/* output data */
for(entry& e : list) {
std::cout << "name: " << e.name << std::endl;
std::cout << "number: " << e.number << std::endl;
std::cout << "others: ";
for(std::string& s : e.others) {
std::cout << s << ",";
}
std::cout << std::endl;
}
return 0;
}
I am using getline to read up to end of newline but c++ getline gets me stuff till space,
I have txt file data as
address(tab char)1420 Happy Lane
When I do
getline(reader, ss, '\t') I get address in ss string.
when I do getline(reader, ss, '\n') I just get 1420.
I want full "1420 Happy Lane", How to get it ?
Thanks.
#include <fstream>
#include <string>
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main( int argc, char *argv[] )
{
if( argc < 2 )
{
cout << "Missing filename as first argument" << "\n";
exit(2);
}
vector<string> myvector;
string ss;
int i=0, j=0;
ifstream reader(argv[1]);
if (! reader )
{
cout << "Error opening input file : " << " " << argv[1] << '\n';
return -1;
}
while( !reader.eof())
{
if ((i+1) % 2 == 0 )
getline(reader, ss, '\n');
else
getline(reader, ss, '\t');
if (ss[0] == '#')
{
//Skip
getline(reader,ss, '\n');i=0;
continue;
}
i++;
myvector.push_back(ss);
}
reader.close();
vector<string>::iterator it;
stringstream stream;
int vecloc=1;
string tag;
string sData;
cout << "myvector contains: \n";
for ( it=myvector.begin() ; it < myvector.end(); it++ )
{
switch (vecloc)
{
case 1: stream << *it; stream >> tag; vecloc++;break;
case 2:
stream << *it; stream >> sData;
// Do job
cout << tag << " " << sData << "\n";
// Reset.
vecloc=1; break;
default : break;
}
// Clear String stream
stream.str(""); stream.clear();
}
return(0);
}
output
/home/sr/utl
cat abc.txt
hey c++ making me nuts.
/home/sr/utl
a.out abc.txt
myvector contains:
hey c++
Paste the actual code from your editor and double check that there isn't a newline (or maybe other unexpected non-printing characters) in your data file.
This works as expected here:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream reader("address\t1420 Happy Lane\n");
string ss;
getline(reader, ss, '\t');
cout << "1: " << ss << endl;
getline(reader, ss, '\n');
cout << "2: " << ss << endl;
}
Output:
1: address
2: 1420 Happy Lane
I got a split() function you can use for that. Use \t as the delimeter:
void split(std::string &string, std::vector<std::string> &tokens, const char &delim) {
std::string ea;
std::stringstream stream(string);
while(getline(stream, ea, delim))
tokens.push_back(ea);
}
You're trying to alternate between grabbing up until a \t and grabbing up until a \n. But the times that you find a '#' comment line throw off your alternation.
By far the easiest and most robust way to handle this sort of thing is to read each line first, and then re-parse the line.