Parse number until comma - c++

I have a format where, in a string, 88 is to be parsed as the number 88 while 8,8 is to be parsed as two 8s. I need to go through the string, and for every ., push a 0 to a vector, and otherwise push the number(s) at the current position to the vector according to the above rule. Zeros will never appear in the input string. I don't want to use yacc or another BNF parser generator; it would be overkill for my situation. What's the easiest way to do this? Here's what I've go so far; it's only partial and doesn't even compile:
for(int i=0; i<line.length(); i++){
if (line[i] == '.')
puzzle.push_back(0);
else
//do weird comma stuff
//push stuff
}
Example:
line = ".1.1,1.11"
puzzle = {0,1,0,1,1,0,11}

Here's a sketch what it looks like you're asking for (not compiled, not tested):
int value;
bool in_number = false;
while (cin.getline(line)) {
for (int i = 0; i < line.length(); ++i)
switch(line[i]) {
case '.':
if (in_number) {
puzzle.push_back(value);
in_number = false;
}
puzzle.push_back(0);
break;
case ',':
if (in_number) {
puzzle.push_back(value);
in_number = false;
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (in_number) {
value *= 10;
value += line[i] - '0';
} else {
in_number = true;
value = line[i] - '0';
}
break;
}
}

For such tasks common solution is to use regexp:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <regex>
#include <vector>
int main(int argc, char* argv[])
{
std::string s(".1.1,1.11");
std::smatch m;
std::regex e("([0-9]+|\\.)[,]?");
std::vector<int> v;
while (std::regex_search(s, m, e)) {
const std::string& d = m[1];
v.push_back(strtol(d.c_str(), 0, 10));
s = m.suffix().str();
}
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
}

AntolyS's answer is probably cleanest, but I went with a modified version of Pete Becker's answer because I'm a noob and there were to many weird things going on with Antoly's:
int value; bool in_number = false;
for(int i=0; i<line.length(); i++){
if (line[i] == '.'){
if (in_number){
puzzle.push_back(value);
in_number = false;
}
puzzle.push_back(0);
}
else if (line[i] == ','){
if (in_number) {
puzzle.push_back(value);
in_number = false;
}
}
else if (line[i] > '0' && line[i] <= '9'){
if (in_number) {
value *= 10;
value += line[i] - '0';
} else {
in_number = true;
value = line[i] - '0';
}
}
}

Related

How to convert char to integer from .txt file in C++

I have a .txt file that contains:
XXXX:YYYY:ABCCCCE.
I need to write a function that reads this section of the .txt file ABCCCCE and finds the sum of the values of those characters.
Assume:
A = 1, B = 2, C = 3, D = 4, E = 5
Here is what I have so far to distinguish the values of each character:
int getComplexity(char theCode)
{
int complexity;
if(theCode == 'A')
{
complexity = 1;
} else if(theCode == 'B')
{
complexity = 2;
} else if(theCode == 'C')
{
complexity = 3;
} else if(theCode == 'D')
{
complexity = 4;
} else if(theCode == 'E')
{
complexity = 5;
}
return complexity;
}
I'm just not sure how I would read from the .txt file and convert the values. I am new to c++ so any help would be greatly appreciated!
I don't know if this is what your after but:
#include <fstream>
#include <numeric>
#include <vector>
using namespace std;
int Return_Complexity(char character)
{
switch (character)
{
case 'a':
return 1;
break;
case 'b':
return 2;
break;
case 'c':
return 3;
break;
case 'd':
return 4;
break;
case 'e':
return 5;
break;
default:
return 0; //Zero indicates that we didn't find what we're looking for
}
}
int main()
{
ifstream file{ "some-file.txt" };
vector<int> values;
char character;
while (file >> character)
{
int result = Return_Complexity(tolower(character));
if (result > 0) //if its a-e
values.push_back(result);
}
int Result = accumulate(values.begin(), values.end(), 1); //add them together
cout << Result;
}
this pushes back all characters found and then sums them up.
If this is not what your after, i will fix this.

warning: control may reach end of non-void function problem

Well, i made RGB To Hex Conversion. My programm in online compiler works pretty well, but on codewars it has a problem "control may reach end of non-void function". What should i do? Should I remove for loop?
using namespace std;
#include <iostream>
#include <string>
int checkForNumber(int input) {
if (input > 255) return 255;
if (input < 0) return 0;
else return input;
}
string check(int input) {
if (input < 10) return to_string(input);
switch (input)
{
case 10:
return "A";
break;
case 11:
return "B";
break;
case 12:
return "C";
break;
case 13:
return "D";
break;
case 14:
return "E";
break;
case 15:
return "F";
break;
}
}
**string YES(int input) {
string m;
char temp;
for (int i = 0; i < 2; i++) {
m += check(input % 16);
input /= 16;**
//problem is somewhere here
}
temp = m[0];
m[0] = m[1];
m[1] = temp;
return m;
}
int main()
{
string output;
ios_base::sync_with_stdio(false);
int r = 148 , g = 0, b = 211;
r = checkForNumber(r);
g = checkForNumber(g);
b = checkForNumber(b);
output += YES(r) + YES(g) + YES(b);
cout << output;
}
The problem is in your check(int input) function -- consider what happens if the value of the input argument is not in the range [10, 15]. I suggest putting in a default: case that returns something appropriate at the bottom of your switch block.

Overwrite the elements in a vector without specifying specific elements

I am making a calculator that accepts multiple operators at once. I have a vector pair that stores the position of operators, and the type of operator. The vector must be updated after each loop as the previous positions are no longer valid due to the result replacing a part of the input string.
I've attempted to use clear() so that it starts from the beginning again, but that results in Expression: vector iterators incompatible. I don't think I can use std::replace since the number of operators in the string changes after each loop. Is there a way to just have it start from the beginning again and overwrite any existing elements?
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::cout << "C++ Calculator" << std::endl;
while (true) //runs forever with loop
{
std::string input;
std::getline(std::cin, input);
//erases whitespace
int inp_length = input.length();
for (int i = inp_length - 1; i >= 0; --i)
{
if (input[i] == ' ')
input.erase(i, 1);
}
std::vector<std::pair<int, char>> oper_pvec;
int vec_pos = 0;
//finds the position of operators and type
for (std::string::iterator i = input.begin(); i != input.end(); ++vec_pos, ++i)
{
switch (*i)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '-'));
break;
}
}
}
//declarations before loop to make sure they're all able to be accessed, will probably change later
int loper_pos = 0; //must be set 0 since there's no left operator at first
int roper_pos;
double lnum; //left number
double rnum; //right number
char loper; //left operator
char roper; //right operator
int pos = -1; //position of loop, needs to be -1 since it increments it each time
std::string holder = input; //copy of input
auto op = oper_pvec.begin();
while (op != oper_pvec.end())
{
op = oper_pvec.begin();
++pos; //position of loop
int key = std::get<0>(*op); //gets first value from vector pair
char val = std::get<1>(*op); //gets second value from vector pair
//gets previous/next vector pairs
std::vector<std::pair<int, char>>::iterator prev_op = oper_pvec.begin();
std::vector<std::pair<int, char>>::iterator next_op = oper_pvec.end();
if (op != oper_pvec.begin()) prev_op = std::prev(op);
if (op != oper_pvec.end()) next_op = std::next(op);
//extracts the value of pairs
if (pos > 0)
{
loper_pos = std::get<0>(*prev_op);
loper = std::get<1>(*prev_op);
}
if (pos == oper_pvec.size() - 1) roper_pos = oper_pvec.size();
else
{
roper_pos = std::get<0>(*next_op);
roper = std::get<1>(*next_op);
}
//replaces numbers and etc with product, only multiplication for now
switch (val)
{
case 'x':
{
int lnum_start = loper_pos + 1;
if (loper_pos == 0) lnum_start = 0;
int lnum_len = key - (loper_pos + 1);
if (loper_pos == 0) lnum_len = key;
lnum = std::stod(input.substr(lnum_start, lnum_len));
int rnum_start = key + 1;
int rnum_len = (roper_pos - 1) - key;
rnum = std::stod(input.substr(rnum_start, rnum_len));
double prod = lnum * rnum;
std::string to_string = std::to_string(prod);
input.replace(loper_pos, roper_pos, to_string);
break;
}
}
/////////////////////////////////problem area////////////////////////////////////////
//clears the vector and then finds the operators again
oper_pvec.clear();
int vpos = 0;
for (std::string::iterator it = input.begin(); it != input.end(); ++vpos, ++it)
{
if (vpos == input.length())
{
vpos = 0;
break;
}
switch (*it)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vpos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '-'));
break;
}
}
}
/////////////////////////////////////////////////////////////////////////////////////
}
//converts to double then prints on screen
double out = std::stod(input);
std::cout << out << std::endl;
}
}
Not really the answer to the title but instead of trying to overwrite the vector I just continued to use clear() and changed the while loop to oper_pvec.size() != 0.
(Full code since I had to change quite a few things to get it to work properly)
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
std::cout << "C++ Calculator" << std::endl;
while (true) //runs forever with loop
{
std::string input;
std::getline(std::cin, input);
//erases whitespace
int inp_length = input.length();
for (int i = inp_length - 1; i >= 0; --i)
{
if (input[i] == ' ')
input.erase(i, 1);
}
std::vector<std::pair<int, char>> oper_pvec;
int vec_pos = 0;
//finds the position of operators and type
for (std::string::iterator i = input.begin(); i != input.end(); ++vec_pos, ++i)
{
switch (*i)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vec_pos, '-'));
break;
}
}
}
//declarations before loop to make sure they're all able to be accessed, will probably change later
int loper_pos = 0; //must be set 0 since there's no left operator at first
int roper_pos;
double lnum; //left number
double rnum; //right number
char loper; //left operator
char roper; //right operator
int pos = -1; //position of loop, needs to be -1 since it increments it each time
std::string holder = input; //copy of input
std::vector<std::pair<int, char>> vec_copy = oper_pvec;
auto op = oper_pvec.begin();
while (oper_pvec.size() != 0)
{
op = oper_pvec.begin();
++pos; //position of loop
int key = std::get<0>(*op); //gets first value from vector pair
char val = std::get<1>(*op); //gets second value from vector pair
//gets previous/next vector pairs
std::vector<std::pair<int, char>>::iterator prev_op = oper_pvec.begin();
std::vector<std::pair<int, char>>::iterator next_op = oper_pvec.end();
if (op != oper_pvec.begin()) prev_op = std::prev(op);
if (op != oper_pvec.end()) next_op = std::next(op);
//extracts the value of pairs
if (pos > 0)
{
loper_pos = std::get<0>(*prev_op);
loper = std::get<1>(*prev_op);
}
if (op == oper_pvec.begin()) loper_pos = 0;
if (oper_pvec.size() == 1) roper_pos = input.length();
else
{
roper_pos = std::get<0>(*next_op);
roper = std::get<1>(*next_op);
}
//replaces numbers and etc with product, only multiplication for now
switch (val)
{
case 'x':
{
int lnum_start = loper_pos + 1;
if (lnum_start == 1) lnum_start = 0;
if (loper_pos > 0)
if (isdigit(input[loper_pos - 1])) lnum_start = 0;
int lnum_len = key - (loper_pos + 1);
if (lnum_start == 0)
{
if (key == 1) lnum_len = 1;
else lnum_len = key - 1;
}
lnum = std::stod(input.substr(lnum_start, lnum_len));
int rnum_start = key + 1;
int rnum_len = (roper_pos - 1) - key;
rnum = std::stod(input.substr(rnum_start, rnum_len));
double prod = lnum * rnum;
std::string to_string = std::to_string(prod);
input.replace(loper_pos, roper_pos, to_string);
break;
}
}
//clears the vector and then finds the operators again
oper_pvec.clear();
int vpos = 0;
for (std::string::iterator it = input.begin(); it != input.end(); ++vpos, ++it)
{
if (vpos == input.length())
{
vpos = 0;
break;
}
switch (*it)
{
case 'x':
{
oper_pvec.push_back(std::pair<int, char>(vpos, 'x'));
break;
}
case '/':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '/'));
break;
}
case '+':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '+'));
break;
}
case '-':
{
oper_pvec.push_back(std::pair<int, char>(vpos, '-'));
break;
}
}
}
}
//converts to double then prints on screen
double out = std::stod(input);
std::cout << out << std::endl;
}
}

