Extract data from text file in formatted/sequential way - c++

I have a file .txt with this structure:
000010109000010309000010409
Where i need to read like this:
00001 01 09
00001 03 09
00001 04 09
I have a structure in this way:
struct A{
string number // first 5 numbers
int day; // 2 numbers
int month; // last 2 numbers
};
I tried in this way.
But dont work.
char number[6];
char day[3];
char monthes[3];
ifstream read("file.txt");
for (int i = 0; i < 100; i++) {
read.get(number,6);
structure[i].number= number;
read.get(day,3);
structure[i].day= atoi(day);
read.get(month,3);
structure[i].month= atoi(month);
}
How read and store the datas from the file to this structure?
And how compare if the number have in the same month many days.
Thanks a lot.

You could try something like this:
FILE *fp = fopen("file.txt", "r");
A a;
char x[6], y[3], z[3];
fscanf(fp, "%5s%2s%2s", x, y, z);
a.number = string(x);
a.day = atoi(y);
a.month = atoi(z);
EDIT:
It is valid C++ code (with cstdio and cstdlib), but if you want some C++ version, you could try something like this
// read from file.txt
std::ifstream inFile("file.txt", std::ios::in);
char number[6], day[3], month[3];
int cnt = 0;
while (inFile.get(number, 6) && inFile.get(day, 3) && inFile.get(month, 3)) {
// Let's assume that structure[] is array of struct A
structure[cnt].number = number;
structure[cnt].day = atoi(day);
structure[cnt].month = atoi(month);
++cnt;
}
// store to file2.txt
std::ofstream outFile("file2.txt", std::ios::out);
for (int i = 0; i < cnt; ++i) {
outFile << structure[i].number << ' ' << structure[i].day << ' ' << structure[i].month << std::endl;
// If you need fixed-width for day/month, use std::setw and std::setfill
}
// compare first two
if (cnt >= 2) {
if (structure[0].number == structure[1].number &&
structure[0].month == structure[1].month &&
structure[0].day == structure[1].day) {
std::cout << "Same!" << std::endl;
} else {
std::cout << "Different!" << std::endl;
}
}

I'm using stringstream here as an example but the same will work with fstream. Convert number, day and month from char arrays to required data types as necessary (all are '\0' terminated)
#include <iostream>
#include <sstream>
int main() {
std::string s = "000010109000010309000010409";
std::istringstream iss(s);
char number[6], day[3], month[3];
while (iss.get(number, 6) && iss.get(day, 3) && iss.get(month, 3))
std::cout << number << " " << day << " " << month << std::endl;
return 0;
}
https://ideone.com/tyBShW
00001 01 09
00001 03 09
00001 04 09

Related

How to get data from a file.txt to my object and then store it in mysql database in c++

