The array is set up like so:
string * str = new string[11];
Where the content of the string looks like:
str[0]=AAAAAAAA,BBBBBBBB,CCCCCCCC,DDDDDDDD,EEEE,FFFFFFFF,GGGGGGGG,HHHH,IIII,JJJJ,KKKK
str[1]=AAAAAAAA,BBBBBBBB,CCCCCCCC,DDDDDDDD,EEEE,FFFFFFFF,GGGGGGGG,HHHH,IIII,JJJJ,KKKK
str[2]=AAAAAAAA,BBBBBBBB,CCCCCCCC,DDDDDDDD,EEEE,FFFFFFFF,GGGGGGGG,HHHH,IIII,JJJJ,KKKK
...
str[12]=AAAAAAAA,BBBBBBBB,CCCCCCCC,DDDDDDDD,EEEE,FFFFFFFF,GGGGGGGG,HHHH,IIII,JJJJ,KKKK
Another array looks like:
string * type = new string[11];
Where the content is:
type[0]="1";
type[1]="1";
type[2]="1";
type[3]="1";
type[4]="2";
type[5]="1";
type[6]="1";
type[7]="2";
type[8]="2";
type[9]="2";
type[10]="2";
These types correspond to each value in the string, so, for the first string:
1=float , 2=integer
AAAAAAAA would be 1; or an float
BBBBBBBB would be 1; or an float
CCCCCCCC would be 1; or an float
DDDDDDDD would be 1; or an float
EEEE would be 2; or a integer
FFFFFFFF would be 1; or an float
GGGGGGGG would be 1; or an float
HHHH would be 2; or a integer
IIII would be 2; or a integer
JJJJ would be 2; or a integer
KKKK would be 2; or a integer
In addition the single type array works for all strings in the str array.
Now for my question:
How do i use the above information to extract each individual values from the string and convert it to an integer or a float based on the value in the type array.
BE AWARE:
Boost is not available to me
The conversion functions look like: (The other is formatted similarly except for an integer)
unsigned int BinaryParser::hexToFloat(std::string hexInput)
{
std::stringstream ss (hexInput);
unsigned int floatOutput;
ss >> hex >> floatOutput;
return reinterpret_cast<float&>(floatOutput);
}
OK, first part: extract the comma-separated strings. One way would be:
std::vector<std::string> split( std::string s ){
std::vector<std::string> vec;
int pos = 0;
while( std::string::npos != (pos = s.find( ',', pos ) ) ){
vec.push_back( s.substr( 0, pos ) );
s = s.substr( pos + 1 );
}
vec.push_back( s );
return vec;
}
Depends on the input string being "well-behaved".
This converts an int from hex digits:
int convInt( std::string hexInput ){
std::istringstream iss (hexInput);
uint16_t intOutput;
iss >> std::hex >> intOutput;
return intOutput;
}
Float cannot be read using std::hex, so we assume the HHHHHHHH is a float's bytes interpreted as an int32_t.
float convFloat( std::string & hexInput ){
std::istringstream iss (hexInput);
uint32_t intOutput;
iss >> std::hex >> intOutput;
return reinterpret_cast<float&>(intOutput);
}
For storing the results we can use:
enum TypeTag { eInt, eFloat };
class IntOrFloat {
public:
IntOrFloat( int i ) : typeTag(eInt),integer(i),floating(0) { }
IntOrFloat( float f ) : typeTag(eFloat),integer(0),floating(f) { }
virtual ~IntOrFloat(){}
int getInt() const { return integer; }
float getFloat() const { return floating; }
TypeTag getTypeTag() const { return typeTag; }
private:
TypeTag typeTag;
int integer;
float floating;
};
std::ostream& operator<< (std::ostream& os, const IntOrFloat& iof){
switch( iof.getTypeTag() ){
case eInt:
os << iof.getInt();
break;
case eFloat:
os << iof.getFloat();
break;
}
return os;
}
To convert one comma-separated string according to the type vector:
std::vector<IntOrFloat> convert( const std::vector<std::string> t, const std::string s ){
std::vector<IntOrFloat> results;
std::vector<std::string> hexes = split( s );
for( int i = 0; i < hexes.size(); i++ ){
if( t[i] == "1" ){
results.push_back( IntOrFloat( convFloat( hexes[i] ) ) );
} else {
results.push_back( IntOrFloat( convInt( hexes[i] ) ) );
}
}
return results;
}
That's it, then. - I've been using vector instead of the arrays. You can easily convert, e.g.
std::vector<std::string> fromArray( std::string strs[], int n ){
std::vector<std::string> strings;
for( int i = 0; i < n; i++ ) strings.push_back( std::string( strs[i] ) );
return strings;
}
#define fromArray(a) fromArray( a, (sizeof(a)/sizeof(a[0])) )
And here is my test program:
#define LENGTH(a) (sizeof(a)/sizeof(a[0]))
int main(){
std::string t[] = {"2","1","1","2"};
std::string s[] = {
"8000,4048f5c3,bf000000,FFFF",
"0001,42f6e979,c44271ba,7FFF",
"1234,00000000,447a0000,5678"
};
std::vector<std::string> types = fromArray( t );
std::vector<std::string> strings = fromArray( s );
for( std::vector<std::string>::iterator it = strings.begin() ; it != strings.end(); ++it ){
std::vector<IntOrFloat> results = convert( types, *it );
std::cout << "converting string " << *it << ", " << results.size() << " values:" << std::endl;
for( std::vector<IntOrFloat>::iterator iof = results.begin() ; iof != results.end(); ++iof ){
std::cout << " " << *iof << std::endl;
}
}
}
Related
I was testing the following code, and a bit perplexed as to why count_if is returning me the total of texts?
Match function that takes string of Text as argument and returns true is the Text size is 4
bool Match(string Text)
{
if (Text.size() == 4)
return true;
}
numMatchwes produces the total number of Text in a vector
int numMatches(vector<string>Texts, bool (*Match)(string Text)) // Texts is an array
{
int count = 0;
for (int i = 0; i < Texts.size(); i++)
{
if (Match(Texts[i]) == 1)
// checking every string in vector and returns true
count++;
}
return count;
}
The main function
int main()
{
vector<string> texts;
texts.push_back("Bing");
texts.push_back("Pony");
texts.push_back("Mil");
texts.push_back("Sillty");
texts.push_back("Ballz");
texts.push_back("Mars");
cout << Match("Sind") << endl;
cout << "Matches are: " << numMatches(texts, Match) << endl;
cout << endl;
int num = count_if(texts.begin(), texts.end(), Match); // count_if is STL function
cout << num << endl;
}
Now I’m confused as to why count_if is giving me the total of texts?
The function Match has undefined behavior in case when the passed string does not have a length equal to 4.
Define it the following way
bool Match( const std::string &Text )
{
return Text.size() == 4;
}
Correspondingly the function numMatches can be defined the following way
auto numMatches( const std::vector<std::string> &Texts, bool Match(const std::string & ) )
{
std::vector<std::string>::size_type count = 0;
for ( const auto &s : Texts )
{
if ( Match( s ) ) ++count;
}
return count;
}
Here is your updated program.
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
auto numMatches( const std::vector<std::string> &Texts, bool Match(const std::string & ) )
{
std::vector<std::string>::size_type count = 0;
for ( const auto &s : Texts )
{
if ( Match( s ) ) ++count;
}
return count;
}
bool Match( const std::string &Text )
{
return Text.size() == 4;
}
int main()
{
std::vector<std::string> texts;
texts.push_back( "Bing" );
texts.push_back( "Pony" );
texts.push_back( "Mil" );
texts.push_back( "Sillty" );
texts.push_back( "Ballz" );
texts.push_back( "Mars" );
std::cout << std::boolalpha << Match( "Sind" ) << '\n';
std::cout << "Matches are: " << numMatches( texts, Match ) << '\n';
std::cout << '\n';
auto num = std::count_if( std::begin( texts ), std::end( texts ), Match );
std::cout << num << std::endl;
return 0;
}
The program output is
true
Matches are: 3
3
I have a file, at the end of each line there is possibly a newline:
111\n
100\n
101
In C++ you can load the lines of a file into an array of byte strings like this:
auto lines_from( istream& is )
-> vector<string>
{
string line;
vector<string> result;
while( getline( is, line ) )
{
result.push_back( line );
}
return result;
}
auto main() -> int
{
vector<string> const lines = lines_from( cin );
// Use it.
}
Here string is std::string from the <string> header, getline is std::getline from the same header, and vector is std::vector from the <vector> header. I chose to use a descriptive name for the function, lines_from. However, it's commonly named readall.
Where you absolutely need a char**, presumably with an assumption of some given buffer size for each string, then you can use a vector of pointers, pointing to buffers that e.g. are managed by a class like this:
class C_strings
{
private:
vector<string> buffers_;
vector<char*> pointers_;
int bufsize_;
C_strings( C_strings const& ) = delete;
auto operator=( C_strings const& ) -> C_strings& = delete;
public:
auto pointer() -> char** { return pointers_.data(); }
auto bufsize() const -> int { return bufsize_; }
C_strings( vector<string> const& strings, int const bufsize )
: buffers_( strings )
, bufsize_( bufsize )
{
pointers_.reserve( buffers_.size() + 1 );
for( string& s : buffers_ )
{
s.reserve( bufsize );
if( s.empty() or s.back() != '\0' ) { s += '\0'; }
pointers_.push_back( &s[0] );
}
pointers_.push_back( nullptr );
}
C_strings( C_strings&& other )
: buffers_( move( other.buffers_ ) )
, pointers_( move( other.pointers_ ) )
{}
};
Then let's say you want to call a double-star function like this:
void doublestarfunc( char** const lines )
{
using std::cout;
for( char** pps = lines; *pps != nullptr; ++pps )
{
if( strlen( *pps ) < 40 ) { strcat( *pps, " < Oh la la!" ); }
cout << *pps << '\n';
}
cout << '\n';
}
It can be done very simply:
using namespace std; // cin, cout
int const columns = 80;
int const cstring_bufsize = columns + 1;
auto c_strings = C_strings( lines_from( cin ), cstring_bufsize );
doublestarfunc( c_strings.pointer() );
But is it a good idea? No, except when you have to relate to an existing C style API. For C++ code, better restructure it to use C++ std::string throughout.
I need to implement a function in C++,
vector<string> generateSubstrings(string s),
that returns a vector of all substrings of a string. For example, the substrings of the string “rum” are the seven strings
“r”, “ru”, “rum”, “u”, “um”, “m”, “”.
The function has to be recursive and has to return the results as a vector.
Here is my code so far. It's only printing "r", "ru" and "rm". I'm having alot of trouble implementing this function. I've been working on this for the past few hours but I just can't figure out how to get it working as stated, so any help would be appreciated.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> generateSubstrings(string s, int num){
int index = num;
int SIZE = s.size();
vector<string> substrings;
if(index == s.size()){//BASE CASE
string temp = s.substr(index,1);
substrings.push_back(temp);
}
else{
for(int i = 0; i < SIZE; ++i){
string temp = s.at(index) + s.substr(i,i);
substrings.push_back(temp);
}
generateSubstrings(s, num + 1);
}
return substrings;
}
int main() {
vector<string> vec(20);
vec = generateSubstrings("rum", 0);
cout << endl << endl;cout << "PRINTING VECTOR" << endl;
for ( int i = 0; i<vec.size();++i){
cout << vec.at(i);
cout << endl;
}
cout << "DONE";
}
In your assignment there is written that the recursive function has to be declared like
vector<string> generateSubstrings(string s),
But you are trying to make another function recursive that declared like
vector<string> generateSubstrings(string s, int num);
So in any case your solution does not satisfy the requirement of the assignment.
The function can look the following way
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return {};
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
for ( const std::string &t : generateSubstrings( s.substr( 1 ) ) )
{
v.push_back( t );
}
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
Its output is
r
ru
rum
u
um
m
If you need also to include an empty string then you should change condition
if ( s.empty() ) return {};
in appropriate way. For example
if ( s.empty() ) return { "" };
Also in this case you should write
v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );
Also you can replace the loop in the shown function with method insert. For example
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return {};
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );
v.insert( v.end(), v2.begin(), v2.end() );
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
The program output will be the same as shown above.
Here is a program modification that includes an empty string in the vector.
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> generateSubstrings( std::string s )
{
if ( s.empty() ) return { "" };
std::vector<std::string> v;
v.reserve( s.size() * ( s.size() + 1 ) / 2 + 1 );
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v.push_back( s.substr( 0, i + 1 ) );
}
std::vector<std::string> v2 = generateSubstrings( s.substr( 1 ) );
v.insert( v.end(), v2.begin(), v2.end() );
return v;
}
int main()
{
std::string s( "rum" );
for ( const std::string &t : generateSubstrings( s ) )
{
std::cout << t << std::endl;
}
return 0;
}
Here's an answer using Python. It prints the correct result for "rum", but for "rumm" it prints two "m" substrings for obvious reasons:
def substrings(s):
result = []
if len(s) == 0:
result.append("")
if len(s) > 0:
result += substrings(s[1:])
for n in range(1,len(s)+1):
result.append(s[0:n])
return result
print substrings("rum")
print substrings("rumm")
The idea of the algorithm is the following: for "rum", the substrings are the substrings of "um" followed by "r", "ru" and "rum". For "um", the substrings are the substrings of "m" followed by "u" and "um". For "m", the substrings are the substrings of "" followed by "m". For "", the substrings are simply "". So, the final list is "", "m", "u", "um", "r", "ru", "rum".
Although this isn't C++, you should be able to translate the code to C++. But that may not necessarily be what you want as "rumm" has two "m" substrings. If you think that "rumm" should have only one "m" substring, please leave a comment and I'll post another answer.
First, you should pay attention about code indent.
Then, I don't look your code, I wrote some code to achieve your aim, as follow:
void generateSubstrings(string s, int num, vector<string> &sta)
{
if (num == s.size())
return;
auto b = begin(s) + num;
string temp = "";
temp += *b;
sta.push_back(temp);
b++;
while (b != end(s))
{
temp += *b;
sta.push_back(temp);
b++;
}
generateSubstrings(s, num + 1, sta);
}
How can I insert a character into a string exactly after 1 character?
I need to insert '|' into
the string after every other character.
In other words (C++): "Tokens all around!"
Turns into: "T|o|k|e|n|s| |a|l|l| |a|r|o|u|n|d|!" (no thats not an array)
Thanks
std::string tokenize(const std::string& s) {
if (!s.size()) {
return "";
}
std::stringstream ss;
ss << s[0];
for (int i = 1; i < s.size(); i++) {
ss << '|' << s[i];
}
return ss.str();
}
I think I'd use a standard algorithm and iterator:
std::string add_seps(std::string const &input, std::string sep="|") {
std::ostringstream os;
std::copy(input.begin(), input.end(), std::ostream_iterator<char>(os, sep));
return os.str();
}
As it stands, this adds a separator after the last character of the input. If you only want them between characters, you'd use an infix_ostream_iterator.
Here is my C++11 example (with gcc 4.7):
#include <string>
#include <iostream>
template<const unsigned num, const char separator>
void separate(std::string & input)
{
for ( auto it = input.begin(); (num+1) <= std::distance(it, input.end()); ++it )
{
std::advance(it,num);
it = input.insert(it,separator);
}
}
int main(void)
{
std::string input{"aaffbb3322ff77c"};
separate<3,' '>(input);
std::cout << input << std::endl;
separate<4,'+'>(input);
std::cout << input << std::endl;
return 0;
}
The result output is:
aaf fbb 332 2ff 77c
aaf +fbb +332 +2ff +77c
You can use
string& insert (size_t pos, const string& str);
You would have to loop through the string, inserting a character each time.
for (int i = 1; i < str.size(); i++) {
str << str.insert(i, '|');
i++;
}
Here's a slightly different approach that will only do 1 allocation for the resultant string so it should be slightly more efficient than some other suggestions.
std::string AddSeparators(const std::string & s)
{
if(s.size() <= 1)
return s;
std::string r;
r.reserve((s.size()*2)-1);
r.push_back(s[0]);
for(size_t i = 1; i < s.size(); ++i)
{
r.push_back('|');
r.push_back(s[i]);
}
return r;
}
I have the following piece of code. The code creates a vector Dataset, each element of which is a vector. It also creates a vector S.
I want to check which vector of Dataset contain vector of S. Apparently I am doing something wrong, because for the following example,
Dataset is:
a b c
a d
a b d
and S:
a b
it should print: 0 2
and for me it prints: 0 1 2
#include <iostream>
#include <fstream>
#include <sstream>
#include <string.h>
#include <string>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
class StringRef
{
private:
char const* begin_;
int size_;
public:
int size() const { return size_; }
char const* begin() const { return begin_; }
char const* end() const { return begin_ + size_; }
StringRef( char const* const begin, int const size )
: begin_( begin )
, size_( size )
{}
bool operator<(const StringRef& obj) const
{
return (strcmp(begin(),obj.begin()) > 0 );
}
};
/************************************************
* Checks if vector B is subset of vector A *
************************************************/
bool isSubset(std::vector<StringRef> A, std::vector<StringRef> B)
{
std::sort(A.begin(), A.end());
std::sort(B.begin(), B.end());
return std::includes(A.begin(), A.end(), B.begin(), B.end());
}
vector<StringRef> split3( string const& str, char delimiter = ' ' )
{
vector<StringRef> result;
enum State { inSpace, inToken };
State state = inSpace;
char const* pTokenBegin = 0; // Init to satisfy compiler.
for(auto it = str.begin(); it != str.end(); ++it )
{
State const newState = (*it == delimiter? inSpace : inToken);
if( newState != state )
{
switch( newState )
{
case inSpace:
result.push_back( StringRef( pTokenBegin, &*it - pTokenBegin ) );
break;
case inToken:
pTokenBegin = &*it;
}
}
state = newState;
}
if( state == inToken )
{
result.push_back( StringRef( pTokenBegin, &str.back() - pTokenBegin ) );
}
return result;
}
int main() {
vector<vector<StringRef> > Dataset;
vector<vector<StringRef> > S;
ifstream input("test.dat");
long count = 0;
int sec, lps;
time_t start = time(NULL);
cin.sync_with_stdio(false); //disable synchronous IO
for( string line; getline( input, line ); )
{
Dataset.push_back(split3( line ));
count++;
};
input.close();
input.clear();
input.open("subs.dat");
for( string line; getline( input, line ); )
{
S.push_back(split3( line ));
};
for ( std::vector<std::vector<StringRef> >::size_type i = 0; i < S.size(); i++ )
{
for(std::vector<std::vector<StringRef> >::size_type j=0; j<Dataset.size();j++)
{
if (isSubset(Dataset[j], S[i]))
{
cout << j << " ";
}
}
}
sec = (int) time(NULL) - start;
cerr << "C++ : Saw " << count << " lines in " << sec << " seconds." ;
if (sec > 0) {
lps = count / sec;
cerr << " Crunch speed: " << lps << endl;
} else
cerr << endl;
return 0;
}
Your StringRef type is dangerous because it contains a const char * pointer, but no concept of ownership. So the pointer could be invalidated at some point after the object is constructed.
And indeed this is what happens here: You have a single string (line) and create StringRefs with pointers to its internal data. When the string is later modified, these pointers are invalidated.
You should create a vector<std::string> instead to prevent this problem.