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());
}
Related
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
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;
}
I am trying to split specific string with couple of different ways. The example of my input is (-5,3,0,1,-2).
And this is my first code,
// code 1
string s = "(-5,3,0,1,-2)";
int j = 0;
int * temp = new int[s.length()];
for (int i = 0; i < s.length(); i++) {
if (s[i] != '(' && s[i] != ',' && s[i] != ')') {
temp[j++] = (s[i]-'0');
}
}
code 1 works well except, it converts - sign to ascii value(45) not negative int value.
//code2
char *first = _strdup(s.c_str());
char * temp2 = NULL;
char *temp = strtok_s(first, "(,)", &temp2);
/* Expected output is
temp[0] = -5
temp[1] = 3
temp[2] = 0
temp[3] = 1
temp[4] = -2
*/
However middle of debugging, temp contains ascii value, not string value. Also not sure code2 is correctly working.
Thanks in advances!
You need a proper string to int conversion. Use std::stoi. I used the boost tokenizer. It is very handy for your case.
#include <string>
#include <boost/tokenizer.hpp>
#include <vector>
using namespace std;
using namespace boost;
int main() {
vector<int> intList
string text = "(-5,3,0,1,-2)";
char_separator<char> sep(",");
tokenizer<char_separator<char>> tokens(text, sep);
for (const auto& t : tokens)
intList.push_back(std::stoi(t));
}
PS. you forgot the delete for you new. Please use a proper container (e.g. std::vector).
Use istrstream::get method. You can avoid the open and close braces by replacing those.
void _parse_(istrstream &str,string &strText, char ch = ',')
{
char chText[MAX_PATH];
str.get(chText, MAX_PATH,ch);
str.get(ch);
strText = chText;
}
string s = "(-5,3,0,1,-2)";
istrstream inputStream(s);
string sTemp;
//Replace here the open and close braces.
do
{
_parse_(inputStream, sTemp,',');
//Your value in sTemp
}while(!sTemp.empty())
If you need use c++ without any library, you can use flowing code:
#include <string>
#include <vector>
using namespace std;
int main()
{
string s = "(-5 2,3 0 1, 0 , 1 , -21 0 )";
int location = 0;
vector<int> array;
string sub;
while (location <= s.length())
{
if ((s[location] >= 48 && s[location] <= 57) || s[location] == 45 || s[location] == 32)
{
if (s[location] != 32)
{
sub += s[location];
}
}
else
{
if (sub.length() != 0)
{
std::string::size_type sz;
int num = stoi(sub, &sz);
array.push_back(num);
}
sub.clear();
}
location++;
}
return 0;
}
#include <sstream>
#include <iomanip>
using namespace std;
const string INTEGER_CHARS {"0123456789+-"};
vector<int> readIntFromString(const string src) {
const char stopFlag{'\0'};
const string str {src + stopFlag};
vector<int> numbers;
stringstream ss(str);
int tmp;
for(char nextChar = ss.peek(); nextChar != stopFlag; nextChar = ss.peek()) {
if (INTEGER_CHARS.find(nextChar) != string::npos) {
ss >> setbase(0) >> tmp;
numbers.push_back(tmp);
} else {
ss.ignore();
}
}
return numbers;
}
setbase(0): make >> operator to recognize other based numbers, e.g. 0b01, 070, 0xF
ss.ignore(): skip the char we don't care
You can use the following,
string s = "(-5,3,0,1,-2)";
int j = 0;
string temp;
std::vector<int> values;
for (int i = 0; i < s.length(); i++)
{
if (s[i] != '(' && s[i] != ')')
{
while (s[i] != ',' && s[i] != ')')
{
temp += s[i];
++i;
}
values.push_back(std::atoi(temp.c_str()));
temp.clear();
}
}
I'm trying to write a function which only reads four ints out of a users input like this: ewzge242jfdsiii23 So it is supposed to save only 2422.
This is my code and it just gives me some weird output, if I let it cout number.
Can you maybe see my mistakes and explain why I can't do it how I did and what I could do instead? Thanks a lot!
int readnumber ( ) {
char kar, ont_kar, ont_ont_kar;
int number;
while (kar != '\n' ){
cin.get (kar);
if (kar >= '0' && kar <= '9') {
old_kar=kar;
old_kar = old_kar*10 + (kar - '0');
old_old_kar = old_kar ;
} //if
} //while
if (old_kar < 9999) {
number=old_kar;
}//if
else {
number=old_old_kar;
}//else
}//readnumber
This looks too complicated, why do you need so many variables?
Also old_kar and old_old_kar are misstyped. The function does not return, that should be the main problem.
Here's a quick simple example:
unsigned readnumber(int number_of_chars) {
char ch;
unsigned number = 0;
while (number_of_chars > 0) {
std::cin.get(ch);
if ('\n' == ch)
break; // Stop on new line
if (ch < '0' or ch > '9')
continue; // Skip non-digits
--number_of_chars; // One digit processed
number = number * 10 + ch - '0'; // And added to the result
}
return number;
}
And here is a full version without break or continue:
#include <iostream> // std::cin, std::cout
#include <fstream> // std::ifstream
using namespace std;
int readnumber(int number_of_chars) {
char ch;
int number = 0;
while (number_of_chars > 0) {
std::cin.get(ch);
if ('\n' == ch)
return number;
if (ch >= '0' and ch <= '9') {
--number_of_chars;
number = number * 10 + ch - '0';
}
}
return number;
}
int main() {
int n = readnumber(4);
cout << "You entered: " << n << endl;
return 0;
}
NB: Always compile with all warnings on, this will save you a lot of time.
Given a string of characters, how can I go through it and assign all the numbers within that string into an integer variable, leaving out all other characters?
I want to do this task when there is a string of characters already read in through gets(), not when the input is read.
unsigned int get_num(const char* s) {
unsigned int value = 0;
for (; *s; ++s) {
if (isdigit(*s)) {
value *= 10;
value += (*s - '0');
}
}
return value;
}
Edit: Here is a safer version of the function.
It returns 0 if s is NULL or cannot be converted to a numeric value at all. It return UINT_MAX if the string represents a value larger than UINT_MAX.
#include <limits.h>
unsigned int safe_get_num(const char* s) {
unsigned int limit = UINT_MAX / 10;
unsigned int value = 0;
if (!s) {
return 0;
}
for (; *s; ++s) {
if (value < limit) {
if (isdigit(*s)) {
value *= 10;
value += (*s - '0');
}
}
else {
return UINT_MAX;
}
}
return value;
}
This is a simple C++ way to do that:
#include <iostream>
#include <sstream>
using namespace std;
int main(int argc, char* argv[]) {
istringstream is("string with 123 embedded 10 12 13 ints", istringstream::in);
int a;
while (1) {
is >> a;
while ( !is.eof() && (is.bad() || is.fail()) ) {
is.clear();
is.ignore(1);
is >> a;
}
if (is.eof()) {
break;
}
cout << "Extracted int: " << a << endl;
}
}
Look up the strtol function from the standard C library. It allows you to find the part of a character array that is a number, and points to the first character that isn't a number and stopped the parsing.
You can use sscanf: it works like scanf but on a string (char array).
sscanf might be overkill for what you want though, so you can also do this:
int getNum(char s[])
{
int ret = 0;
for ( int i = 0; s[i]; ++i )
if ( s[i] >= '0' && s[i] <= '9' )
ret = ret * 10 + (s[i] - '0');
return ret;
}