Trouble getting character classification information from map - c++

I have a program that maps the ctype identification of a character to a textual representation. I use a std::map to map a value of the mask (ctype_base::mask) to a string that represents the type of character in a string. The trouble I'm having is that when I attempt to print out the value, nothing gets printed to output. Why is this?
#include <iostream>
#include <map>
#include <vector>
class mask_attribute
{
private:
typedef std::ctype_base base_type;
public:
mask_attribute()
{
mask_names[base_type::space] = "space";
mask_names[base_type::alpha] = "alpha";
mask_names[base_type::digit] = "digit";
}
std::string get_mask_name(base_type::mask mask) const
{
std::string result = (*mask_names.find(mask)).second;
return result;
}
private:
std::map<base_type::mask, std::string> mask_names;
};
int main()
{
std::string a = "abc123";
std::vector<std::ctype_base::mask> v(a.size());
auto& f = std::use_facet<std::ctype<char>>(std::locale());
f.is(&a[0], &a[0] + a.size(), &v[0]);
for (unsigned i = 0; i < v.size(); ++i)
std::cout << mask_attribute().get_mask_name(v[i]) << std::endl;
}
The output I expected was:
alpha
alpha
alpha
digit
digit
digit
but instead nothing is printed. What did I do wrong here and how do I fix it?

Print out v[i] as integer in hex, that might prove illuminating.
You expect ctype::is to produce exactly one bit for each character. That is not what normally happens. For example, for 'a' you are likely to see alpha | lower | print. You don't have an entry for this in mask_names, so find returns mask_names.end(), which you promptly dereference, whereupon your program exhibits undefined behavior.

Related

Substring to Int C++

I am trying to convert a string that is only 1s and 0s to a decimal value. The variable value is initialized to 0 and is never updated. I suspect the problem is that binaryString[i] is treated as a string and therefore the athematic function doesn't work. How can I fix this?
void binaryToDec(string binaryString, int value)
{
int binaryStringLength = binaryString.length();
for (int i = 0; i < binaryStringLength; i++)
{
value += pow(2,i)+ binaryString[i];
}
}
I tried to use basic type casting like int(binaryString[i]) but that doesn't work.
Firstly binaryString[i] is a character, not an integer. To convert a digit character to an integer you can just subtract '0'.
binaryString[i] - '0'
Secondly pow(2,i) returns a floating point number, when you want an integer. This is inefficient, and even more seriously might be subject to rounding errors. Instead you should use a shift operator, which efficiently and accurately calculates integer powers of two.
1 << i
Thirdly you have + where you need *. The two terms should be multiplied not added.
Putting all that together you get
value += (1 << i) * (binaryString[i] - '0');
But the most serious error of all is that your function does not return a value. It should look like this
int binaryToDec(string binaryString)
{
int value = 0;
...
return value;
}
Your version passes value as a parameter, that's the wrong way round, binaryString is a parameter, but value should be returned from the function. Not sure why but this is a difference a lot of newbies struggle with.
You could construct a bitset from the string and then back to a ullong.
But, limiting the solution to a maximum binary string size.
[Demo]
#include <bitset>
#include <fmt/core.h>
#include <stdexcept> // out_of_range
auto binaryToDec(const std::string& binary) {
if (binary.size() > 64) {
throw std::out_of_range{ "binary string is too big" };
}
return std::bitset<64>{binary}.to_ullong();
}
int main() {
try {
std::string binary_1{"101010"};
fmt::print("binary: {}, decimal: {}\n", binary_1, binaryToDec(binary_1));
std::string binary_2{
"1111""1111""1111""1111"
"1111""1111""1111""1111"
"1111""1111""1111""1111"
"1111""1111""1111""1111"
"1"
};
fmt::print("{}\n", binaryToDec(binary_2));
} catch (const std::exception& e) {
fmt::print("Error: {}.\n", e.what());
}
}
// Outputs:
//
// binary: 101010, decimal: 42
// Error: binary string is too big.

C++: convert vector of floats to char*

