How to compare strings that shows number of differences - c++

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;
}

Related

Counting words in an input string in C++ **with consideration for typos

I've been looking for ways to count the number of words in a string, but specifically for strings that may contain typos (i.e. "_This_is_a___test" as opposed to "This_is_a_test"). Most of the pages I've looked at only handle single spaces.
This is actually my first time programming in C++, and I don't have much other programming experience to speak of (2 years of college in C and Java). Although what I have is functional, I'm also aware it's complex, and I'm wondering if there is a more efficient way to achieve the same results?
This is what I have currently. Before I run the string through numWords(), I run it through a trim function that removes leading whitespace, then check that there are still characters remaining.
int numWords(string str) {
int count = 1;
for (int i = 0; i < str.size(); i++) {
if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
bool repeat = true;
int j = 1;
while (j < (str.size() - i) && repeat) {
if (str[i + j] != ' ' && str[i + j] != '\t' && str[i + j] != '\n') {
repeat = false;
i = i + j;
count++;
}
else
j++;
}
}
}
return count;
}
Also, I wrote mine to take a string argument, but most of the examples I've seen used (char* str) instead, which I wasn't sure how to use with my input string.
You don't need all those stringstreams to count word boundary
#include <string>
#include <cctype>
int numWords(std::string str)
{
bool space = true; // not in word
int count = 0;
for(auto c:str){
if(std::isspace(c))space=true;
else{
if(space)++count;
space=false;
}
}
return count;
}
One solution is to utilize std::istringstream to count the number of words and to skip over spaces automatically.
#include <sstream>
#include <string>
#include <iostream>
int numWords(std::string str)
{
int count = 0;
std::istringstream strm(str);
std::string word;
while (strm >> word)
++count;
return count;
}
int main()
{
std::cout << numWords(" This is a test ");
}
Output:
4
Albeit as mentioned std::istringstream is more "heavier" in terms of performance than writing your own loop.
Sam's comment made me write a function that does not allocate strings for words. But just creates string_views on the input string.
#include <cassert>
#include <cctype>
#include <vector>
#include <string_view>
#include <iostream>
std::vector<std::string_view> get_words(const std::string& input)
{
std::vector<std::string_view> words;
// the first word begins at an alpha character
auto begin_of_word = std::find_if(input.begin(), input.end(), [](const char c) { return std::isalpha(c); });
auto end_of_word = input.begin();
auto end_of_input = input.end();
// parse the whole string
while (end_of_word != end_of_input)
{
// as long as you see text characters move end_of_word one back
while ((end_of_word != end_of_input) && std::isalpha(*end_of_word)) end_of_word++;
// create a string view from begin of word to end of word.
// no new string memory will be allocated
// std::vector will do some dynamic memory allocation to store string_view (metadata of word positions)
words.emplace_back(begin_of_word, end_of_word);
// then skip all non readable characters.
while ((end_of_word != end_of_input) && !std::isalpha(*end_of_word) ) end_of_word++;
// and if we haven't reached the end then we are at the beginning of a new word.
if ( end_of_word != input.end()) begin_of_word = end_of_word;
}
return words;
}
int main()
{
std::string input{ "This, this is a test!" };
auto words = get_words(input);
for (const auto& word : words)
{
std::cout << word << "\n";
}
return 0;
}
You can use standard function std::distance with std::istringstream the following way
#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
int main()
{
std::string s( " This is a test" );
std::istringstream iss( s );
auto count = std::distance( std::istream_iterator<std::string>( iss ),
std::istream_iterator<std::string>() );
std::cout << count << '\n';
}
The program output is
4
If you want you can place the call of std::distance in a separate function like
#include <iostream>
#include <sstream>
#include <string>
#include <iterator>
size_t numWords( const std::string &s )
{
std::istringstream iss( s );
return std::distance( std::istream_iterator<std::string>( iss ),
std::istream_iterator<std::string>() );
}
int main()
{
std::string s( " This is a test" );
std::cout << numWords( s ) << '\n';
}
If separators can include other characters apart from white space characters as for example punctuations then you should use methods of the class std::string or std::string_view find_first_of and find_first_not_of.
Here is a demonstration program.
#include <iostream>
#include <string>
#include <string_view>
size_t numWords( const std::string_view s, std::string_view delim = " \t" )
{
size_t count = 0;
for ( std::string_view::size_type pos = 0;
( pos = s.find_first_not_of( delim, pos ) ) != std::string_view::npos;
pos = s.find_first_of( delim, pos ) )
{
++count;
}
return count;
}
int main()
{
std::string s( "Is it a test ? Yes ! Now we will run it ..." );
std::cout << numWords( s, " \t!?.," ) << '\n';
}
The program output is
10
you can do it easily with regex
int numWords(std::string str)
{
std::regex re("\\S+"); // or `[^ \t\n]+` to exactly match the question
return std::distance(
std::sregex_iterator(str.begin(), str.end(), re),
std::sregex_iterator()
);
}