Why doesn't a While Loop inside a For Loop work in my program?

I should make a program where I should print out the short (compressed word), having the long one. For an example: 8S2Q3R is short for SSSSSSSSQQRRR. Now, I made this short program, which doesn't work (loops endlessly). I'm pretty sure I shouldn't be putting a while-loop inside a for-loop, but I'm not sure how exactly to fix this.
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char word[80];
cin >> word;
int length = strlen(word);
int counter = 1;
for (int i = 0; i < length; i++) {{
while (word[i] == word[i + 1]) {
counter++;
}
cout << counter << word[i];
}
return 0;
}
Similarly, if I have to print out a long word having a short one, I made a program which also doesn't work (output is a bunch of hieroglyphs):
#include <iostream>
#include <string.h>
using namespace std;
int number = 0;
bool Number(char c) {
switch(c) {
case '1':
number = 1;
return true;
break;
case '2':
number = 2;
return true;
break;
case '3':
number = 3;
return true;
break;
case '4':
number = 4;
return true;
break;
case '5':
number = 5;
return true;
break;
case '6':
number = 6;
return true;
break;
case '7':
number = 7;
return true;
break;
case '8':
number = 8;
return true;
break;
case '9':
number = 9;
return true;
break;
case '0':
number = 0;
return true;
break;
default:
return false;
}
}
int main()
{
char word[80];
cin >> word;
int length = strlen(word);
int counter = 1;
for (int i = 0; i < length; i++) {
if (Number(word[i])) {
for (int j = 0; j < number; i++) {
cout << word[i];
}
} else {
continue;
}
}
return 0;
}
Not sure if this is what you want but I assumed that there can be 2 or more consecutive digits and only one character after the digits.
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int
main ()
{
char word[80];
char out[128];
char temp[10];
cin >> word;
int len = strlen (word);
int index = 0;
int numindex = 0;
int count;
while (index < len) {
while (word[index] >= '0' && word[index] <= '9') {
temp[numindex++] = word[index++];
}
temp[numindex] = 0;
count = atoi (temp);
numindex = 0;
char ch = word[index++];
for (int i = 0; i < count; i++) {
out[i] = ch;
}
out[count] = 0;
cout << out;
}
return 0;
}

