I want to extract an specific number from a file which contains lines that look like this (the line goes on, this is the only important part):
"https://stackoverflow.com/questions/ask?wizard=1";
Where I have to ignore until I find the character '=' with a f.ignore(MAX_LONG_LINE, '\n'). But when it comes to getting the number 1 (it could be any number) in the url, I don't know what to do.
I've tried with getline(f, num, '"') but that doesn't support integers and converting from string to int is too advanced for what I'm learning and what my course is. There has to be a simpler method. After that, I tried with f >> num but that skips until the next space instead of the '"'.
num should result in the number between '=' and '"' in a file, which in the example is 1 but it could be different.
Thanks in advance
can be :
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main(int argc, char ** argv)
{
if (argc != 2) {
cout << "usage : " << argv[0] << " <file path>" << endl;
return -1;
}
ifstream in(argv[1]);
if (!in) {
cout << "cannot open " << argv[1] << endl;
return -1;
}
string line;
in >> line;
size_t p = line.rfind('=');
if (p == string::npos) {
cout << "invalid line '" << line << "', = is missing" << endl;
return -1;
}
stringstream ss(line.substr(p + 1));
int n;
string s;
ss >> n >> s;
if (s != "\";") {
cout << "invalid line '" << line << "', must be ...<number>\";'" << endl;
return -1;
}
cout << "number is " << n << endl;
return 0;
}
I ended up solving this myself:
Turns out f >> num does work, I just needed to add one more ignore before doing it, as it was getting the previous number. If you're having issues with this I suggest you to check you're correctly positioned with f.ignore(MAX_LONG_LINE, '\n') or similar methods before anything else. As long as num is an integer, it will extract a value of the same type.
Thanks a lot to everyone who helped me.
Related
i was trying to find a way to check two different files and get, from the second, all lines that aren't in the first.. but does all the opposite.
I tried the possible to solve this but nothing...
This is the code:
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
char username[UNLEN+1];
DWORD username_len = UNLEN+1;
GetUserName(username, &username_len);
stringstream buffer;
buffer << "C:\\Users\\" << username << "\\Desktop\\";
stringstream buffer2;
buffer2 << "C:\\Users\\" << username << "\\Desktop\\Legit.txt";
stringstream buffer3;
buffer3 << "C:\\Users\\" << username << "\\Desktop\\Unlegit.txt";
stringstream buffer4;
buffer4 << "C:\\Users\\" << username << "\\Desktop\\result.txt";
string results = buffer4.str();
int offset;
int num;
num = 1;
string search;
string linea;
string legit;
string unlegit;
string line;
cout << "Is the Legit.txt file at '" << buffer.str() << "'? [Y/N]: ";
cin >> legit;
if (legit == "Y" || legit == "y"){
}else if(legit == "N" || legit == "n"){
return 0;
}else{
cout << "\n.";
return 0;
}
string legitfile = buffer2.str();
cout << "\nIs the Unlegit.txt file at '" << buffer.str() << "'? [Y/N]: ";
cin >> unlegit;
if (unlegit == "Y" || unlegit == "y"){
}else if(unlegit == "N" || unlegit == "n"){
return 0;
}else{
cout << "\n";
return 0;
}
string unlegitfile = buffer3.str();
ifstream file(legitfile.c_str());
if(file.is_open()){
while(getline(file, line)){
ifstream MyFile(unlegitfile.c_str());
if(MyFile.is_open()){
while(!MyFile.eof()){
getline(MyFile,linea);
if((offset = linea.find(line, 0)) != string::npos) {
cout << "\n[" << num << "]" << " Word Found: " << line << "\n";
num++;
fstream result(results.c_str());
result << line << "\n";
result.close();
}
}
MyFile.close();
}
}
file.close();
return 0;
}else{
cout << "\nThe file '" << legitfile << "' does not exist.";
cout << "\nThe file '" << unlegitfile << "' does not exist.";
}
}
As i said, This code checks which words are equals in both (first & second) files and, once found, writes them to a third file, there is a way to do the opposite (check the two files and get the words that aren't equals)? Thank you so much!
I'm new, both in the forum and in C++, sorry if I make any mistakes. (sorry for my bad english too).
The classic solution to this sort of problem is to use a hash table collection to represent all the words in the first file. Then while iterating items from the second file, consult the set constructed of the first file. In C++, the std::unordered_set will do fine.
#include <unordered_set>
using namespace std;
unordered_set<string> firstFileSet;
unordered_set<string> missingFromSecondFileSet;
string line;
while(!firstfile.eof())
{
getline(firstfile,line);
firstFileSet.insert(line);
}
Then for each word in the second file, use a second set collection to keep track of what words are missing.
while(!secondfile.eof())
{
getline(secondfile,line);
if (firstFileSet.find(line) != firstFileSet.end())
{
missingFromSecondFileSet.insert(line);
}
else
{
firstFileSet.erase(line);
}
}
After the above runs, firstFileSet contains all the lines in the first file that were not present in the second. missingFromSecondFileSet contains all the lines in the second file that were not in the first:
for (auto &s : firstFileSet)
{
cout << s << " was in the first file, but not the second" << endl;
}
for (auto &s : missingFromSecondFileSet)
{
cout << s << " was in the second file, but not the first" << endl;
}
There is a program called diff on linux which does just what you are looking to do in C++.
It is written in C so you can just copy its source code =P
for (;; cmp->file[0].buffered = cmp->file[1].buffered = 0)
{
/* Read a buffer's worth from both files. */
for (f = 0; f < 2; f++)
if (0 <= cmp->file[f].desc)
file_block_read (&cmp->file[f],
buffer_size - cmp->file[f].buffered);
/* If the buffers differ, the files differ. */
if (cmp->file[0].buffered != cmp->file[1].buffered
|| memcmp (cmp->file[0].buffer,
cmp->file[1].buffer,
cmp->file[0].buffered))
{
changes = 1;
break;
}
/* If we reach end of file, the files are the same. */
if (cmp->file[0].buffered != buffer_size)
{
changes = 0;
break;
}
}
Taken from ftp://mirrors.kernel.org/gnu/diffutils/diffutils-3.0.tar.gz > src/analyze.c
My Text File:
Name G M S
Cart 1 0 1
Jane 0 1 0
What I have so far:
#include <iostream>
#include <string>
#include <fstream>
#include <stdlib.h>
#include <algorithm>
using namespace std;
void scoreChanger();
string line;
int main()
{
string yn;
int ctr = 0;
ifstream infile;
infile.open("WiiTourney.txt");
if (infile.is_open())
{
cout << "This is your current score table: " << endl;
while(getline(infile, line))
{
ctr++;
cout << line << endl;
cout << ctr << endl;
}
cout << endl;
}
else
{
cout << "Unable to open file" << endl;
}
infile.close();
cout << endl;
cout << "Would you like to change the scores? " << endl;
cin >> yn;
transform(yn.begin(), yn.end(), yn.begin(), ::tolower);
if (yn == "yes")
{
scoreChanger();
}
else
{
infile.close();
return 0;
}
return 0;
}
void scoreChanger()
{
string name;
ofstream outfile;
outfile.open("WiiTourney.txt");
if (outfile.is_open())
{
cout << "Who won the game? " << endl;
cin >> name;
transform(name.begin(), name.end(), name.begin(), ::tolower);
if (name == "jane")
{
while(getline(outfile, line))
{
cout << line << endl;
}
}
for (int x = 0; x < line.length(); x++)
{
if (line[x] == 8 && line[x] != 'G')
{
}
}
}
else
{
cout << "Error opening file. " << endl;
exit(1);
}
}
What I want it to do:
Let's say I wanted to be able to add 1 point to the Games column(G) only for Cart. The problem for me is that I only want to change the 1 in the G column and I know that I would encounter problems by just looping through and searching for instances where 1 comes up because there could be multiple 1's in one line. I am also getting the error on the line while(getline(outfile, line)) that says "no matching function for call to 'getline(std::ofstream&, std::string&)'"
Thank you, your help is very much appreciated.
My first thought was that the structure of the table is very uniform, so you could determine the position of a specific score using columns and rows.
Because the names are the only elements with variable length (assuming the scores don't go above 9, because that would give 2 characters), I would first read the first word of every row and input this into an array of names.
From this you can find specific elements using the row and column indices. If C++ doesn't contain a function to get characters based on row and column indices, I would loop through the file and add each character to the corresponding position in a 2-dimensional array.
For example:
characters[0][0]
would return N, from the start of "Names".
And of course to retrieve the score you incorporate the length of the name the specific line to get the value:
characters[names[0].length()+1][1]
This would return the score under G for the first name in the list.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
int main()
{
//Input .txt file
ifstream inputFile ("input.txt");
try
{
int i = 1; //Line iterator
int vertices = 0;
int faces = 0;
string line;
while (getline(inputFile, line))
{
//Take number from line 4, set as variable "vertices"
if (i == 3)
{
getline (inputFile,line);
size_t last_index = line.find_last_not_of("0123456789");
string str = line.substr(last_index);
vertices = atoi(str.c_str()); //Convert to int
cout << "vertices " + str << endl;
}
//Take number from line 11, set as variable "triangles"
if (i == 11)
{
getline (inputFile,line);
size_t last_index = line.find_last_not_of("0123456789");
string str = line.substr(last_index);
faces = atoi(str.c_str()); //Convert to int
cout << "faces " + str << endl;
}
if (i == 13)
{
i++;
break;
}
cout << "line: " + i << endl; //Prints line number
i++;
}
} catch(const char* error) {
cout << "Cannot read file, please try again." << error;
}
return 0;
}
This program is simply trying to read file, take a number from a couple of lines and for each line print "line: " with respective line number. It looks like C++ iterates differently to Java?
For some reason this program outputs:
*ine:
ne:
vertices 752
e:
:
Cannot read mesh, please try again.
faces r
annot read mesh, please try again.
nnot read mesh, please try again.*
I have no idea why.
This line:
cout << "line: " + i << endl;
should be:
cout << "line: " << i << endl;
Your + is adding i to the string constant "line: ", which has the effect of knocking one character off the front each time round the loop (and eventually going off the end, leading to undefined behaviour).
You can't add objects to strings in C++ in the way you're attempting, but you can send multiple objects to cout by repeated use of <<.
You then have the same problem here:
cout << "vertices " + str << endl;
and here:
cout << "faces " + str << endl;
Given input in the form of
fifteen,7,fourth-four,2,1,six
66,eight-six,99,eighteen
6,5,4,3,2,1
What can I use to read this into a format that I can then parse? The goal is to be able to sort the numbers and then print them back out, in order, in the same format that they were given to me. For example, the following should be printed as
1,2,six,7,fifteen,forty-four
eighteen,66,eighty-six,99
1,2,3,4,5,6
I have an idea of how the sorting should be done, I'm just having trouble figuring out the best way to read in the input. Currently, I'm using just doing this:
#include <iostream>
#include <string>
using namespace std;
int main() {
char word;
char arr[20];
int count = 0;
while (cin >> word) {
if (word == '\n') {
cout << "Newline detected.";
}
cout << "Character at: " << count << " is " << word << endl;
count++;
}
}
This does not work, because there is never a \n read in.
IMO the easiest way to do it would be to use std::istream's getline function with the ',' as the delimiter.
E.g. Something like.
char dummystr[256];
int count = 0;
while (cin.getline(dummystr, 256, ',')) {
cout << "Character at: " << count << " is " << dummystr << endl;
++count;
}
For newline delimiters with comma delimiters on each line (you really should just pick one):
char dummystr[256]; // not max size for the string
int count = 0;
while (cin.getline(dummystr, 256, '\n')) {
std::stringstream nested(dummystr);
char dummystr2[256];
while (nexted.getline(dummystr2, 256, ',')) {
cout << "Character at: " << count << " is " << dummystr << endl;
++count;
}
}
I posted an earlier question asking for help with using a validation script in my code. After a very helpful answer I was able to sort of figure out how I needed to proceed. Well, I've hit a big obstacle;
#include <iostream>
#include <sstream>
#include <string>
#include <ctype.h>
using namespace std;
int main()
{
unsigned __int64 input = 0;
int n, i;
char str[]="c3po...";
i=1;
n=0;
for (cout << "Input a number" << endl; cin >> input; cin.ignore(numeric_limits<int>::max(), '\n'))
{
cout << "We're parsing your input '" << input << "'\n";
if (input % 2 == 0)
{
cout << "Even!" << endl;
}
else if (input % 2 == 1)
{
cout << "Odd" << endl;
cout << "Lets make it even shall we? " << "Your new number is... " << input + 1 << endl;
}
else (isalnum(str[i]));i++;
{
cout << "We could not parse '" << input << "' as a number.\n";
}
}
system ("pause");
return 0;
}
As you can see from my code, the validation script is well, sort of working. I have some bugs I wish to iron out.
1- When I input a number, it runs though the code as it should but it also displays
Could not parse 'inputted number' as a number
obviously when a number is inputted you don't want this to happen!
2- For the error message, it is showing the inputted number as [0]. Is this to do with using an integer? How can this be fixed?
Thanks!
your problem is quite simple, you have small mistake on this line
else (isalnum(str[i]));
Your else statement ends at the semicolon and does actually nothing. Following statements will be executed every time.
i++;
{
cout << "We could not parse '" << input << "' as a number.\n";
}