I am new to c++ and I have to work on a project for my end-of-study internship.
The project consists in managing the data of the electronic log of the ATMs.
My problem is that I have to get the data from a file.txt(which is an electronic gab log) and store it in the table I created.
Here is an example of the file.txt (the electronic gab log) :
Every events of this file is separated by : ************************
File log.txt
File log.txt
The data I need to store in the table is : (look the image)
Table journal_contents
I have the Journal object that I created and I want to get tha data in this object and then in the database.
Here is the code I've done :
This is my header.h
//Declaration de struct
struct events {
int id_event;
std::string id_event_ligne;
float amount_withdraw;
int type_transaction;
int type_return_transaction;
int type_card_returned;
int type_card_insert;
int type_return_motif;
};
class Journal // Object journal
{
public:
Journal(){};
int getId_ligne();
private:
int id;
int id_atm;
int id_ligne;
int date_ligne;
int date_insert;
std::vector<events> trans_events;
};
This is my file.cpp
//Some random code
int Journal::getId_ligne( )
{
time_t t =time(0); // get time now
tm* now = localtime(&t);
int year= (now->tm_year + 1900);
string syear(to_string(year));
int month = (now->tm_mon + 1);
string smonth(to_string(month));
int day = now->tm_mday;
string sday(to_string(day));
int hour = now->tm_hour;
string shour(to_string(hour));
int minute = now->tm_min;
string sminute(to_string(minute));
int second = now->tm_sec;
string sseconde(to_string(second));
if(smonth.length()== 1)
{
smonth = '0' + smonth;
}
if(sday.length()== 1)
{
sday = '0' + sday;
}
if(shour.length()== 1)
{
shour = '0' + shour;
}
if(sminute.length()== 1)
{
sminute = '0' + sminute;
}
if(sseconde.length()== 1)
{
sseconde = '0' + sseconde;
}
string current_time =syear + '-' + smonth + '-' + sday + '\t' + shour + ':' + sminute + ':' + sseconde ;
string datee= syear + smonth+ sday + ".jrn" ;
const char* path = "C:\\Users\\dell\\Desktop\\Stage\\journals\\";
string str_path = string(path)+ datee;
//find filename
unsigned found = str_path.find_last_of("/\\");
string same_path = str_path.substr(found+1);
//Compare
if (datee.compare(same_path)== 0)
{
// Here I just writed 8902 as an Id to test but what I need to do is to get the id from the file.txt
string filename = string(str_path);
ifstream file1(filename);
string line;
string word;
if(file1.is_open())
{ int k=0;
while (getline(file1, line))
{
if (line.find("8902") != string::npos){
istringstream isstream;
isstream.str(line);
getline(isstream, word, ' ');
getline(isstream, word, ' ');
int id_ligne = stoi(word);
Db_response::Connection();
string insert_query = "INSERT INTO `journal_contents`(`id_ligne`) VALUES ('"+word+"')";
//int qstate = mysql_real_query(conn,insert_query.c_str(), strlen(insert_query.c_str()));
query_state=mysql_query(conn, insert_query.c_str());
if(!query_state)
{
cout << "Query Execution Problem " << mysql_errno(conn) << endl;
}
else
{
cout << endl << "success" << endl;
}
k=1;
}}
if (k==0) {
}
file1.close();
}
else
cout <<"File not found " << endl;
file1.close();
//cout << id << endl;
return id_ligne;
}
}
main.cpp
int main(int argc, const char* argv[])
{
cout << "Hello world!" << endl;
Journal current_journal;
cout << current_journal.getId_ligne() << endl;
}
I hope I have explained my problem well. I really need your help
Thanks in advance for helping me.

Cross referencing data from file

Cant figure this out....I got two txt files, one is encoding1.txt which contains a set of hexadecimals and the ID number that is assigned to them, such as
61 1
C3A4 2
C990 4
C991 5
C991CC83 6
C992 7
CA8C 9
The other file source.txt is the source file which contains a bunch of combined hex and the students' names
CA8CC992 Jack
C991C3A4 Amy
C991CC83 Sam
61C991 Tom
I want to output a txt file for each students with their name as their filenames and inside the file should be the assigned numbers of their hex. e.g. for jack.txt, inside it should be
9
7
Below is the code that I've tried it generates all the test file but inside its jack.txt theres only 9 and other files are empty. Whats the correct way to do this and how do I get the results right?
#include "stdafx.h"
#include <iostream>
#include <string>
//#include<map>
//#include<unordered_map>
#include <fstream>
#include<array>
//#include<vector>
#include <algorithm>
using namespace std;
int main()
{
std::ifstream file;
file.open("encoding1.txt");
if (file.is_open())
{
std::cout << "opened encoding1 file";
}
std::ifstream file2;
file2.open("source.txt");
if (file.is_open())
{
std::cout << "opened source file" << std::endl;
}
std::ofstream outfile;
const int hexencosize = 7;
std::string hexenco[hexencosize] = {};
int id[7] = {};
std::string hexsource;
string * p;
std::string name;
for (int i = 0; i < 6; i++)
while (file >> hexenco[i] >> id[i]) {
std::cout << "hexenco is " << hexenco[i] << std::endl;
std::cout << "id is " << id[i] << std::endl;
};
for (int o = 0; o < 6; o++)
while (file2 >> hexsource >> name) {
outfile.open(name + ".txt");
std::size_t found = hexsource.find(hexenco[o]);
if (found != std::string::npos)
p = std::find(hexenco, hexenco + hexencosize, hexenco[o]);
if (p >= hexenco + hexencosize) std::cout << "Not found" <<
std::endl;
else outfile << id[p - hexenco] << '\n';
outfile.close();
};
system("pause");
return 0;
};