String.length() returns a wrong result

I'm trying to write a program in C++ to normalize a string by converting every uppercase letter into lowercase.
Also, I'm dealing with some special characters since my native language is Spanish, and it is supposed to work with Spanish words, too. For some reason, I was returning a string from my normalize() but couldn't cout it.
So, to make it work, I had to print it as if it was an array, and it worked for most cases because I was using word.length(). However, when I switched to result.length() it was giving me a straight 0 every time. I can't figure out what the problem is, maybe I have to add a null terminator to result so length() can do its work?
#include <iostream>
#include <string>
using namespace std;
string normalize(string word)
{
string result;
int j = 0;
for (int i = 0; i < word.length(); i++)
{
if (word[i] >= 'A' && word[i] <= 'Z')
{
result[j] = tolower(word[i]);
}
else
{
if (word[i] == char(0xC3))
{
switch (word[i + 1])
{
case char(0xA1):
word[j] = 'a';
break;
case char(0xA9):
word[j] = 'e';
break;
case char(0xAD):
word[j] = 'i';
break;
case char(0xB3):
word[j] = 'o';
break;
case char(0xBA):
word[j] = 'u';
break;
case char(0xBC):
word[j] = 'u';
break;
case char(0x81):
word[j] = 'a';
break;
case char(0x89):
word[j] = 'e';
break;
case char(0x8D):
word[j] = 'i';
break;
case char(0x93):
word[j] = 'o';
break;
case char(0x9A):
word[j] = 'u';
break;
case char(0x9C):
word[j] = 'u';
break;
}
i++;
}
else
result[j] = result[i];
}
j++;
}
return result;
}
int main()
{
int counter = 0;
string word;
while (cin >> word)
{
counter++;
string result = normalize(word);
cout << counter << ". ";
for (int i = 0; i < result.length(); i++)
{
cout << result[i];
}
cout << endl;
}
return 0;
}
normalize() expects a UTF-8 string as input. When handling the "special" characters, you are not writing any characters to result at all, you are writing them back to word instead. Even if you were writing them to result, you are not writing them correctly, as you haven't allocated any memory for result before populating it. You should be using operator+= instead of operator[], or at least call result.resize(word.length()) before entering the loop, and then call result.resize(j) after exiting the loop.
Try something more like this instead:
string normalize(const string &word)
{
string result;
result.reserve(word.length());
int i = 0;
while (i < word.length())
{
char ch = word[i++];
if (ch <= 0x7F)
{
result += (char) tolower(ch);
}
else if ((ch == 0xC3) && (i < word.length()))
{
ch = word[i++];
switch (ch)
{
case 0x81:
case 0xA1:
result += 'a';
break;
case 0x89:
case 0xA9:
result += 'e';
break;
case 0x8D:
case 0xAD:
result += 'i';
break;
case 0x93:
case 0xB3:
result += 'o';
break;
case 0x9A:
case 0x9C:
case 0xBA:
case 0xBC:
result += 'u';
break;
default:
result += '?';
break;
}
}
else
result += '?';
}
return result;
}
However, that being said, what normalize() is doing is not the correct way to handle UTF-8 in general. What you are looking for is called "transliteration", which is much more involved than your simple implementation. You should use a dedicated Unicode library like ICONV or ICU instead. But if you are going to do it manually, at least decode and process the UTF-8 properly, eg:
string normalize(const string &word)
{
// TODO: normalize word using Unicode Normalization Form NFC first...
string result;
result.reserve(word.length());
int i = 0;
while (i < word.length())
{
uint8_t ch = (uint8_t) word[i++];
int32_t cp;
int count;
if ((ch & 0x80) == 0x00)
{
cp = (ch & 0x7F);
count = 0;
}
else if ((ch & 0xE0) == 0xC0)
{
cp = ch & 0x1F;
count = 1;
}
else if ((ch & 0xF0) == 0xE0)
{
cp = ch & 0x0F;
count = 2;
}
else if ((ch & 0xF8) == 0xF0)
{
cp = ch & 0x07;
count = 3;
}
else
{
result += '?';
continue;
}
bool ok = ((i+count) <= word.length());
for (int j = 0; (ok) && (j < count); ++j)
{
ch = (uint8_t) word[i++];
if ((ch & 0xC0) != 0x80)
{
ok = false;
break;
}
cp <<= 6;
cp |= (ch & 0x3F);
}
if (!ok)
{
result += '?';
}
else
{
switch (cp)
{
case 0x00C1:
case 0x00E1:
result += 'a';
break;
case 0x00C9:
case 0x00E9:
result += 'e';
break;
case 0x00CD:
case 0x00ED:
result += 'i';
break;
case 0x00D3:
case 0x00F3:
result += 'o';
break;
case 0x00DA:
case 0x00DC:
case 0x00FA:
case 0x00FC:
result += 'u';
break;
default:
if (cp <= 0x007F)
result += (char) tolower(cp);
else
result += '?';
break;
}
}
}
return result;
}
Alternatively, if you are using C++11 or later:
string normalize(const string &word)
{
u32string u32 = codecvt_utf8<char32_t>{}.from_bytes(word);
// TODO: normalize u32 using Unicode Normalization Form NFC first...
string result;
result.reserve(u32.length());
for (char32_t cp : u32)
{
switch (cp)
{
case 0x00C1:
case 0x00E1:
result += 'a';
break;
case 0x00C9:
case 0x00E9:
result += 'e';
break;
case 0x00CD:
case 0x00ED:
result += 'i';
break;
case 0x00D3:
case 0x00F3:
result += 'o';
break;
case 0x00DA:
case 0x00DC:
case 0x00FA:
case 0x00FC:
result += 'u';
break;
default:
if (cp <= 0x007F)
result += (char) tolower(cp);
else
result += '?';
break;
}
}
return result;
}