How to extract substring by using start and end delimiters in C++ - c++

I have a string from command line input, like this:
string input = cmd_line.get_arg("-i"); // Filepath for offline mode
This looks like a file as below:
input = "../../dataPosition180.csv"
I want to extract out the 180 and store as an int.
In python, I would just do:
data = int(input.split('Position')[-1].split('.csv')[0])
How do I replicate this in C++?

Here's a (somewhat verbose) solution:
#include <string>
#include <iostream>
using namespace std;
int main() {
string input = "../../dataPosition180.csv";
// We add 8 because we want the position after "Position", which has length 8.
int start = input.rfind("Position") + 8;
int end = input.find(".csv");
int length = end - start;
int part = atoi(input.substr(start, length).c_str());
cout << part << endl;
return 0;
}

#include <string>
#include <regex>
using namespace std;
int getDataPositionId (const string& input){
regex mask ("dataPosition(\\d+).csv");
smatch match;
if (! regex_search(input, match, mask)){
throw runtime_error("invalid input");
}
return std::stoi(match[1].str());
}

Related

i am trying to use getline to read a csv file line by line and separate the data in the file and turn a string into int

I am a beginner and I just need a bit of help on why I getline is showing an error:
this is what I have so far
#include <iostream>
#include <iomanip>
#include <cmath>
#include <fstream>
using namespace std;
const double TAX_RATE = 0.0825;
const int MAX_ITEMS = 1000;
const int MAX_TRANSACTIONS = 100;
int main(int argc, char const *argv[]){
string fname = "";
int itemCnt = 0, start = 0, end = 0;
int ids[MAX_ITEMS], qtys[MAX_ITEMS];
double costs[MAX_ITEMS], subtotals[MAX_TRANSACTIONS],
taxes[MAX_TRANSACTIONS], totals[MAX_TRANSACTIONS];
string names[MAX_ITEMS], paymentTypes[MAX_ITEMS], payments[MAX_ITEMS];
ifstream iFile;
if ( argc != 2 ) {
cout<<"usage: "<< argv[0]<< " <file name>" <<endl;
return 0;
} else {
iFile.open(argv[1]);
}
if (!iFile) {
cout<<"Error: Invalid file name"<<endl;
cin.clear();
}
while (!iFile.eof())
{
getline(iFile,str); //this isn't working
int commaLoc = str.find(',');
ids[itemCnt]= str.substr(0,commaLoc);
str = str.substr(commaLoc +1, str.length());
//string to int I'm not sure how to do I know its something with stoi() but not sure how to format it
}
return 0;
}
I am able to get the file to open but I'm not sure why getline isn't working it keeps saying something like
no instance of overload function
My csv file looks like:
1,Laptop,799.99,1,cash,1100
I need it to read the first number and because Its a string i don't know how to save it as an int
Multiple errors. First there is nothing called 'str' in your program. I will guess its just a string used as a temp buffer
do not do this (!File.eof) it doesnt do what you think.
while (iFile)
{
string str; <<<<<==== added
getline(iFile,str); //this isn't working <<<===is now
int commaLoc = str.find(',');
Next this line doesnt work because ids are ints and substring returns a string.
// ids[itemCnt]= str.substr(0,commaLoc);
ids[itemCnt]= stoi(str.substr(0,commaLoc)); <<<<==== fixed
str = str.substr(commaLoc +1, str.length());
}
I strongly recommend you use std::vector instead of c-style fixed size arrays. Takes 5 minutes to learn how to use them and they have huge benefits. If you must use fixed size arrays use std::array instead of c-style
You can read a string and try to convert it to a number in different ways. For example, since C++17, you can use from_chars. One of its overloads:
Receives a pair of begin and end char pointers, and an int variable,
tries to parse an int number, and
and returns the parsed number, together with a pointer to the first character that wasn't part of the match.
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) { /* do something with i */} else { /* error */ }
[Demo]
Full code (using a istrinstream instead of a ifstream):
#include <charconv> // from_chars
#include <iomanip>
#include <iostream>
#include <sstream> // istringstream
#include <system_error> // errc
constinit const int MAX_ITEMS = 10;
int main() {
std::istringstream iss{
"1,Laptop,799.99,1,cash,1100\n"
"2,PC,688.88,2,card,1101\n"
"blah,Keyboard,39.00,3,cash,1102"
};
size_t itemCnt{};
int ids[MAX_ITEMS]{};
std::string str{};
while (std::getline(iss, str)) {
// Parse counter
int i{};
auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), i);
if (ec == std::errc{}) {
ids[itemCnt] = i;
// Remaining string
std::string remaining_string{ str.substr(ptr - str.data() + 1) };
std::cout << ids[itemCnt] << ", " << remaining_string << "\n";
}
else {
std::cout << "Error: invalid counter.\n";
}
++itemCnt;
}
}
// Outputs:
//
// 1, Laptop,799.99,1,cash,1100
// 2, PC,688.88,2,card,1101
// Error: invalid counter.

