using isDigit to find charecters c++ - c++

Trying to figure how I can use isDigit to ignore every character except x, X, e, E within a string. As you can see below I'm doing duodecimal to decimal with x equal to 10 and e equal to 11 (not case sensitive). Having trouble with cin.ignore(). The output should be 36. The string duo should read in the 3 then 0 and negate the rest.
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
using namespace std;
main() {
using str_t = std::string::size_type;
str_t idx = 0;
int decValue = 0;
string duo = "30-something";
while (isspace(duo.at(idx)) && idx < duo.length()) {
idx++;
}
for (std::string::size_type i = 0; i < duo.length(); ++i) {
decValue *= 12;
if (isdigit(duo.at(i))) {
decValue += duo.at(i) - '0';
}
else if (duo.at(i) == 'x' || duo.at(i) == 'X') {
decValue += 10;
}
else if (duo.at(i) == 'e' || duo.at(i) == 'E') {
decValue += 11;
}
/// Program works if this executable line is taken out
else if (!char.isDigit(duo.at(i))) {
cin.ignore();
}
}
cout << decValue << endl;
}

Below I modified your code so that it gives correct answer. For input 30-something it gives 36 as output.
As I understood you want to finish conversion right after 30 i.e. ignore -something. For such behaviour I put a flag stop_on_first_non_digit in my code, if it is true then it finishes on first non-digit character. But you may set it to false then I just skip non-digit chars but use all chars that are digits, for example -something has e in it, so contains one digit, if stop_on_first_non_digit is false then this single e digit will be used. By default now it is true so that it behaves the way you like.
Also I kept your logic of skipping first spaces in a string so you can input 30-something (leading spaces) and it gives 36 too.
Try it online!
#include <string>
#include <cctype>
#include <iostream>
int main() {
std::string duo = "30-something";
bool stop_on_first_non_digit = true;
size_t i = 0;
int decValue = 0;
while (i < duo.length() && std::isspace(duo.at(i)))
++i;
for (; i < duo.length(); ++i) {
char c = duo.at(i);
int digit = 0;
if (std::isdigit(c))
digit = c - '0';
else if (c == 'x' || c == 'X')
digit = 10;
else if (c == 'e' || c == 'E')
digit = 11;
else {
if (stop_on_first_non_digit)
break;
else
continue;
}
decValue *= 12;
decValue += digit;
}
std::cout << decValue << std::endl;
}
Output:
36

Related

(C++) String to Double converter is inaccurate and totally wrong with negative numbers. What am i doing wrong?

