Construct stringstream from char - c++

I implemented the following code, which does what it's supposed to, but I think that it can / should be simplified.
Basically, I need to create a vector of numbers, each containing one of the digits found in testString. Is there any way to construct the stringstream directly from a char (i. e. testString[i])? I'd rather not involve C-style functions, like atoi, if it can be done in a C++ way.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
int main ()
{
std::string testString = "abc123.bla";
std::string prefix = "abc";
std::vector<unsigned short> digits;
if (0 == testString.find(prefix))
{
for (size_t i = prefix.size(); i < testString.find("."); ++i)
{
int digit;
std::stringstream digitStream;
digitStream << testString[i];
digitStream >> digit;
digits.emplace_back(digit);
}
}
for (std::vector<unsigned short>::iterator digit = digits.begin(); digit < digits.end(); ++digit)
{
std::cout << *digit << std::endl;
}
return 0;
}

Assuming testString[i] is between '0' and '9', just do:
digits.emplace_back(testString[i] - '0');

See my original comment; subtract '0' from each digit character.
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cctype>
#include <functional>
#include <iostream>
...
std::string input = "abc123.bla";
std::string prefix = "abc";
std::vector<unsigned short> digits;
auto input_b = input.begin();
std::copy_if(input_b, std::find(input_b, input.end(), '.'),
std::back_inserter(digits), (int (*)(int)) std::isdigit);
auto digits_b = digits.begin();
auto digits_e = digits.end();
std::transform(digits_b, digits_e, digits_b,
std::bind2nd(std::minus<unsigned short>(), '0'));
std::copy(digits_b, digits_e,
std::ostream_iterator<unsigned short>(std::cout, "\n"));
It can even be shortened if you don't need digits to contain the intermediate digit values.
std::transform(digits.begin(), digits.end(),
std::ostream_iterator<unsigned short>(std::cout, "\n"),
std::bind2nd(std::minus<unsigned short>(), '0'));

Related

C++ masking all characters of a string except for the last n characters with <algorithm>

In C++, how to mask all characters of string except last in character using <algorithm>?
ie;
I have a string
std::string barcode = "300001629197835714";
I would like to get output as
**************5714
This program can be easily done in a conventional way,
std::string barcode = "300001629197835714";
std::string out;
for (int i=0;i<barcode.length();i++)
{
if (i<barcode.length()-4)
{
out+="*";
}
else
{
out+=barcode[i];
}
}
std::cout<<out;
But can I do this with std::replace_if or with std::transform or any function from <algorithm> header?
Here's a solution using the algorithm library and iterators. I'm using std::prev to get an iterator 4 characters before end(), then std::fill to replace the digits in the range [begin, end - 4) with '*'.
#include <algorithm>
#include <string>
#include <iterator>
#include <iostream>
int main()
{
std::string barcode = "300001629197835714";
std::fill(barcode.begin(), std::prev(std::end(barcode), 4), '*');
std::cout << barcode;
}
Note that
std::prev(std::end(barcode), 4)
will cause undefined behavior if barcode is less than 4 characters.
Neither std::replace_if nor std::transform is necessary. The simple
barcode.replace(0, barcode.size() - 4, barcode.size() - 4, '*');
std::cout << barcode;
Make sure barcode.size() is greater than 4.
std::basic_string::replace (6).
For string manipulation I usually revert to regex instead of algorithm
#include <iostream>
#include <regex>
#include <string>
int main()
{
std::string barcode = "300001629197835714";
std::regex expression{ ".(?=.{4,}$)" };
auto secret = std::regex_replace(barcode, expression, "*");
std::cout << secret << std::endl;
}
You can use replace_if with a always true returning predicate and simply use the iterators from begin() to end()-4:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string code = "1234564598745774";
int numVisibleDigits = 4;
std::replace_if(
code.begin(),
code.end()-numVisibleDigits,
[](char){return true;},
'*'
);
std::cout << code << std::endl;
}
it can be done with std::replace_if
std::string barcode = "300001629197835714";
int nonMasklenght = 4;
std::replace_if(barcode.begin(), barcode.end(), [&barcode, &nonMasklenght](const char &x)->bool {
size_t index = &x - &barcode[0];
return (index <( barcode.length() - nonMasklenght) );},
'*');
std::cout<<barcode;
ideone example
IfI look at the original code of the OP, then we can clearly see that the original string should not be modified.
Only masked output should be shown.
So, nearly all answers, except from Pepijn Kramer, are wrong.
And by the way. A Modification is not required and is not necessary. Simply show the masked output:
#include <iostream>
#include <string>
int main() {
// Our base data. It is const. It will not be modified
const std::string barcode = "300001629197835714";
// No algorithm and code
// - - -
// Just output
std::cout << std::string(14, '*') << barcode.substr(barcode.length() - 4) << '\n';
return 0;
}