How can I convert vector of floats into a char*?
I have a collection of floats stored inside std::vector<float> id_list:
0,
0,
0,
0,
0,
1.77636e-15,
2.35099e-38,
-7.10543e-15,
3.06107e-38,
....
and using this code to convert it:
char *ptr = (char*)&id_list[0];
std::string dump_string(ptr, id_list.size() * sizeof(float));
but dump_string.c_str() returns empty, despite having some values stored in my vector. I'm expecting to get all values concatenated into a one, long string, ie.:
0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38........
I'm expecting to get all values concatenated into a one, long string, ie.:
0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38........
You are creating a std::string that simply holds a copy of the raw bytes of the float array. So, if any of the bytes happen to contain a numeric value of 0 (as is the case in your example), you will get a truncated result if you try to treat the std::string as a null-terminated C string.
If you want to actually convert the float values into a human-readable string, you need to format the values individually, such as with std::ostringstream or std::to_string(), eg:
std::ostringstream oss;
if (!id_list.empty()) {
oss << id_list[0];
for(size_t i = 1; i < id_list.size(); ++i) {
oss << "," << id_list[i];
}
}
std::string dump_string = oss.str();
std::string dump_string;
if (!id_list.empty()) {
dump_string += std::to_string(id_list[0]);
for(size_t i = 1; i < id_list.size(); ++i) {
dump_string += ',';
dump_string += std::to_string(id_list[i]);
}
}
. I'm expecting to get all values concatenated into a one, long string, ie.:
You could write a small function to do that.
Example:
#include <iostream>
#include <iterator> // std::advance
#include <string>
#include <sstream> // std::stringstream
#include <vector>
// a function taking two iterators and streaming the content to a stringstream
// then returning a `std::string` using `stringstream::str()`
template<typename Begin, typename End = Begin>
std::string join(Begin begin, End end) {
std::stringstream retval;
if(begin != end) {
retval << *begin;
for(std::advance(begin, 1); begin != end; std::advance(begin, 1)) {
retval << ',' << *begin;
}
}
return retval.str();
}
int main()
{
std::vector<float> id_list {
0,
0,
0,
0,
0,
1.77636e-15,
2.35099e-38,
-7.10543e-15,
3.06107e-38,
};
std::cout << join(id_list.begin(), id_list.end());
}
Output:
0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38
As others note, your approach of using casting is not the right way to go. Also, note that all of the value in your example are probably exactly 0.0 (or -0.0)! Why? Because they're beyond the precision range of float on typical platforms.
Still, you could concatenate the string representation of the float's in an std::vector, using the ranges library, and with no need for any loops:
#include <vector>
#include <string>
#include <iostream>
#include <range/v3/all.hpp>
std::string concat_my_floats(const std::vector<float>& vec)
{
std::ostringstream oss;
auto convert = [&](float x) { oss.str(""); oss << x; return oss.str(); };
return vec
| ranges::views::transform(convert)
| ranges::views::cache1 // We need this, see footnote.
| ranges::views::join(',')
| ranges::to<std::string>();
}
int main () {
std::vector<float> id_list = {0, 1.1, -2.2, 3.3};
std::cout << concat_my_floats(id_list) << std::endl;
}
This will give you:
0,1.1,-2.2,3.3
If you're wondering what's that cache1 business - it has to do with how the transformed range is a range of prvalues, which the ranges library is not willing to join for performance reasons; apparently you need to explicitly allow a caching of the last element, expensive though it may be. See here.
How can I convert vector of floats into a char*?
Here is one way to reinterpret the array of floating point numbers as bytes:
char *ptr = reinterpret_cast<char*>(id_list.data());
Which does exactly what your cast did except it doesn't rely on a C style cast.
but dump_string.c_str() returns empty
This is because dump_string happens to contain an empty null terminated string at the beginning.
I'm expecting to get all values concatenated into a one, long string, ie.:
0,0,0,0,0,1.77636e-15,2.35099e-38,-7.10543e-15,3.06107e-38........
You expectation is misguided. Reinterpreting bytes of floating point numbers is a separate thing from serialising them to readable text. If this is the output you want, then reinterpretation is not the operation that you need.
You can use for example a string stream to convert floating point numbers to text.