How to replace specific numbers by another number in a text file (C++)

First, I want to mention that I'm completely new to C++, so it's possible that I've overlooked any obvious solutions.
My task is to replace any non-zero number with 1.
The file looks like this:
Some text
0;0;0;0;0;0.236223;0;0;0;0;0;0.312757;0;0;0;0;0;0;0;0;0;0.367119;... (multiple lines)
and should turn into:
Some text
0;0;0;0;0;1;0;0;0;0;0;1;0;0;0;0;0;0;0;0;0;1,... (multiple lines)
My idea was to start out with a string replacement code. I tried the following:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream filein( "input.txt" );
ofstream fileout( "output.txt" );
string toreplace = "0";
string replacewith = "1";
string text;
while ( getline( filein, text ) )
{
for ( size_t p = text.find( toreplace ); p != string::npos;
p = text.find( toreplace , p ) )
text.replace( p, toreplace.length(), replacewith );
fileout << text << endl;
}
return 0;
}
This gives back:
1;1;1;1;1;1.236223;1;1;1;1;1;1.312757;1;1;1;1;1;1;1;1;1;1.367119,...
which is the opposite of what I want (not entirely). So, I thought it would be easy to declare toreplace and replacewith as floats and use != 0, which didn't work, especially because I can't define text as float because it contains ";". (Do I need to remove this delimiter? I would still need it in the final text file.)
The other problem in that code is that it replaces every zero, which includes "0.236223" turning into "1.236223". I assume this wouldn't matter when eventually working with floats instead of strings.
Is this the right approach to the given task, or would it be better to do it a different way? Thanks for any help given.
EDIT: There was a ";" at the end of each line, which I didn't want and used the string::pop_back() function to resolve the problem.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
ifstream filein("input.txt");
ofstream fileout("output.txt");
string toreplace = "0";
string replacewith = "1";
string text, new_text="";
while (getline(filein, text))
{
new_text = "";
double num;
while (sscanf_s(text.c_str(), "%lf;", &num))
{
if (num)
new_text += "1;";
else
new_text += "0;";
while (text.length() && text.at(0) != ';')
{
text.erase(0,1);
}
text.erase(0,1);
if (text.empty())
break;
}
fileout << new_text << endl;
}
return 0;
}
If you are able to simplify your input file the solution can be one-liner.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <fstream>
int main()
{
std::ifstream filein("./data/input.txt"); // Contains 1. 2.3 0. 3.2
std::ofstream fileout("./data/output.txt"); // Should contain 1. 1. 0. 1.
std::replace_copy_if(std::istream_iterator<double>(filein), std::istream_iterator<double>(), std::ostream_iterator<double>(fileout," "),
[](auto v) {return v != 0.; }, 1.);
return EXIT_SUCCESS;
}
If you have to stick with the ';' delimiter it can be done with a two-liner:
#include <iostream>
#include <sstream>
#include <iterator>
#include <algorithm>
#include <fstream>
int main()
{
std::ifstream filein("./data/input.txt"); // Contains 1. 2.3 0. 3.2
std::ofstream fileout("./data/output.txt"); // Should contain 1. 1. 0. 1.
std::stringstream replaced;
std::replace_copy_if(
std::istream_iterator<char>(filein),
std::istream_iterator<char>(),
std::ostream_iterator<char>(replaced),
[](auto v) { return v == ';'; },
' ');
std::replace_copy_if(
std::istream_iterator<double>(replaced),
std::istream_iterator<double>(),
std::ostream_iterator<double>(fileout,";"),
[](auto v) {return v != 0.; },
1.);
return EXIT_SUCCESS;
}
And, just to be complete. The solution with a regex. The regex gives you the ability to specify more precisely what you want to search:
And the result is also an one-liner (one Statement)
Please see:
#include <iostream>
#include <sstream>
#include <regex>
#include <iterator>
const std::string testData{"0;0;0;0 ; 0;0.236223;0;0;0;0;0;0.312757;0;0;0;0;0;0;0;0;0;0.367119"};
// This is, what we would like to match. Any number, int or double
const std::regex re{"([-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?)"};
int main()
{
std::transform(
std::sregex_token_iterator(testData.begin(), testData.end(), re, 1),
std::sregex_token_iterator(),
std::ostream_iterator<int>(std::cout,";"),
[](const std::string& s) -> int { double d=stod(s); return d==0.0 ? 0 : 1; }
);
return 0;
}
If you do not want to have the trailing ';' then you can use.
std::experimental::make_ostream_joiner(std::cout,";"),
instead of the std::ostream_iterator.