string to numbers (vector array of int type)conversion

The function takes a string containing of comma(,) separated numbers as string and converts into numbers. Sometimes it produces a garbage value at the end.
vector<int> parseInts(string str)
{
int as[200]={0};
int i=0,j=0;
for(;str[i]!='\0';i++)
{
while(str[i]!=','&&str[i]!='\0')
{as[j]= as[j]*10 +str[i] -'0';
i++;}
j++;
}
vector<int>rr;
for(int i=0;i<j;i++)
rr.push_back(as[i]);
return rr;
}
If you're writing in C++, use C++ features instead of C-style string manipulation. You can combine std::istringstream, std::getline(), and std::stoi() into a very short solution. (Also note that you should take the argument by const reference since you do not modify it.)
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
std::vector<int> parseInts(std::string const & str) {
std::vector<int> values;
std::istringstream src{str};
std::string buf;
while (std::getline(src, buf, ',')) {
// Note no error checking on this conversion -- exercise for the reader.
values.push_back(std::stoi(buf));
}
return values;
}
(Demo)
The code doesn't handle whitespace and inputs with more than 200 numbers.
An alternative working solution:
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <vector>
std::vector<int> parseInts(std::string s) {
std::replace(s.begin(), s.end(), ',', ' ');
std::istringstream ss(std::move(s));
return std::vector<int>{
std::istream_iterator<int>{ss},
std::istream_iterator<int>{}
};
}
int main() {
auto v = parseInts("1,2 , 3 ,,, 4,5,,,");
for(auto i : v)
std::cout << i << '\n';
}
Output:
1
2
3
4
5
You never really asked a question. If you are looking for an elegant method, then I provide that below. If you are asking us to debug the code, then that is a different matter.
First here is a nice utility for splitting a string
std::vector<std::string> split(const std::string& str, char delim) {
std::vector<std::string> strings;
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
strings.push_back(str.substr(start, end - start));
}
return strings;
}
First split the string on commas:
std::vector<std::string> strings = split(str, ',');
Then covert each to an int
std::vector<int> ints;
for (auto s : strings)
ints.push_back(std::stoi(s))

My function does not always work because of the second argument

My trouble is that my function not always work, and i don't know why.
Here's my code:
#include <stdio.h>
#include <string.h>
#include <cstring>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <string>
using namespace std;
void fill_zeros(std::string& fill_zeros_str, int fill_zeros_num){
if (fill_zeros_str.length()<fill_zeros_num){
int i = 0;
for (i=0;i<=((int)fill_zeros_num)-((int)fill_zeros_str.length());i++){
fill_zeros_str = "0"+fill_zeros_str;
}
}
}
int main(){
string testString = to_string(2);
fill_zeros(testString,7);
cout << testString << "\n";
return 0;
}
The second argument of fill_zeros (fill_zeros_num) does not work all the time, and I don't know why.
Because in
for (i=0;i<=((int)fill_zeros_num)-((int)fill_zeros_str.length());i++)
the length of fill_zeros_str changes as you add zeros(decrease by one), and you are also adding one to i(so, the start is adding by one, and the end is decreasing by one). So the best way is to define a length at the beginning of the function to store the string length.
Your loop is modifying the std::string on each iteration, which affects its length(). The loop is re-evaluating the length() on each iteration.
You need to calculate the number of zeros wanted and save that value to a local variable first, and then use that variable in your loop. Also, your loop needs to use < instead of <=.
Try this:
void fill_zeros(std::string& str, size_t min_length){
if (str.length() < min_length){
size_t fill_zeros_num = min_length - str.length();
for (size_t i = 0; i < fill_zeros_num; ++i){
str = "0" + str;
// or: str.insert(0, "0");
// or: str.insert(0, '0');
// or: str.insert(str.begin(), '0');
}
}
}
Live Demo
However, there is a much simpler way to implement fill_zeros() that doesn't involve using a manual loop at all:
void fill_zeros(std::string& str, size_t min_length){
if (str.length() < min_length){
str = std::string(min_length - str.length(), '0') + str;
// or: str.insert(0, std::string(min_length - str.length(), '0'));
// or: str.insert(str.begin(), std::string(min_length - str.length(), '0'));
// or: str.insert(0, min_length - str.length(), '0');
// or: str.insert(str.begin(), min_length - str.length(), '0');
}
}
Live Demo
Alternatively:
#include <sstream>
#include <iomanip>
void fill_zeros(std::string& str, size_t min_length){
if (str.length() < min_length){
std::ostringstream oss;
oss << std::setw(min_length) << std::setfill('0') << str;
str = oss.str();
}
}
Live Demo
In which case, you could simply get rid of fill_zeros() altogether and apply the I/O manipulators directly to std::cout in main() instead:
#include <iostream>
#include <iomanip>
int main(){
std::cout << std::setw(7) << std::setfill('0') << 2 << "\n";
return 0;
}
Live Demo