Our teacher gave us this exercise:
"Given a string like '-5,14' write a function that returns the float value of -5,14
I used double here just to test the precision, but it also didn't work with floats.
[also i'm from Europe, we use the comma instead of the dot. Oh also we aren't allowed to use the type string and bool, we have to "make" them like in C]
This is what i came up with, and it seems to work a little bit. Positive numbers are similar, but wrong, and given a negative number, the result is similar to 10 times the positive of the given number.
It should work like this:
I read the string into an array of characters;
I check if the first character is a minus. if so, subtract 1 from the number of integer figures because i will count them later starting from index 0;
I count the number of integer figures with a loop from the start of the array to the ',' character;
I count the number of decimal figures with a loop from after the ',' to the end of the string;
[Keep in mind for the next step that, following the ASCII table, the code for the character of a number is that number + 48]
I add to the result variable every integer figure multiplied by ten to the power of whatever place in the number it has.
I do the same for the deicmal values but with the negative exponent.
if the number was negative, i multiply the result with -1.
But for some reason it's not working properly. The lower the number is, the less accurate it is (given 4,5 the result is 9, but given 345,543 the result is 350,43)
#include <iostream>
#define EOS '\0'
#define DIM 100
#define TRUE 1
#define FALSE 0
void leggiN(char* c)
{
std::cout << "Insert a number: ";
std::cin >> c;
}
double stof(char* str)
{
double Result = 0;
double ascii_to_int = 48;
int i = 0;
int j = 0;
int IntegerDigits = 0;
int DecimalDigits = 0;
int CommaIndex;
int isNegative = FALSE;
if (str[0] == '-')
{
IntegerDigits = -1;
isNegative = TRUE;
}
while (str[i] != ',')
{
++IntegerDigits;
++i;
}
CommaIndex = i;
++i;
while (str[i] != EOS)
{
++DecimalDigits;
++i;
}
for (i = (CommaIndex - 1); i >= 0; --i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, j));
++j;
}
j = 0;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
if (isNegative == 1)
Result = Result * -1;
return Result;
}
int main()
{
char str[DIM];
leggiN(str);
std::cout << stof(str);
}
use j = 1 to start your second for loop. You are trying to raise 10 to the power of -0
j = 1;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
If your code return 9.0 when you enter "4,5", your problem has nothing to do with imprecision.
There are other problems in your code, I've tried to un it and got a SEGFAULT...
#include <iostream>
#define EOS '\0' // 0 being such a special value, there is no need to
// define a named constant for it.
#define DIM 100
#define TRUE 1 // the language defines boolean values, avoid defining
#define FALSE 0 // unnecessary named constants for something that already
// exists.
void leggiN(char* c)
{
std::cout << "Insert a number: ";
std::cin >> c; // Inserting from cin to a char* is a BIG no-no.
// some compilers won't even allow it, for good reasons
// i.e.: what is the length of the array pointed to?
}
double stof(char* str) // you are indicating that you may modify str?
{
double Result = 0;
double ascii_to_int = 48; // this is a terrible name.
int i = 0;
int j = 0;
int IntegerDigits = 0;
int DecimalDigits = 0;
int CommaIndex;
int isNegative = FALSE;
if (str[0] == '-') // is str a valid pointer? what happens if NULL ??
{
IntegerDigits = -1;
isNegative = TRUE;
// you fail to skip the sing character, should have ++i here.
}
while (str[i] != ',') // what happens if there is no ',' in the string?
{ // you should check for str[i] == 0.
++IntegerDigits;
++i;
}
CommaIndex = i;
++i;
while (str[i] != EOS)
{
++DecimalDigits; // why do you count decimal digits?
++i; // you do not use this result anyway...
}
for (i = (CommaIndex - 1); i >= 0; --i)
{
// what happens if you have non-digit characters? they participate
// in the conversion??
// you call std::pow(), but do not include <cmath> at the top of the file.
// isn't str[i] - '0' clearer ?
Result += (str[i] - ascii_to_int) * (std::pow(10, j));
++j;
}
j = 0;
for (i = (CommaIndex + 1); str[i] != EOS; ++i)
{
Result += (str[i] - ascii_to_int) * (std::pow(10, -j));
++j;
}
if (isNegative == 1) // you had defined constants fot this, but don't use them.
Result = Result * -1;
return Result;
}
int main()
{
char str[DIM];
leggiN(str);
std::cout << stof(str);
}
Here is one way to achieve what you want.
#include <iostream>
#include <string>
const char DECIMAL_POINT = ','; // we'll use a named constant here....
// usually, we'd have to check the locale
// for regional specific information.
// works like atod(), conversion stops at end of string of first illegal character.
double stof(const char* str) {
// check input, must be not null, not empty
if (!str || str[0] == 0)
return 0;
int i = 0;
bool isNegative = false;
// take care of leading sign
if (str[0] == '-' || str[0] == '+') {
isNegative = (str[0] == '-');
++i;
}
// convert integer part.
double result = 0;
while ('0' <= str[i] && str[i] <= '9') {
result = (result * 10) + (str[i] - '0');
++i;
}
// only do decimals if they are there.
if (str[i] != DECIMAL_POINT)
return (isNegative) ? -result : result;
++i; // skip decimal point
double decimals = 0;
double multiplier = .1;
while ('0' <= str[i] && str[i] <= '9') {
decimals += (str[i] - '0') * multiplier;
++i;
multiplier *= .1;
}
result += decimals;
return (isNegative) ? -result : result;
}
int main() {
// always use std::string to read strings from cin.
std::string str;
std::cout << "Insert a number: ";
std::cin >> str;
std::cout << "in: " << str << " out: " << stof(str.c_str()) << '\n';
return 0;
}

convert lowercase to uppercase first character and make other chars stay lower