Binary number from 0 to n having the same numbers of chars/

I want to make proggram wchich will be generete numbers in binary base from o to n, and i want thme all have the same numbers of chars.
That's the code:
#include <iostream>
#include <bitset>
#include <string>
#include <vector>
#include <cmath>
#include <stdio.h>
using namespace std;
vector<string> temp;
int BinaryNumbers(int number)
{
const int HowManyChars= ceil(log(number));
for(int i = 0; i<number; i++)
{
bitset<HowManyChars> binary(i);
temp.push_back(binary.to_string());
}
}
int main(){
BinaryNumbers(3);
for(int i=0; i<temp.size();i++)
{
cout<<temp[i]<<endl;
}
return 0;
}
My problem is that I can't set bitset<> number(HowManyChars)"[Error] 'HowManyChars' cannot appear in a constant-expression"
A possible solution is to use the maximum sized bitset to create the string. Then only return the last count characters from the string.
In C++17 there is a new function to_chars.
One of the functions (1), takes the base in the last parameter.
// use numeric_limits to find out the maximum number of digits a number can have
constexpr auto reserve_chars = std::numeric_limits< int >::digits10 + 1; // +1 for '\0' at end;
std::array< char, reserve_chars > buffer;
int required_size = 9; // this value is configurable
assert( required_size < reserve_chars ); // a check to verify the required size will fit in the buffer
// C++17 Structured bindings return value. convert value "42" to base 2.
auto [ ptr, err ] = std::to_chars( buffer.data(), buffer.data() + required_size, 42 , 2);
// check there is no error
if ( err == std::errc() )
{
*ptr = '\0'; // add null character to end
std::ostringstream str; // use ostringstream to create a string pre-filled with "0".
str << std::setfill('0') << std::setw(required_size) << buffer.data();
std::cout << str.str() << '\n';
}

Creating 2D array of strings, values will be entered by user in C++