How do I read the whole 64 bytes of a binary file?

I am writing a little program that reads a disk image file in binary and then checks its partition entry tables to display each partition, it's type, start sector and size.
So far it reads the first 16 bytes accurately but the rest of the partition entries are not recognized or have some kind of error.
The result looks like this:
EDIT: The first line of the output is supposed to look like this:
`Partition 0: Type: FAT-16 Start: 63 Size: 518760`
What am I missing? How do I fix the code so that all the partition entries give the appropriate result?
using namespace std;
#include <iostream>
#include <fstream>
struct Partition { char type; int start_sect; int size; } part_entry[4]; // 4 x partition table entry
int main(int argc, char *argv[])
{
//DECLARATIONS
int i, offset = 26, not_exist = 0;
char buf_part_table[64], vol_type[12];
char* diskdata;
int n;
streampos begin, end;
ifstream diskimage;
diskimage.open("Sample_1.dd", ios::in | ios::binary | ios::out);
diskdata = new char[begin];
begin = diskimage.tellg();
diskdata = new char[begin];
diskimage.seekg(446, ios::beg);
diskimage.read(buf_part_table, 64);
for (i = 0; i < 4; i++)
{
part_entry[i].type = *(char*)(buf_part_table + 0x04 + (i * offset));
if (part_entry[i].type == 0) not_exist++;
part_entry[i].start_sect = *(int*)(buf_part_table + 0x08 + (i * offset));
part_entry[i].size = *(int*)(buf_part_table + 0x0C + (i * offset));
switch (part_entry[i].type)
{
case 00: strcpy(vol_type, "NOT-VALID");
break;
case 06: strcpy(vol_type, "FAT-16");
break;
case 07: strcpy(vol_type, "NTFS");
break;
case 0x0B: strcpy(vol_type, "FAT-32");
break;
default: strcpy(vol_type, "NOT-DECODED");
break;
}
cout << "Partition " << i << ":" << " Type:" << vol_type << " Start: " << part_entry[i].start_sect << " Size: " << part_entry[i].size << endl;
}
return 0;
}
You unnecesary made program unreadable and harder to debug.
You can read whole boot sector at once and than display desired content.
Here is my quick example (it does not check if file exists, some may complain it should use memcpy for some fields etc.)
#include <iostream>
#include <fstream>
#include <cstdint>
#include <cstddef>
#include <iomanip>
using namespace std;
struct partition_t {
uint8_t status;
uint8_t start_CHS[3];
uint8_t type;
uint8_t end_CHS[3];
uint32_t start_LBA;
uint32_t size_LBA;
} __attribute__((packed));
struct mbr_t
{
uint8_t bootstrap[446];
partition_t partitions[4];
uint16_t signature;
} __attribute__((packed));
int main(int argc, char *argv[])
{
mbr_t mbr;
ifstream diskimage;
diskimage.open( "/tmp/mbr.dd", ios::in | ios::binary );
diskimage.read( reinterpret_cast<char*>(&mbr), sizeof(mbr) );
diskimage.close();
for( int idx = 0 ; idx < 4 ; idx++ )
{
string bootable = (mbr.partitions[idx].status == 128) ? "yes" : "no";
cout << " bootable : " << setw(5) << bootable <<
" type : " << setw(5) << (int)mbr.partitions[idx].type <<
" start LBA : " << setw(10) << mbr.partitions[idx].start_LBA <<
" size : " << setw(10) << mbr.partitions[idx].size_LBA << endl;
}
return 0;
}
It is easier to read, right?

How do I read a text file having Unicode codes?

