String.length() returns a wrong result - c++

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;
}

Related

Decimal to hexadecimal conversion program not working?? Don't know why?

below is c++ program for decimal to hexadecimal conversion!!
// decimal to hexadecimal conversion
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
string d2h(int n) {
string s, t;
int i = 0;
while (n >= 1) {
t[i] = n % 16;
switch (t[i]) {
case 10:
t[i] = 'A';
break;
case 11:
t[i] = 'B';
break;
case 12:
t[i] = 'C';
break;
case 13:
t[i] = 'D';
break;
case 14:
t[i] = 'E';
break;
case 15:
t[i] = 'F';
break;
default:
break;
}
s[i] = t[i];
n /= 16;
i++;
}
return s;
}
int main() {
int n;
cin >> n;
cout << d2h(n);
return 0;
}
I am getting nothing as output!!
PS C:\Users\anmol\Desktop\c++projectwork> g++ .\dec2hexadec.cpp
PS C:\Users\anmol\Desktop\c++projectwork> ./a
479
PS C:\Users\anmol\Desktop\c++projectwork>
What should i change??
You are not allocating space in s or t for memory. Use s.push_back() instead of s[i].
You'll probably need to reverse the string as well.
t[i] = n % 16; This does not assign the character '0', but rather the number 0. Why don't you just create 16 cases in your switch statement? Or use the ASCII quirk '0' + (n % 16).
// decimal to hexadecimal conversion
#include <iostream>
#include <math.h>
#include <string>
using namespace std;
string d2h(int n) {
string s, t;
string Sign;
int i = 0;
// n is equal to 0? <0 or >0?
if (n == 0){
return "0";
}
if (n < 0){
Sign = "-";
n *= -1;
}
while (n ) {
t.push_back(n % 16) ;
switch (t[i]) {
case 0:
t[i] = '0';
break;
case 1:
t[i] = '1';
break;
case 2:
t[i] = '2';
break;
case 3:
t[i] = '3';
break;
case 4:
t[i] = '4';
break;
case 5:
t[i] = '5';
break;
case 6:
t[i] = '6';
break;
case 7:
t[i] = '7';
break;
case 8:
t[i] = '8';
break;
case 9:
t[i] = '9';
break;
case 10:
t[i] = 'A';
break;
case 11:
t[i] = 'B';
break;
case 12:
t[i] = 'C';
break;
case 13:
t[i] = 'D';
break;
case 14:
t[i] = 'E';
break;
case 15:
t[i] = 'F';
break;
default:
break;
}
s.push_back(t[i]);
n /= 16;
i++;
}
reverse(s.begin(), s.end());
return Sign+s;
}
int main() {
int n;
cin >> n;
cout << d2h(n);
return 0;
}

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;
}
}

Stuck in while loop when change to c++

i'm trying to rewrite this code in c++ which create a bitcoin mini private key
using System;
using System.Text;
using Org.BouncyCastle.Security;
public string CreateRandomMinikey(){
string keytotry = "S6c56bnXQiBjk9mqSYE7ykVQ7NzrQA";
char[] chars = keytotry.ToCharArray();
char[] charstest = (keytotry + "?").ToCharArray();
while (Util.ComputeSha256(utf8.GetBytes(charstest))[0] != 0) {// hash sha256 the key & check if the first character was '0'
// As long as key doesn't pass typo check, increment it.
for (int i = chars.Length - 1; i >= 0; i--) {
char c = chars[i];
if (c == '9') {
charstest[i] = chars[i] = 'A';
break;
} else if (c == 'H') {
charstest[i] = chars[i] = 'J';
break;
} else if (c == 'N') {
charstest[i] = chars[i] = 'P';
break;
} else if (c == 'Z') {
charstest[i] = chars[i] = 'a';
break;
} else if (c == 'k') {
charstest[i] = chars[i] = 'm';
break;
} else if (c == 'z') {
charstest[i] = chars[i] = '2';
// No break - let loop increment prior character.
} else {
charstest[i] = chars[i] = ++c;
break;
}
}
}
string result = new string(chars);//expect S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy
return result;
}
Here my code when i transform into c++
#include "stdafx.h"
#include <string.h>
#include <iostream>
#include <cstring>
#include "sha256.h"
using namespace std;
int main()
{
string input = "S6c56bnXQiBjk9mqSYE7ykVQ7NzrQA";
string inputcharstest = input+"?";
char * chars = new char[input.size() + 1];
strcpy(chars, input.c_str());//convert input to char array
char * charstest = new char[inputcharstest.size() + 1];
strcpy(charstest, inputcharstest.c_str());// convert inputcharstest to char array
string output = sha256(inputcharstest); //hash sha256 inputcharstest to check typo
while (output[0] != '0') {
for (int i = strlen(chars) - 1; i >= 0; i--) {
char c = chars[i];
if (c == '9') {
charstest[i] = chars[i] = 'A';
break;
}
else if (c == 'H') {
charstest[i] = chars[i] = 'J';
break;
}
else if (c == 'N') {
charstest[i] = chars[i] = 'P';
break;
}
else if (c == 'Z') {
charstest[i] = chars[i] = 'a';
break;
}
else if (c == 'k') {
charstest[i] = chars[i] = 'm';
break;
}
else if (c == 'z') {
charstest[i] = chars[i] = '2';
}
else {
charstest[i] = chars[i] = ++c;
break;
}
}
}
string result = string(chars); //expect S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy
cout << "input('" << input << "'):" << result << endl;
return 0;
}
This is the result i expected
The code was stuck & return blank when i run it on console application, i debug & find out it was stuck in while loop forever. May i ask if there're any problem with this & how do i fix it?
Here you are changing the content of the string every time:
char[] charstest = (keytotry + "?").ToCharArray();
while (Util.ComputeSha256(utf8.GetBytes(charstest))[0] != 0) {
charstest changes in every run through the loop, so the test in the while can terminate at some point. In the C++ code, however, you're not doing that:
string output = sha256(inputcharstest); //hash sha256 inputcharstest to check typo
while (output[0] != '0') {
Here, you're only doing the hash once before the loop, and then not again in the loop. The loop doesn't change output at all and neither does it break out of the while, so if output[0] != '0' is true the first time, it will always be true, thus the infinite loop.

Parse number until comma

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';
}
}
}