I'm trying to create a 2D array of strings which will include values entered by user.
I'm getting some errors in Visual Studio 2013 that say something along the lines of:
no suitable conversion function found from 'std::string' to 'const char*' exists.
Here's what I'm trying to do:
#include <iostream>
#include <string>
using namespace std;
int main() {
string stringOne, stringTwo, stringThree, stringFour, stringFive;
const char *myStrings[][5] = { stringOne,
stringTwo,
stringThree,
stringFour,
stringFive };
return 0;
}
You should use vectors and not arrays in C++. You can initialize a nested vector like this:
std::vector<std::vector<std::string>> v = {
{ stringOne, stringTwo, stringThree, stringFour, stringFive }
};
If you're getting input from the user, you don't have to use five different string variables. Instead, you can use push_back to increase the size of your vector. Something like this:
std::vector<std::vector<std::string>> v(5);
std::size_t row = 0;
std::size_t column = 0;
std::string input;
while (std::cin >> input)
{
if (row++ < 5)
v[column].push_back(input);
else
{
row = 0;
column++;
}
}
It is difficult to understand what you want. Maybe you mean the following:)
#include <vector>
#include <array>
#include <string>
//...
std::vector<std::array<std::string, 5>> myStrings;
Here is an example of this approach
#include <iostream>
#include <vector>
#include <array>
#include <string>
int main()
{
std::vector<std::array<std::string, 5>> myStrings;
myStrings.push_back( { "FirstString", "SecondString", "ThirdString",
"FourthString", "FifthString" } );
std::string firstString( "FirstString" );
std::string secondString( "SecondString" );
std::string thirdString( "ThirdString" );
std::string fourthString( "FourthString" );
std::string fifthString( "FifthString" );
myStrings.push_back( { firstString, secondString, thirdString,
fourthString, fifthString } );
for ( const auto &a : myStrings )
{
for ( const auto &s : a ) std::cout << s << ' ';
std::cout << std::endl;
}
return 0;
}
The output is
FirstString SecondString ThirdString FourthString FifthString
FirstString SecondString ThirdString FourthString FifthString
So you will get a table of five columns of objects of type std::string

Find string with the most different characters

I have an array of strings,
sparnus , sapnus , lol , noon ...
As you can see they both start and end with the same character.
What can i do to compare, let's say "sparnus" with "sapnus" and find out which string has more different characters?
sparnus has s p a r n u s (6 different characters)
sapnus has s a p n u s (5 different characters)
(note: s repeats itself, so it's not a different character)
is there a function? algorithm? tips and advice are welcome.
Standard container std::set itself is in fact an algorithm.:)
For example
#include <iostream>
#include <string>
#include <set>
int main()
{
std::string s1( "sparnus" ), s2( "sapnus" );
std::cout << std::set<char>( s1.begin(), s1.end() ).size() << std::endl;
std::cout << std::set<char>( s2.begin(), s2.end() ).size() << std::endl;
return 0;
}
The output is
6
5
So you can use standard algorithm std::max_element with a predicat that compares sizes of two sets built from strings.
Here is an example
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <cstring>
#include <iterator>
int main()
{
const size_t N = 10;
char s[][N] = { "lol" , "noon", "sparnus", "sapnus" };
auto it = std::max_element( std::begin( s ), std::end( s ),
[]( const char *a, const char *b )
{
return std::set<char>( a, a + std::strlen( a ) ).size() <
std::set<char>( b, b + std::strlen( b ) ).size();
} );
std::cout << *it<< std::endl;
return 0;
}
The output is
sparnus
Or you can use the approach that was shown in one post here that was deleted by unknown reason. For example You can sort all words by using standard algorithm std::sort then apply standard algorithm std::unique and standard C function std::strlen will give you the number of unique characters in each string.
template <typename InputIterator>
std::size_t countDiffChars( InputIterator first,
InputIterator last )
{
bool lookup[1 << CHAR_BIT] {};
std::size_t count = 0;
while (first != last)
{
auto&& val = lookup[(unsigned char)*first++];
count += !val;
val = true;
}
return count;
}
Usage:
char const str[] = "Hello";
auto c = countDiffChars(std::begin(s), std::end(s));
Demo.
use a boolean array of 256 entries and loop on the string and set each flag of the array to true indexing by the letter of the string. At the end you may count the number of trues in the array and found how many different characters are there.
If instead of a boolean array you use an int array you may also count how many times a letter is found if that serves somehow! ( that may be done if you don't want to use sets as a previous answer points ).
#include <iostream>
#include <string>
int cnt(std::string s){
bool b[0x100]={false};int r=0;
for(int i:s) b[i]=true;for(int i:b) r+=i;
return r;
}
int main(int argc, char **argv)
{ std::cout<<cnt("sparnus")<<" "<<cnt("sapnus")<<std::endl;
return 0;
}