Read integer from string

I have a string in form "blah-blah..obj_xx..blah-blah" where xx are digits. E.g. the string may be "root75/obj_43.dat".
I want to read "xx" (or 43 from the sample above) as an integer. How do I do it?
I tried to find "obj_" first:
std::string::size_type const cpos = name.find("obj_");
assert(std::string::npos != cpos);
but what's next?
My GCC doesn't support regexes fully, but I think this should work:
#include <iostream>
#include <string>
#include <regex>
#include <iterator>
int main ()
{
std::string input ("blah-blah..obj_42..blah-blah");
std::regex expr ("obj_([0-9]+)");
std::sregex_iterator i = std::sregex_iterator(input.begin(), input.end(), expr);
std::smatch match = *i;
int number = std::stoi(match.str());
std::cout << number << '\n';
}
With something this simple you can do
auto b = name.find_first_of("0123456789", cpos);
auto e = name.find_first_not_of("0123456789", b);
if (b != std::string::npos)
{
auto digits = name.substr(b, e);
int n = std::stoi(digits);
}
else
{
// Error handling
}
For anything more complicated I would use regex.
How about:
#include <iostream>
#include <string>
int main()
{
const std::string test("root75/obj_43.dat");
int number;
// validate input:
const auto index = test.find("obj_");
if(index != std::string::npos)
{
number = std::stoi(test.substr(index+4));
std::cout << "number: " << number << ".\n";
}
else
std::cout << "Input validation failed.\n";
}
Live demo here. Includes (very) basic input validation (e.g. it will fail if the string contains multiple obj_), variable length numbers at the end, or even more stuff following it (adjust the substr call accordingly) and you can add a second argument to std::stoi to make sure it didn't fail for some reason.
Here's another option
//your code:
std::string::size_type const cpos = name.find("obj_");
assert(std::string::npos != cpos);
//my code starts here:
int n;
std::stringstream sin(name.substr(cpos+4));
sin>>n;
Dirt simple method, though probably pretty inefficient, and doesn't take advantage of the STL:
(Note that I didn't try to compile this)
unsigned GetFileNumber(std::string &s)
{
const std::string extension = ".dat";
/// get starting position - first character to the left of the file extension
/// in a real implementation, you'd want to verify that the string actually contains
/// the correct extension.
int i = (int)(s.size() - extension.size() - 1);
unsigned sum = 0;
int tensMultiplier = 1;
while (i >= 0)
{
/// get the integer value of this digit - subtract (int)'0' rather than
/// using the ASCII code of `0` directly for clarity. Optimizer converts
/// it to a literal immediate at compile time, anyway.
int digit = s[i] - (int)'0';
/// if this is a valid numeric character
if (digit >= 0 && digit <= 9)
{
/// add the digit's value, adjusted for it's place within the numeric
/// substring, to the accumulator
sum += digit * tensMultiplier;
/// set the tens place multiplier for the next digit to the left.
tensMultiplier *= 10;
}
else
{
break;
}
i--;
}
return sum;
}
If you need it as a string, just append the found digits to a result string rather than accumulating their values in sum.
This also assumes that .dat is the last part of your string. If not, I'd start at the end, count left until you find a numeric character, and then start the above loop. This is nice because it's O(n), but may not be as clear as the regex or find approaches.

Scanning ASCII value of each character of a string

Is there anyway , if I enter any string , then I want to scan ASCII value of each character inside that string , if I enter "john" then I should get 4 variables getting ASCII value of each character, in C or C++
Given a string in C:
char s[] = "john";
or in C++:
std::string s = "john";
s[0] gives the numeric value of the first character, s[1] the second an so on.
If your computer uses an ASCII representation of characters (which it does, unless it's something very unusual), then these values are the ASCII codes. You can display these values numerically:
printf("%d", s[0]); // in C
std::cout << static_cast<int>(s[0]); // in C++
Being an integer type (char), you can also assign these values to variables and perform arithmetic on them, if that's what you want.
I'm not quite sure what you mean by "scan". If you're asking how to iterate over the string to process each character in turn, then in C it's:
for (char const * p = s; *p; ++p) {
// Do something with the character value *p
}
and in (modern) C++:
for (char c : s) {
// Do something with the character value c
}
If you're asking how to read the string as a line of input from the terminal, then in C it's
char s[SOME_SIZE_YOU_HOPE_IS_LARGE_ENOUGH];
fgets(s, sizeof s, stdin);
and in C++ it's
std::string s;
std::cin >> s; // if you want a single word
std::getline(std::cin, s); // if you want a whole line
If you mean something else by "scan", then please clarify.
You can simply get the ascii value of a char by casting it to type int:
char c = 'b';
int i = c; //i contains ascii value of char 'b'
Thus, in your example the code to get the ascii values of a string would look something like this:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
int main()
{
string text = "John";
for (int i = 0; i < text.size(); i++)
{
cout << (int)text[i] << endl; //prints corresponding ascii values (one per line)
}
}
To get the corresponding char from an integer representing an entry in the ascii table, you just have to cast the int back to char again:
char c = (char)74 // c contains 'J'
The code given above was written in C++ but it basically works the same way in C (and many other languages as well I guess)
There is no way to turn a string of length 'x' into x variables. In C or C++ you can only declare a fixed number of variables. But probably you don't need to do what you are saying. Perhaps you just need an array, or most likely you just need a better way to solve whatever problem you are trying to solve. If you explain what the problem is in the first place, then I'm sure a better way can be explained.
Ya,I think there are some more better solutions are also available but this one also be helpful.
In C
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main(){
char s[]="abc";
int cnt=0;
while(1){
if(s[cnt++]==NULL)break;
}
int *a=(int *)malloc(sizeof(int)*cnt);
for(int i=0;i<cnt;i++)a[i]=s[i];
for(int i=0;i<cnt-1;i++)printf("%d\n",a[i]);
return 0;
}
In C++
#include <iostream>
#include <string>
using namespace std;
int main(){
string s="abc";
//int *a=new int[s.length()];
//for(int i=0;i<s.length();i++)a[i]=s[i];
for(int i=0;i<s.length();i++)
cout<<(int)s[i]<<endl;
return 0;
}
I hope this one will be helpful..
yeah it's very easy ..just a demo
int main()
{
char *s="hello";
while(*s!='\0')
{
printf("%c --> %d\n",*s,*s);
s++;
}
return 0;
}
But make sure your machine is supporting the ASCII value format.
In C every char has one integral value associted with it called ASCII.
Using %d format specifier you can directly print the ASCII of any char as above.
NOTE: It's better to get good book and practice this kind of program yourself.

How to generate 'consecutive' c++ strings?

I would like to generate consecutive C++ strings like e.g. in cameras: IMG001, IMG002 etc. being able to indicate the prefix and the string length.
I have found a solution where I can generate random strings from concrete character set: link
But I cannot find the thing I want to achieve.
A possible solution:
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
std::string make_string(const std::string& a_prefix,
size_t a_suffix,
size_t a_max_length)
{
std::ostringstream result;
result << a_prefix <<
std::setfill('0') <<
std::setw(a_max_length - a_prefix.length()) <<
a_suffix;
return result.str();
}
int main()
{
for (size_t i = 0; i < 100; i++)
{
std::cout << make_string("IMG", i, 6) << "\n";
}
return 0;
}
See online demo at http://ideone.com/HZWmtI.
Something like this would work
#include <string>
#include <iomanip>
#include <sstream>
std::string GetNextNumber( int &lastNum )
{
std::stringstream ss;
ss << "IMG";
ss << std::setfill('0') << std::setw(3) << lastNum++;
return ss.str();
}
int main()
{
int x = 1;
std::string s = GetNextNumber( x );
s = GetNextNumber( x );
return 0;
}
You can call GetNextNumber repeatedly with an int reference to generate new image numbers. You can always use sprintf but it won't be the c++ way :)
const int max_size = 7 + 1; // maximum size of the name plus one
char buf[max_size];
for (int i = 0 ; i < 1000; ++i) {
sprintf(buf, "IMG%.04d", i);
printf("The next name is %s\n", buf);
}
char * seq_gen(char * prefix) {
static int counter;
char * result;
sprintf(result, "%s%03d", prefix, counter++);
return result;
}
This would print your prefix with 3 digit padding string. If you want a lengthy string, all you have to do is provide the prefix as much as needed and change the %03d in the above code to whatever length of digit padding you want.
Well, the idea is rather simple. Just store the current number and increment it each time new string is generated. You can implement it to model an iterator to reduce the fluff in using it (you can then use standard algorithms with it). Using Boost.Iterator (it should work with any string type, too):
#include <boost/iterator/iterator_facade.hpp>
#include <sstream>
#include <iomanip>
// can't come up with a better name
template <typename StringT, typename OrdT>
struct ordinal_id_generator : boost::iterator_facade<
ordinal_id_generator<StringT, OrdT>, StringT,
boost::forward_traversal_tag, StringT
> {
ordinal_id_generator(
const StringT& prefix = StringT(),
typename StringT::size_type suffix_length = 5, OrdT initial = 0
) : prefix(prefix), suffix_length(suffix_length), ordinal(initial)
{}
private:
StringT prefix;
typename StringT::size_type suffix_length;
OrdT ordinal;
friend class boost::iterator_core_access;
void increment() {
++ordinal;
}
bool equal(const ordinal_id_generator& other) const {
return (
ordinal == other.ordinal
&& prefix == other.prefix
&& suffix_length == other.suffix_length
);
}
StringT dereference() const {
std::basic_ostringstream<typename StringT::value_type> ss;
ss << prefix << std::setfill('0')
<< std::setw(suffix_length) << ordinal;
return ss.str();
}
};
And example code:
#include <string>
#include <iostream>
#include <iterator>
#include <algorithm>
typedef ordinal_id_generator<std::string, unsigned> generator;
int main() {
std::ostream_iterator<std::string> out(std::cout, "\n");
std::copy_n(generator("IMG"), 5, out);
// can even behave as a range
std::copy(generator("foo", 1, 2), generator("foo", 1, 4), out);
return 0;
}
Take a look at the standard library's string streams. Have an integer that you increment, and insert into the string stream after every increment. To control the string length, there's the concept of fill characters, and the width() member function.
You have many ways of doing that.
The generic one would be to, like the link that you showed, have an array of possible characters. Then after each iteration, you start from right-most character, increment it (that is, change it to the next one in the possible characters list) and if it overflowed, set it to the first one (index 0) and go the one on the left. This is exactly like incrementing a number in base, say 62.
In your specific example, you are better off with creating the string from another string and a number.
If you like *printf, you can write a string with "IMG%04d" and have the parameter go from 0 to whatever.
If you like stringstream, you can similarly do so.
What exactly do you mean by consecutive strings ?
Since you've mentioned that you're using C++ strings, try using the .string::append method.
string str, str2;
str.append("A");
str.append(str2);
Lookup http://www.cplusplus.com/reference/string/string/append/ for more overloaded calls of the append function.
it's pseudo code. you'll understand what i mean :D
int counter = 0, retval;
do
{
char filename[MAX_PATH];
sprintf(filename, "IMG00%d", counter++);
if(retval = CreateFile(...))
//ok, return
}while(!retval);
You have to keep a counter that is increased everytime you get a new name. This counter has to be saved when your application is ends, and loaded when you application starts.
Could be something like this:
class NameGenerator
{
public:
NameGenerator()
: m_counter(0)
{
// Code to load the counter from a file
}
~NameGenerator()
{
// Code to save the counter to a file
}
std::string get_next_name()
{
// Combine your preferred prefix with your counter
// Increase the counter
// Return the string
}
private:
int m_counter;
}
NameGenerator my_name_generator;
Then use it like this:
std::string my_name = my_name_generator.get_next_name();