Testing if the string meets the Right format C++ - c++

I am currently trying to test if a read in string matches the following format, without the use of regex.
The format the code should be in, is:
Supplier Reference: XXXXXXX
Date & Time: XXXX
Name of Device: XXXXX
Priority: X
IP Address: XXXXXXXXXXXXXXXXXXXX
Event ID: XXXXXX
Description of Event: XXXXXXXXXXXX
I want the code to have a cout << "Format is incorrect" << endl;.
This is edit, taken out previous attempt and gone back to basics to explain my logic:
using namespace std;
int f;
int main()
{
string mystring;
ifstream myfile ("test.txt");
if (myfile.is_open())
{ while (getline (myfile,mystring))
{
//searches the text entered//
string search;
size_t pos;
{
//searches the text for the Date entry//
{
search = "Supplier Reference:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f=f-1;
}
else
{
++f;
}
}
}
{
search = "Date & Time:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Name of Device:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Priority:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "IP Address";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Event ID:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
{
search = "Description of Event:";
pos = mystring.find(search);
{
if (pos != string::npos)
{
cout<<mystring<<endl;
f = f - 1;
}
else
{
++f;
}
}
}
}
}
{
if (f>35)
cout << f << "Field is missing, Ticket is formatted incorrectly" << endl;
}
}
system ("pause");
return 0;
}
I know the code is incredibly repetitive. Cheep and Cheerful is what I'm aiming for.
I was hoping someone could let me know how to test for the order of the lines?

One way to solve this is to read seven lines (one for each line of data). If a line is empty, then discard it and don't count it.
Then for each line, you split it into two strings at the colon ':'. Use the left part (e.g. "Supplier Reference") as the key into a std::map with the right part as data.
Then just loop over the map and make sure that each key matches the needed keys from the file. If a key is missing, or an unknown key is in the map (or if there are not enough lines when reading from the file) your have a format error.

Related

how to split a sentence into strings using recursion in c++

string strings[10];
void split(string s){
int curr=0,start=0,end=0,i=0;
while(i<=len(s)){
if(s[i]==' ' or i == len(s)){
end = i;
string sub;
sub.append(s,start,end-start);
strings[curr] = sub;
start = end + 1;
curr += 1 ;
}
i++;
}
}
for example if the input is " computer laptop screen desktop mouse " then the output string should be:
computer
laptop
screen
desktop
mouse
I have successfully tried using loops but failed using recursion,
can anyone help me solve split() using recursion.
Thank you
This solution assumes you want only words from the string to enter your array and that you want to split on some predetermined string delimiter like <space>" " or <double-dash>"--".
If you need to keep the void function signature, here is one:
void split_rec(string str_array[], size_t arr_index,
string s, string delimiter) {
if (s == "") {
return;
}
size_t str_index = s.find(delimiter);
string word = s.substr(0, str_index);
if (word != "") {
str_array[arr_index++] = word;
}
// find type functions return string::npos if they don't find.
str_index = s.find_first_not_of(delimiter, str_index);
if (str_index == string::npos) {
return;
}
return split_rec(str_array, arr_index, s.substr(str_index), delimiter);
}
But I would recommend returning the size of the array so you communicate what the function is doing more accurately. Like this:
size_t split_rec(string str_array[], size_t arr_index,
string s, string delimiter) {
if (s == "") {
return arr_index;
}
size_t str_index = s.find(delimiter);
string word = s.substr(0, str_index);
if (word != "") {
str_array[arr_index++] = word;
}
str_index = s.find_first_not_of(delimiter, str_index);
if (str_index == string::npos) {
return arr_index;
}
return split_rec(str_array, arr_index, s.substr(str_index), delimiter);
}
Then the call is like this:
string strings[10];
// I left some extra spaces in this string.
string str = " computer laptop screen desktop mouse ";
size_t strings_len = split_rec(strings, 0, str, " ");
cout << "Array is length " << strings_len << endl;
for (size_t i = 0; i < strings_len; i++) {
cout << strings[i] << endl;
}
Array is length 5
computer
laptop
screen
desktop
mouse

Storing in a vector based on certain criteria