I initialize a string using the following code.
std::string unicode8String = "\u00C1 M\u00F3ti S\u00F3l";
Printing it using cout, the output is Á Móti Sól.
But when I read same same string from a text file using ifstream, store it in a std::string, and print it, the output is \u00C1 M\u00F3ti S\u00F3l.
The content of my file is \u00C1 M\u00F3ti S\u00F3l and I want to print it as Á Móti Sól. Is there any way to do this?
Off the top of my head (completely untested)
std::string convert_string(const std::string& in)
{
std::string out;
for (size_t i = 0; i < in.size(); )
{
if (i + 5 < in.size() && in[i] == '\\' && in[i+1] == 'u' &&
in[i+2] == '0' && in[i+3] == '0' &&
isxdigit(in[i+4]) && isxdigit(in[i+5]))
{
out += (unsigned char)16*in[i+4] + (unsigned char)in[i+5];
i += 6;
}
else
{
out += in[i];
++i;
}
}
return out;
}
But this won't work with any unicode values above 255, (e.g. \u1234) because you have the fundamental problem that your string stores 8 bit characters, and Unicode characters can have up to 20 bits.
As I said completely untested, but I'm sure you get the idea.
Can you try printing using "std::wcout"!
The unicode characters have a different representation in a text file (There is no \u).
For Evaluation
int main()
{
// Write
{
std::string s = "\u00C1 M\u00F3ti S\u00F3l";
std::ofstream out("/tmp/test.txt");
out << s;
}
// Read Text
{
std::string s;
std::ifstream in("/tmp/test.txt");
std::getline(in, s);
std::cout << "Result: " << s << std::endl;
}
// Read Binary
{
std::ifstream in("/tmp/test.txt");
in.unsetf(std::ios_base::skipws);
std::istream_iterator<unsigned char> first(in);
std::istream_iterator<unsigned char> last;
std::vector<unsigned char> v(first, last);
std::cout << "Result: ";
for(unsigned c: v) std::cout << std::hex << c << ' ';
std::cout << std::endl;
}
return 0;
}
On Linux with UTF8:
Result: Á Móti Sól
Result: c3 81 20 4d c3 b3 74 69 20 53 c3 b3 6c

Extract integer from a string

I have string like "y.x-name', where y and x are number ranging from 0 to 100. From this string, what would be the best method to extract 'x' into an integer variable in C++.
You could split the string by . and convert it to integer type directly. The second number in while loop is the one you want, see sample code:
template<typename T>
T stringToDecimal(const string& s)
{
T t = T();
std::stringstream ss(s);
ss >> t;
return t;
}
int func()
{
string s("100.3-name");
std::vector<int> v;
std::stringstream ss(s);
string line;
while(std::getline(ss, line, '.'))
{
v.push_back(stringToDecimal<int>(line));
}
std::cout << v.back() << std::endl;
}
It will output: 3
It seem that this thread has a problem similar to you, it might help ;)
Simple string parsing with C++
You can achieve it with boost::lexical_cast, which utilizes streams like in billz' answer:
Pseudo code would look like this (indices might be wrong in that example):
std::string yxString = "56.74-name";
size_t xStart = yxString.find(".") + 1;
size_t xLength = yxString.find("-") - xStart;
int x = boost::lexical_cast<int>( yxString + xStart, xLength );
Parsing errors can be handled via exceptions that are thrown by lexical_cast.
For more flexible / powerful text matching I suggest boost::regex.
Use two calls to unsigned long strtoul( const char *str, char **str_end, int base ), e.g:
#include <cstdlib>
#include <iostream>
using namespace std;
int main(){
char const * s = "1.99-name";
char *endp;
unsigned long l1 = strtoul(s,&endp,10);
if (endp == s || *endp != '.') {
cerr << "Bad parse" << endl;
return EXIT_FAILURE;
}
s = endp + 1;
unsigned long l2 = strtoul(s,&endp,10);
if (endp == s || *endp != '-') {
cerr << "Bad parse" << endl;
return EXIT_FAILURE;
}
cout << "num 1 = " << l1 << "; num 2 = " << l2 << endl;
return EXIT_FAILURE;
}