void correcter(string s, int j)
{
string correct;
for (; j < s.length(); j++)
{
if (int(s[j]) != 46){
if (int(s[j]) >= 97 && int(s[j]) <= 122 && i == 0)
{
char a = int(s[j]) - 32;
correct += a;
i++;
}
else if (int(s[j]) >= 65 && int(s[j]) <= 90&&i==0)
{
char a = int(s[j]) + 32;
correct += a;
i++;
}
else if (int(s[j]) >= 65 && int(s[j]) <= 90)
{
char a = int(s[j]) + 32;
correct += a;
i++;
}
else
correct += s[j];
}
else
{
correct += ". ";
i = 0;
}
}
cout << correct << endl;
}
question is to write a code that convert first character of string to uppercase and other stay as lowercase. after every "." make the words first char again upper and other parts in lower!
Input:
hellOWOrLD.hELLOWORLD.
Output:
Helloworld. Helloworld.
It should work like in the picture...
I would use isalpha(), toupper() and tolower()
EDIT: To look for punctuation.
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
void upperCase(string& line) {
bool firstCharacter = true;
string punctuation=".?!";
for(int i = 0; line[i] != '\0'; i++) {
char c=line[i];
if(isalpha(c)) {
if (firstCharacter) {
line[i] = toupper(c);
firstCharacter = false;
} else {
line[i] = tolower(c);
}
} else if (punctuation.find(c)!=string::npos) {
firstCharacter=true;
}
}
}
int main() {
string str = "hello UNiverse?! World? Hello. Hello";
upperCase(str);
std::cout << str << '\n';
}

C++ make a string to int function

I usually program in python which has a string to integer converter built in but when i use C++ it doesn't seem to work so I decided to make my own.
this is what i made so far
C++:
int strtoint(string str)
{
int values [str.length()];
int return_value = 0;
for (int i=0; i < str.length(); ++i)
if(str.at(str.length()-1-i) == '1')
values[i] = 1;
else if(str.at(str.length()-1-i) == '2')
values[i] = 2;
else if(str.at(str.length()-1-i) == '3')
values[i] = 3;
else if(str.at(str.length()-1-i) == '4')
values[i] = 4;
else if(str.at(str.length()-1-i) == '5')
values[i] = 5;
else if(str.at(str.length()-1-i) == '6')
values[i] = 6;
else if(str.at(str.length()-1-i) == '7')
values[i] = 7;
else if(str.at(str.length()-1-i) == '8')
values[i] = 8;
else if(str.at(str.length()-1-i) == '9')
values[i] = 9;
for (int i=0; i < str.length(); ++i)
return_value += values[i]^(10*i);
return return_value;
}
I seem to get very weird answers like "12" returns 13 and "23" returns 11.
I know about stoi but I prefer to make my own so I can learn C++.
Three problems I can see on a quick look.
The first is that
int values [str.length()];
is not valid C++. It is using a feature from the 1999 C standard, which some C++ compilers support as an extension, but it is still not valid C++.
The second is lack of handling of 0s or errors (non-digit characters) in input.
The third is the statement
return_value += values[i]^(10*i);
^ is a bitwise XOR operator in C++. Not mathematical exponentiation.
A couple of other minor tips.
You can probably simplify your code a lot by using iterators.
Also, with all standard character sets, the roman digits are sequential, starting with '0'. So a simple way to convert a digit to the numeric value you want is digit - '0', which will convert '0' to 0, '1' to 1, .... '9' to 9.
In C++ I use std::stringstream to convert std::string to int. Simple example I found:
#include <sstream>
#include <iostream> //used for cout
int main()
{
std::string str = "12345";
std::istringstream ss(str);
int i;
ss >> i;
if (ss.fail())
{
// Error
}
else
{
std::cout << "The integer value is: " << i;
}
return 0;
}
Mistakes in your code you can find in #Peter answer.
You could simplify this a lot with the char conversion where you just subtract the value of '0' and the use of iterators, especially reverse iterators which make it simpler to calculate the value.
#include <cmath>
#include <string>
/*! Converts a char to an integer.
* #param c the character to convert
* #return the integer value [0-9] or -1 if not convertible
*/
int chartoint(const char c)
{
auto value = (c - '0');
if (value < 0 || value > 9)
{
value = -1;
}
return value;
}
/*! Converts a string to an integer.
* #param string the string to convert
* #return the converted integer value or 0 if not convertible
*/
int strtoint(const std::string& string)
{
auto integer = 0;
const auto begin = string.rbegin();
for (auto it = begin, end = string.rend(); it != end; ++it)
{
const auto current = chartoint(*it);
if (current == -1)
{
integer = 0;
break;
}
else
{
const auto factor = static_cast<int>(std::pow(10, (it - begin)));
integer += factor * current;
}
}
return integer;
}
Test run:
#include <cassert>
int _tmain(int argc, _TCHAR* argv[])
{
assert(strtoint("1") == 1);
assert(strtoint("1x") == 0);
assert(strtoint("12") == 12);
assert(strtoint("10") == 10);
return 0;
}