How to compare strings that shows number of differences

I'm new to programming so I'm sorry if my question is hard to understand.
I have a string modelAnswer as such
string modelAnswer = "ABABACDA";
So it's supposed to be the answers to a quiz and I'm trying to make it so that if user's input is
string studentAnswer = "ABADBDBB"; for example the program will show that I have gotten 3 points as the first three letters of the studentAnswer string matches the modelAnswer.
You can use standard algorithm std::inner_product as for example
#include <iostream>
#include <string>
#include <numeric>
#include <functional>
int main()
{
std::string modelAnswer( "ABABACDA" );
std::string studentAnswer( "ABADBDBB" );
auto n = std::inner_product( modelAnswer.begin(), modelAnswer.end(),
studentAnswer.begin(), size_t( 0 ),
std::plus<size_t>(), std::equal_to<char>() );
std::cout << n << std::endl;
return 0;
}
The program output is
3
It is assumed that the strings have the same length. Otherwise you should use the less string as the first pair of arguments.
For example
#include <iostream>
#include <string>
#include <numeric>
#include <algorithm>
#include <functional>
#include <iterator>
int main()
{
std::string modelAnswer( "ABABACDA" );
std::string studentAnswer( "ABADBDBB" );
auto n = std::inner_product( modelAnswer.begin(),
std::next( modelAnswer.begin(), std::min( modelAnswer.size(), studentAnswer.size() ) ),
studentAnswer.begin(), size_t( 0 ),
std::plus<size_t>(), std::equal_to<char>() );
std::cout << n << std::endl;
return 0;
}
If you are using standard strings, with the proper includes (Mainly #include <string>), you can write a simple for loop to iterate over each character, comparing them.
std::string answer = "ABABACDA";
std::string stringToCompare = "ABADBDBB";
int score = 0;
for (unsigned int i = 0; (i < answer.size()) && (i < stringToCompare.size()); ++i)
{
if (answer[i] == stringToCompare[i])
{
++score;
}
}
printf("Compare string gets a score of %d.\n", score);
The above code works for me, printing the following result:
Compare string gets a score of 3.
Using a stringstream, you can push one character at a time into temporary variables and test for equivalence in a loop.
#include <iostream>
#include <string>
#include <sstream>
int main() {
std::istringstream model("ABABACDA");
std::istringstream student("ABADBDBB");
int diff = 0;
char m, s;
while ((model >> m) && (student >> s))
if (m != s) diff++;
std::cout << diff << std::endl; // 5
return 0;
}

Change String Array to tolower

In my program I have a text file that is read into an array that tokenizes each word. I need it this way so that I can compare the words to the words found in my Binary Tree. Issue is... some duplicates of words are not formatted the same way (one is uppercase and one is lowercase) and I need them to be so they can be found in my Binary Tree.
So my question is: How do I change my whole array to lowercase?
Here is what I tried so far:
#include <iostream>
#include "Binary_SearchTree.h"
#include "Node.h"
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
const int SIZE = 100;
string myArray[SIZE];
int main() {
// first constructor will be used since it is empty
Binary_SearchTree<string> *tree = new Binary_SearchTree<string>();
string token, lines;
ifstream file("hashtags.txt");
while (getline(file, lines)){
tree -> insertNode(lines);
}
// Convert all strings in myArray to all-lower
myArray = tolower(myArray);
// tokenize tweet into an array to search
ifstream tweet1("exampleTweet.txt");
if(tweet1.is_open())
{
while (getline(tweet1, token)){
for(int i = 0; i < SIZE; ++i)
{
tweet1 >> myArray[i];
}
}
tweet1.close();
}
With C++11 and later, you can downcase an array of strings like this:
#include <algorithm>
#include <cctype>
#include <string>
std::string myArray[23];
// ...
for (std::string & s : myArray)
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::tolower(c); });
Alternatively:
for (std::string & s : myArray)
std::for_each(s.begin(), s.end(), [](char & c) {
c = std::tolower(static_cast<unsigned char>(c)); });
Or even:
for (std::string & s : myArray)
for (char & c : s)
c = std::tolower(static_cast<unsigned char>(c));
If you only have C++98 support, use the following loops:
for (std::size_t i = 0; i != 23; ++i)
{
std::string & s = myArray[i];
for (std::string::iterator it = s.begin(), e = s.end(); it != e; ++it)
{
*it = std::tolower(static_cast<unsigned char>(*it));
}
}
You get the idea.
Don't forget to convert the character to unsigned char, since that's what std::tolower expects. (See this question for a discussion.) Many C I/O functions are expressed in terms of unsigned char-converted-to-int, since usually an int is big enough to represent all values of an unsigned char plus additional out-of-band information, and char and unsigned char are roundtrip convertible both ways as well as layout-compatible.