How can I go through a string entered by the user and return the same string 7 characters ascii forward?

For example, if I introduce hello, the program through the ASCII table will return the same but character 7 letters forward: 'hello' -> 'olssu'.
Thanks in advance.
I have tried this but it obviously doesn't work:
#include <iostream>
using namespace std;
int main()
{
int asciiValue=65;
string pass;
cout<<"introduce la contraseƱa"<<endl;
cin>>pass;
char character = char(asciiValue+7);
for(int a=0;a<pass.length();a++){
cout<<character;
cout<<pass[a];
}
return 0;
}
In your example, 'hello' would become 'olssv' moving ahead by 7 positions.
The code for achieving this would look like this:
#include <iostream>
#include <string>
using namespace std;
int main() {
string inputString;
cin>>inputString;
// iterate through the string
for(int i=0; i< inputString.length(); i++) {
// for each character, get its ASCII value
// in C++, if you simply parse a character to an int
// you will get the ASCII value
int asciiValue = int(inputString[i]);
// add 7 to the ascii value and print it as a char
cout<<char(asciiValue + 7);
}
return 0;
}

Parsing a text file C++ from specific line to specific line

so, I`m new to c++. My task is parse text file that look like:
RE002%%
RE002%%
RE002%%
RE002%%
RE002%%
RE004%on%
$GPGGA,124749.80,5543.3227107,N,03739.1366738,E,1,08,1.11,147.9635,M,14.4298,M,,*5C
$GPGSV,3,1,10,27,13,078,43,05,31,307,48,16,24,042,43,02,10,267,43*7D
$GPGSV,3,2,10,26,03,031,36,07,75,215,51,09,57,121,53,30,40,234,50*76
$GPGSV,3,3,10,23,29,117,46,04,36,114,46*70
$GPGGA,124749.90,5543.3227105,N,03739.1366737,E,1,08,1.11,147.9664,M,14.4298,M,,*54
RE005%off%
And it continuous for few thousand lines.I need to find where it writes RE004%on% and start processing lines in this loop until it finds RE005%off% and do it over and over until it file ends. I was trying to do it with line.find, but I am pretty sure it is wrong way to solve this problem
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
using namespace std;
int main() {
string line, dollar, star, Checksum;
float *t0 = NULL;
int tount = 0;
int k;
ifstream logs_("C:/Users/Olya/Desktop/LogGLO.txt");
ofstream tout("outLOGTime.txt");
ofstream pout("outLOGPot.txt");
if (logs_.is_open())
{
while(getline(logs_,line))
{
line.find("RE004%on%")
k = 0;
if
dollar = line.find_first_of('$');
star = line.find_first_of('*');
Checksum = line.substr(line, dollar, star - dollar);
for (size_t i = 0; i < Checksum.size(); i++)
{
}
if (line.substr(0,6) == "$GPGSV")
{
for (size_t i = 0, N = 7; i < line.size(); i++)
{
if (line[i] == ',') k++;
if(k == N)
{
pout << line.substr(i+1,2) << endl;
if ((N += 4) > 19) break;
}
}
}
logs_.close();
}
}
else
cout<<"File is not open"<<'\n';
tout.close();
pout.close();
return 0;
}
Unfortunately your description si very unclear. Also by reading your code, I can really not understand, what you intent to do. And you edited your text and changed description. Not so easy for me
But, I made an educated guess. . .
I read all data between your given delimiters, validate the checksum and split the lines into tokens. Finally I store all the lines-with-Tokens in a vector. Then I filter for a specific value and output a column.
Please stude and try to understand. It is not so complicated.
Thank you
#include <iostream>
#include <regex>
#include <vector>
#include <iterator>
#include <string>
#include <utility>
#include <algorithm>
#include <functional>
#include <numeric>
#include <fstream>
const std::regex re{ R"(\$(.*)\*[abcdefABCDEF\d]{2})" };
const std::regex delimiter{ "," };
using Tokens = std::vector<std::string>;
std::tuple<bool, Tokens> checkString(const std::string& str) {
// Return value of the function. Assume that string is not ok
std::tuple<bool, std::vector<std::string>> result(false, {});
// We want to find a string in the given format
std::smatch sm{};
if (std::regex_match(str, sm, re)) {
// OK, found. Validate checksum
if (std::string s = sm[1];std::stoul(str.substr(str.size() - 2), nullptr, 16) == std::accumulate(s.begin(), s.end(), 0U, std::bit_xor<unsigned char>())) {
// Tokenize string
Tokens tokens(std::sregex_token_iterator(str.begin(), str.end(), delimiter, -1), {});
// Build return value
result = std::make_tuple(true, std::move(tokens));
}
}
return result;
}
int main() {
std::vector<Tokens> csvData{};
// Open file and check if it is open
if (std::ifstream logs("r:\\LogGLO.txt"); logs) {
// Shall we process text lines or not
bool processingActive{ false };
// Read all lines of files
for (std::string line{}; std::getline(logs, line);) {
// Check, if we should start or stio processing of the lines
if (line.substr(0, 9) == std::string("RE004%on%")) processingActive = true;
if (line.substr(0, 10) == std::string("RE005%off%")) processingActive = false;
// Check and read csv data
if (processingActive) {
const auto [ok, data] = checkString(line);
if (ok) csvData.push_back(std::move(data));
}
}
}
// So, now we have read all csv data
// Show eight column of GPGSV data
for (const Tokens& t : csvData)
if (t[0] == "$GPGSV")
std::cout << t[7] << "\n";
return 0;
}

Create string of specific length in C++

For my class, I have to take three strings, then center them.
Here's a link to the problem, and no, I'm not asking for the answer to the problem!
http://www.hpcodewars.org/past/cw3/problems/Prog05.htm
I have everything I need, but I need to create a string of "*" with a specific length. In this case, it needs to be 21 characters long of asterisks, and I don't know how to create that.
I mean, yeah, I can do
string test = "********************"
but it needs to be a different length as it changes.
I have a variable set to how long the string needs to be, but I need to know how to create a string with a specific length, then add in the asterisks.
Code so far:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string line;
string lines[2];
int x = 0;
int maxLength;
ifstream myfile ("example.txt");
if (myfile.is_open()) // opening file, setting the strings in the input stream to a variable to use at a later time
{
while ( getline (myfile,line) )
{
lines[x] = line;
x++;
}
myfile.close();
}
if(lines[0].length() > lines[1].length()) //finding the max length;
{
maxLength = lines[0].length();
}else
{
maxLength = lines[1].length();
}
if(lines[2].length() > maxLength)
{
maxLength = lines[2].length();
}
maxLength = maxLength + 4;
cout<<maxLength<<endl;
return 0;
}
It's much simpler than you think. std::string has a constructor just for this purpose:
#include <string>
#include <iostream>
int main()
{
std::string s(21, '*');
std::cout << s << std::endl;
return 0;
}
Output:
*********************

Counting occurrences of word in vector of characters

I have written a program to store a text file in vector of characters .
#include<iostream>
#include<fstream>
#include <algorithm>
#include<vector>
using namespace std;
int main()
{
vector<char> vec;
ifstream file("text.txt");
if(!file.eof() && !file.fail())
{
file.seekg(0, std::ios_base::end);
std::streampos fileSize = file.tellg();
vec.resize(fileSize);
file.seekg(0, std::ios_base::beg);
file.read(&vec[0], fileSize);
}
int c = count(vec.begin(), vec.end(), 'U');
cout << c;
return 0;
}
I want to count occurrence of "USER" in the text file , but using count i can only count number of characters . How can i count number of occurrences of "USER" in the vector of character?
For example
text.txt
USERABRUSER#$$* 34 USER ABC RR IERUSER
Then the count of "USER" is 4. Words can only be in uppercase.
std::string has a find member function that will find an occurrence of one string inside another. You can use that to count occurrences something like this:
size_t count(std::string const &haystack, std::string const &needle) {
auto occurrences = 0;
auto len = needle.size();
auto pos = 0;
while (std::string::npos != (pos = haystack.find(needle, pos))) {
++occurrences;
pos += len;
}
return occurrences;
}
For example:
int main() {
std::string input{ "USERABRUSER#$$* 34 USER ABC RR IERUSER" };
std::cout << count(input, "USER");
}
...produces an output of 4.
This is how I would do it:
#include <fstream>
#include <sstream>
#include <iostream>
#include <unordered_map>
#include <string>
using namespace std;
int main() {
unordered_map<string, size_t> data;
string line;
ifstream file("text.txt");
while (getline(file, line)) {
istringstream is(line);
string word;
while (is >> word) {
++data[word];
}
}
cout << data["USER"] << endl;
return 0;
}
Let's try again. Once again, a vector isn't necessary. This is what I would consider to be the most C++ idiomatic way. It uses std::string's find() method to repeatedly find the substring in order until the end of the string is reached.
#include <fstream>
#include <iostream>
#include <string>
int main() {
// Read entire file into a single string.
std::ifstream file_stream("text.txt");
std::string file_contents(std::istreambuf_iterator<char>(file_stream),
std::istreambuf_iterator<char>());
unsigned count = 0;
std::string substr = "USER";
for (size_t i = file_contents.find(substr); i != std::string::npos;
i = str.find(substr, i + substr.length())) {
++count;
}
}