Good morning Stack Overflow,
I am having trouble getting some key-value pairs to store in a vector only if they meet certain criteria which I will explain below. Everything is working in my program so far except this.
To begin here is my main:
int main()
{
Records passports;
std::string filename = "test.txt";
std::ifstream inFile(filename);
std::string liNe;
while (!inFile.eof()) {
getline(inFile, liNe);
if (liNe.length() == 0) passports.keyHolder2.push_back(" ");
std::istringstream ss(liNe);
while (ss >> liNe) {
passports.keyHolder2.push_back(liNe);
}
}
inFile.close();
cout << isinRangeTest(passports) << endl;
}
Here is my structure to store all my vectors:
struct Records {
std::vector<string> keyHolder;
std::vector<string> validKeys;
std::vector<string> keyHolder2;
std::vector<string> validKeys2;
};
Here is my function to determine if they have the prefixes like "ecl, byr or iyr" and others:
int validPasstest(Records passports)
{
//cout << passports.keyHolder2.size() << endl;
std::vector<string>::iterator count;
string x, z;
int more = 0;
bool plus = false;
for (count = passports.keyHolder2.begin(); count != passports.keyHolder2.end(); count++) {
//cout << *count << endl;
}
for (int i = 0; i < passports.keyHolder2.size(); i++) {
z = passports.keyHolder2.at(i);
std::size_t found = z.find("byr");
if (found != std::string::npos) more++;
found = z.find("iyr");
if (found != std::string::npos) more++;
found = z.find("hgt");
if (found != std::string::npos) more++;
found = z.find("hcl");
if (found != std::string::npos) more++;
found = z.find("ecl");
if (found != std::string::npos) passports.validKeys2.push_back(z);
found = z.find("pid");
if (found != std::string::npos) more++;
found = z.find("cid");
if (found != std::string::npos) more++;
found = z.find(" ");
if (found != std::string::npos)
{
/*if (more == 7) {
plus++;
}*/
more = 0;
}
}
return plus;
}
Here is my function to display the vector that only has valid key-value pairs:
int isinRangeTest(Records passports)
{
for (int i = 0; i < passports.validKeys2.size(); i++)
{
cout << passports.validKeys2.at(i);
}
return 0;
}
When I try to output validKeys 2 I get a "0" on the output window and nothing else. Here is my textfile and output:
ecl:gry pid:860033327 hcl:#fffffd
byr:1937 iyr:2017 cid:147 hgt:183cm
iyr:2013 ecl:amb cid:350 pid:028048884
hcl:#cfa07d byr:1929
hcl:#ae17e1 iyr:2013 cid:150
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm
hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in cid:230
output
In my function validPasstest, I am trying to add 'z' to the vector validKeys2. It is not working. Any suggestions?

This program is automatically exiting after finishing any one action, why?

My program is exiting after giving one command every time and I am unable to find a logical reason why. I have checked all my loops and if-statements for exit codes but was not able to located any.
the program includes many classes and functions, but here is main:
int main()
{
int local_location = 0;
vector<string>Inventory = { "", "", "" };
unordered_set<string> excl = { "in", "on", "the", "with" };
string word;
array<string, 2> command;
size_t n = 0;
command.at(1) = "";
command.at(0) = "";
while (n < command.size() && cin >> word) {
auto search = excl.find(word);
if (search == excl.end())
command.at(n++) = word;
}
if (command.at(0) == "look") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "get") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "drop") {
look(command.at(1), local_location, Inventory);
}
else if (command.at(0) == "bag") {
bag(Inventory);
}
else if (command.at(0) == "go") {
look(command.at(1), local_location, Inventory);
}
}
Loop over standard input and reset the condition on n after processing the command.
while(cin>>word)
{
auto search = excl.find(word);
if (search == excl.end())
command.at(n++) = word;
if (n== command.size())
{
// process the command
// reset n=0
}
}

Using a loop with std::strcmp to load lots of settings