Changing letters by ascii value

I am trying to use ascii values to check different values of a letter to decipher a simple Cesar cipher. I am running into problems when the program tries to check a letter after z. I am using all lower case so if the letter is on z it should move to the beginning of the alphabet again. My code is as follows
#include <iostream>
using namespace std;
#include <string>
#include <vector>
int main()
{
string unencr;
char temp;
cout << "Enter string:" << endl << endl;
cin >> unencr;
for(int i = 0; i<26; i++){
for(int j = 0; j < unencr.size(); j++){
temp = unencr[j];
if ((int)temp + i <= 122){
temp = (int)temp + i;
}
if ((int)temp + i > 122){
temp = (((int)temp +i) % 122)+96;
}
cout << temp;
}
cout << endl;
}
return 0;
}
Your problem is that in your if statement you say (((int)temp +i) % 122)+96; But what if the char was 155 this would then make it equal to 130. Which is out of the bounds of a-z.
What you want to do instead: if(temp > 122) then you should (temp-122)%122 + 97 instead of moding it by itself.
To change a single character c, use this line:
c = ((c - 'a' + 13) % 26) + 'a';
c - 'a' // convert to position in the alphabet, 0 based
c - 'a' + 13 // rot13 (or any other shift that you want)
(c - 'a' + 13) % 26 // wrap around after 'z'
((c - 'a' + 13) % 26) + 'a' // convert it to ASCII again
Also you might want to embrace all of C++'s features:
#include <iostream>
#include <string>
int main() {
// read a whole line instead of a single word:
std::string str;
std::getline(std::cin, str);
// iterate over the string, not over the letters of the alphabet:
for (char &c : str) {
if (('a' <= c) && (c <= 'z')) {
c = (((c + 13) - 'a') % 26) + 'a';
}
}
std::cout << str << std::endl;
return 0;
}

Converting binary to ASCII

I have a text full of binary values(0-1) and i'm trying to convert it to ASCII , I made a code but it didn't work well and it takes too long time and writing, this is a part of it:
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main()
{
ofstream fout("C:\\test.txt",ios :: binary);
ifstream file("E:\\mnmn.txt");
string content;
while(file >> content)
{
for (size_t i = 0; i < content.size(); i++)
{
while((content[i] == '0')
&& (content[i+1] == '0')
&& (content[i+2] == '0')
&& (content[i+3] == '0')
&& (content[i+4] == '0')
&& (content[i+5] == '0')
&& (content[i+6] == '0')
&& (content[i+7] == '0')
{
char *data = "00000000";
char c = strtol(data, 0, 2);
fout<<c;
}
}
}
}
i have to do the same for all values and even if i did the program repeats the values because the zeros and ones is connected without any spaces between , isn't there a better way to convert it?
the text contains:
00001111101010001001010101110
etc..
GCC 4.8.2: g++ -Wall -Wextra -std=c++11 read-01.cpp
#include <bitset>
#include <fstream>
int main() {
std::ofstream fout("test.txt");
std::ifstream fin("mnmn.txt");
char ic;
std::bitset<8> oc;
int i = 8;
while (fin >> ic) {
oc[--i] = ic - '0';
if (0 == i) {
fout << static_cast<char>(oc.to_ulong());
i = 8; } }
return 0; }
You can read the contents of the file character by character and accumulate the characters in a variable. After reading 8 characters, you have the ASCII value. The core of your function can be changed to:
int inChar = 0;
int outChar = 0;
int count = 0;;
while( (inChar = file.get()) != EOF )
{
int x = inChar - '0';
// Ignore newlines and other characters that are not '0' or '1'.
if ( x == 0 || x == 1 )
{
// Accumulate the bit into the output char.
outChar = (outChar << 1) + x;
++count;
if ( count == 8 )
{
fout.put(outChar);
outChar = 0;
count = 0;
}
}
}
// Deal with unused outChar.
if ( count > 0 )
{
cout << "There are " << count << " bits that were not used.\n";
}
If you want to get eight characters (bits) at a time from the input you read, then you should use the std::string::substr function, and you can use the resulting string directly, either in std::stoi (or if you don't have it std::strtol).
Something like
while (file >> content)
{
do
{
std::string byte = content.substr(0, 8); // Get eight "bits"
fout << std::stoi(byte, nullptr, 2); // Convert and output to file
content = content.substr(8); // The remaining bits
} while (!content.empty());
}