c++ Converting roman numerals to decimals

This program is a part of an exam I just took, that I had to write. I only got this far and couldn't get anywhere. Here is the prompt:"Write a Test Function toDecimal() that converts a roman numeral such as MMLXVII to it's decimal number representation. Use Main() to test the function. The toDecimal() function should have 2 arguments, the string array of roman numerals and a helper function. This helper function will return the numeric value of each of the letters used in roman numbers. Then convert the string arguments as so: Look at the first two characters,if the first is larger, convert the first and add it to the summation, then call the conversion function again with the second value and add both. IF the first character is lesser than the second subtract the first from the second, and add the result to the conversion of the string. without validation it will also convert strings like "IC". VAlidate the string arguement, if there is an error, call the error processing function. Provide at least two error processing functions and test toDecimal() with each. One could be adking the user to correct, the other may correct it."
I,X,C,M cannot be repeated more than 3 times in succession, D,L,V, can never be repeated in succession.I can only be subtracted from V and X,X can only be subtracted from L and C, C can only be subtracted from D and M. V, L, and D can never be subtracted.
I've lost about 2 days worth of sleep on this, tried writing it hundreds of different ways using and breaking the rules. This is the closest I've got on it.
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;
bool checker(string roman);
// Adds each value of the roman numeral together
int toDecimal(string, bool* (*function)(string));
int convert(string roman, int i);
int main(){
string roman;
cout << "This program takes a roman numeral the user enters then converts it to decimal notation." << endl;
cout << "Enter a roman numeral: ";
cin >> roman;
transform(roman.begin(), roman.end(), roman.begin(), toupper);
cout << roman << " is equal to " << toDecimal(roman, *checker(roman)) << endl;
}
bool checker(string roman){
int length = roman.length();
for (int count = 0; count < length; count++){
string sub = roman.substr(count, count);
if(sub != "I" || sub != "V" || sub != "X" || sub != "L" || sub != "C" || sub != "D" || sub != "M"){
cout << "Error. Try Again"<< endl;
return false;
}
else if(convert(roman, count) == convert(roman, count-1) && convert(roman, count) == convert(roman, count+1)){
if (convert(roman,count) == 1 || convert(roman,count) == 10 || convert(roman,count) == 100 || convert(roman,count) == 1000)
if(convert(roman, count-1) == convert(roman, count-2) || convert(roman, count+1) == convert(roman, count+2)){
cout << "Error Try again" << endl;
return false;
}
else if (convert(roman,count) == 5 || convert(roman,count) == 50 || convert(roman,count) == 500){
cout << "Error Try again" << endl;
return false;
}
else return true;
}
}
return true;
}
int toDecimal(string s, bool*(checker) (string roman)){
/**map<char, int> roman;
roman['M'] = 1000;
roman['D'] = 500;
roman['C'] = 100;
roman['L'] = 50;
roman['X'] = 10;
roman['V'] = 5;
roman['I'] = 1;*/
checker(s);
int res = 0;
for (int i = 0; i < s.length() - 1; ++i){
int num = convert(s,i);
res += num;
/**if (roman[s[i]] < roman[s[i+1]])
res -= roman[s[i]];
else
res += roman[s[i]];
}
res += roman[s[s.size()-1]];*/}
return res;
}
int convert(string roman, int i){
enum romans {I = 1, V = 5, X = 10, L = 50, C = 100, D = 500, M = 1000};
int num = 0;
char c = roman[0];
switch(c){
case 'M':
num = M; break;
case 'D':
if(i + 1 != roman.size() && roman[i+1] == 'M'){
num = M - D;break;
}
else
num = D; break;
case 'C':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D'){
if(roman[i+1] == 'M') num = M - C; break;
if(roman[i+1] == 'D') num = D - C; break;
}
else
num = C; break;
case 'L':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'){
if(roman[i+1] == 'M') num = M - L; break;
if(roman[i+1] == 'D') num = D - L; break;
if(roman[i+1] == 'C') num = C - L; break;
}
else
num = L; break;
case 'X':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'|| roman[i+1] == 'L'){
if(roman[i+1] == 'M') num = M - X; break;
if(roman[i+1] == 'D') num = D - X; break;
if(roman[i+1] == 'C') num = C - X; break;
if(roman[i+1] == 'L') num = C - X; break;
}
num = X; break;
case 'V':
if(i + 1 != roman.size() && roman[i+1] == 'M' || roman[i+1] == 'D' || roman[i+1] == 'C'|| roman[i+1] == 'L' || roman[i+1] == 'X'){
if(roman[i+1] == 'M') num = M - V; break;
if(roman[i+1] == 'D') num = D - V; break;
if(roman[i+1] == 'C') num = C - V; break;
if(roman[i+1] == 'L') num = L - V; break;
if(roman[i+1] == 'X') num = X - V; break;
}
num = V; break;
case 'I':
if ( i + 1 != roman.size() && roman[i + 1] != 'I'){
if(roman[i+1] == 'M') num = M - I; break;
if(roman[i+1] == 'D') num = D - I; break;
if(roman[i+1] == 'C') num = C - I; break;
if(roman[i+1] == 'L') num = L - I; break;
if(roman[i+1] == 'X') num = X - I; break;
}
num =1; break;
}
return num;
}
** I have added the help of people on here. This is an edit to show an progress/congress.
This is the code that I use to convert Roman (smaller than 3999) to Integer. You may check if it works for larger numbers.
int romanToInt(string s) {
map<char, int> roman;
roman['M'] = 1000;
roman['D'] = 500;
roman['C'] = 100;
roman['L'] = 50;
roman['X'] = 10;
roman['V'] = 5;
roman['I'] = 1;
int res = 0;
for (int i = 0; i < s.size() - 1; ++i)
{
if (roman[s[i]] < roman[s[i+1]])
res -= roman[s[i]];
else
res += roman[s[i]];
}
res += roman[s[s.size()-1]];
return res;
}
Hope this could help you.
The solution provided by Annie Kim works, but it uses a std::map, querying it several times for the same character, and I fail to see a reason for it.
int convert_roman_digit(char d)
{
switch (d)
{
case 'M': return 1000;
case 'D': return 500;
case 'C': return 100;
case 'L': return 50;
case 'X': return 10;
case 'V': return 5;
case 'I': return 1;
default: throw std::invalid_argument("Invalid digit");
}
}
int roman_to_int(const std::string& roman)
{
int result = 0, last_added = 0;
for (auto it = roman.rbegin(); it != roman.rend(); ++it)
{
const int value = convert_roman_digit(*it);
if (value >= last_added)
{
result += value;
last_added = value;
}
else
{
result -= value;
}
}
return result;
}
Caveat: the function happily accepts some invalid inputs (e.g. IMM) including "negative" numbers (e.g. IIIIIIIIIIIIIX), there are no overflow checks, and it throws. Feel free to improve it.
int romanToInt(string s)
{
unordered_map<char, int> roman;
roman['I'] = 1;
roman['V'] = 5;
roman['X'] = 10;
roman['L'] = 50;
roman['C'] = 100;
roman['D'] = 500;
roman['M'] = 1000;
int num = 0, prev = 0, curr;
for (int i = s.length() - 1; i >= 0; i--)
{
curr = roman[s[i]];
num += (curr >= prev ? 1 : -1) * curr;
prev = curr;
}
return num;
}