In my game I keep track of unlocked levels with a vector std::vector<bool> lvlUnlocked_;.
The simple function to save the progress is this:
void save() {
std::stringstream ss;
std::string stringToSave = "";
std::ofstream ofile("./progress.txt");
if (ofile.good()) {
ofile.clear();
for (std::size_t i = 0; i < levelUnlocked_.size(); ++i) {
ss << "lvl" << i << "=" << (lvlUnlocked_.at(i) ? "1" : "0") << std::endl;
}
stringToSave = ss.str();
ofile << stringToSave;
ofile.close();
}
}
This works and is nice since I can just use a loop to dump the info.
Now to the part where I am stuck, the lower part of my load function (see comment in code below):
void load() {
std::ifstream ifile("./progress.txt");
if (ifile.good()) {
int begin;
int end;
std::string line;
std::string stringKey = "";
std::string stringValue = "";
unsigned int result;
while (std::getline(ifile, line)) {
stringKey = "";
stringValue = "";
for (unsigned int i = 0; i < line.length(); i++) {
if (line.at(i) == '=') {
begin = i + 1;
end = line.length();
break;
}
}
for (int i = 0; i < begin - 1; i++) {
stringKey += line.at(i);
}
for (int i = begin; i < end; i++) {
stringValue += line.at(i);
}
result = static_cast<unsigned int>(std::stoi(stringValue));
// usually I now compare the value and act accordingly, like so:
if (std::strcmp(stringKey.c_str(), "lvl0") == 0) {
lvlUnlocked_.at(0) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl1") == 0) {
lvlUnlocked_.at(1) = true;
} else if (std::strcmp(stringKey.c_str(), "lvl2") == 0) {
lvlUnlocked_.at(2) = true;
}
// etc....
}
}
}
This works fine, but...
the problem is that I have 100+ levels and I want it to be dynamic based on the size of my lvlUnlocked_ vector instead of having to type it all like in the code above.
Is there a way to somehow make use of a loop like in my save function to check all levels?
If you parse your key to extract a suitable integer value, you can just index into the bit-vector with that:
while (std::getline(ifile, line)) {
const size_t eq = line.find('=');
if (eq == std::string::npos)
// no equals sign
continue;
auto stringKey = line.substr(0, eq);
auto stringValue = line.substr(eq+1);
if (stringKey.substr(0,3) != "lvl")
// doesn't begin with lvl
continue;
// strip off "lvl"
stringKey = stringKey.substr(3);
size_t end;
std::vector<bool>::size_type index = std::stoi(stringKey, &end);
if (end == 0 || end != stringKey.length())
// not a valid level number
continue;
if (index >= lvlUnlocked_.size())
// out of range
continue;
// Set it :-)
lvlUnlocked_[index] = stringValue=="1";
}
(I've also updated your parsing for "key=value" strings to more idiomatic C++.)

C++, How do get this function to delete the string stored in the array?

I have a delete function that is supposed to delete a string in an array by writing over it with the previous strings.
The look function see's that Overide matches and should be deleted. But the code i wrote for the loop in Delete is not removing that first spot in the array that Overide has taken up, and the output remains unchanged.
Also each phrase after + is being added into the array so four spots are taken in the array, and sorry i could not make that part look better the formatting screwed it up.
int AR::Look(const std::string & word)
{
int result = -1;
for(int i=0; i<counter; ++i)
{
if( con[i].find(word) != std::string::npos)
result = i;
}
return result;
}
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=0; i<counter-1,i++;)
{
con[i]= con[i+1];
}
}
}
AR their
Ar(1);
theirAr + "Overload the +" + " operator as a member function " + "with chaining to add a string " + "to an Arrary object.";
cout<<theirAr<<endl<<endl;
cout<<"testing Delete and Look. <<endl;
theirAr.Delete("XXXXXX");
theirAr.Delete("Overload");
cout<<"Output after Delete and Look called\n";
cout<<theirArray<<endl<<endl;
You are locating the String but only use the value to write an error if it does not appear; if you find the string at pos N you will delete the first string anyway:
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=0;i<counter-1,i++;) <--- Why don't you use loc here???
{
con[i]= con[i+1];
}
}
}
Also, your Look method would be better returning after the first match:
for ... {
if( con[i].find(word) != std::string::npos)
return i;
}
return -1;
Not sure if this is your problem, but shouldn't this be like so?
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout<<"word not found\n";
}
else
{
for(int i=loc;i<counter-1,i++;) // changes in this line
{
con[i]= con[i+1];
}
}
}
Start at where you found the string and start shuffling them backwards. Also, what shortens the array? i.e. drops the last element off. Looks like that is missing too.
Try this instead:
int AR::Look(const std::string & word)
{
for (int i = 0; i < counter; ++i)
{
if (con[i].find(word) != std::string::npos)
return i;
}
return -1;
}
void AR::Delete(const string & word)
{
int loc = Look(word);
if (loc == -1)
{
cout << "word not found" << endl;
}
else
{
for (int i = loc+1; i < counter; ++i)
{
con[i-1] = con[i];
}
--counter;
}
}