Checking user input with string array - c++

string code[4] = {"G", "O", "B", "R"};
string colorPegs[6] = {"R", "B", "Y", "G", "O", "B"};
string userGuess;
getline(cin,userGuess);
Those are the important lines of code in my question.
The user will input 4 letters, for example "BBYG"
How can I make a for loop that checks the first char of user input with the first char of code, and sees if it matches?
for example:
string code is GOBR
user inputs BBBR. In user input, only one letter matches the code, which is the third B, how can I check for this with a for loop?

Try with this code assuming you want to find a match if they are at the same position :
for(int i = 0; i < code.length(); ++i)
{
if(code[i] == user[i]) return true; // Match found here.
}
return false;

Try this:
#include <algorithm>
int main()
{
std::string code{"GOBR"};
std::string input;
std::cin >> input;
auto match = [&] (char c)
{
return std::find(code.begin(), code.end(), c) != code.end();
};
if (std::any_of(input.begin(), input.end(), match))
{
// match
}
}

Related

What is the effective way to replace all occurrences of a character with every character in the alphabet?

What is the effective way to replace all occurrences of a character with every character in the alphabet in std::string?
#include <algorithm>
#include <string>
using namespace std;
void some_func() {
string s = "example *trin*";
string letters = "abcdefghijklmnopqrstuvwxyz";
// replace all '*' to 'letter of alphabet'
for (int i = 0; i < 25; i++)
{
//replace letter * with a letter in string which is moved +1 each loop
replace(s.begin(), s.end(), '*', letters.at(i));
i++;
cout << s;
}
how can i get this to work?
You can just have a function:
receiving the string you want to operate on, and the character you want to replace, and
returning a list with the new strings, once the replacement has been done;
for every letter in the alphabet, you could check if it is in the input string and, in that case, create a copy of the input string, do the replacement using std::replace, and add it to the return list.
[Demo]
#include <algorithm> // replace
#include <fmt/ranges.h>
#include <string>
#include <string_view>
#include <vector>
std::vector<std::string> replace(const std::string& s, const char c) {
std::string_view alphabet{"abcdefghijklmnopqrstuvwxyz"};
std::vector<std::string> ret{};
for (const char l : alphabet) {
if (s.find(c) != std::string::npos) {
std::string t{s};
std::ranges::replace(t, c, l);
ret.emplace_back(std::move(t));
}
}
return ret;
}
int main() {
std::string s{"occurrences"};
fmt::print("Replace '{}': {}\n", 'c', replace(s, 'c'));
fmt::print("Replace '{}': {}\n", 'z', replace(s, 'z'));
}
// Outputs:
//
// Replace 'c': ["oaaurrenaes", "obburrenbes", "oddurrendes"...]
// Replace 'z': []
Edit: update on your comment below.
however if I wanted to replace 1 character at a time for example in
occurrences there are multiple "C" if i only wanted to replace 1 of
them then run all outcomes of that then move onto the next "C" and
replace all of them and so on, how could that be done?
In that case, you'd need to iterate over your input string, doing the replacement to one char at a time, and adding each of those new strings to the return list.
[Demo]
for (const char l : alphabet) {
if (s.find(c) != std::string::npos) {
for (size_t i{0}; i < s.size(); ++i) {
if (s[i] == c) {
std::string t{s};
t[i] = l;
ret.emplace_back(std::move(t));
}
}
}
}
// Outputs:
//
// Replace 'c': ["oacurrences", "ocaurrences", "occurrenaes"...]
// Replace 'z': []

Extracting all words separated by non-alphabetical characters

Given a string such as:
std::string word = "Hello World!it's#.-/sunday";
I want to extract all the words which are separated by non-alphabetical letters stored in a container like a vector, so for this case it would be:
Hello, World, it, s, sunday
My initial try was to use isalpha() along with an index count to substr() accordingly like so:
std::string word = "Hello World!it's#.-/sunday";
int count = 0, index = 0;
std::string temp;
for (; count < word.length();count++){
if (!isalpha(word[count])){
temp = word.substr(index,count);
index = count;
}
}
But this does not work as I thought it would as the index does not update fast enough resulting in words mixed with non-alphabetical characters. Is there perhaps a function or a better way to extract said words?
You can try the following code. It constructs the words char by char.
#include <string>
#include <iostream>
#include <vector>
int main()
{
std::string phrase = "Hello World!it's#.-/sunday";
std::vector<std::string> words;
std::string tmp;
for (const char &c:phrase)
{
if (isalpha(c))
{
tmp.push_back(c);
}
else
{
words.push_back(tmp);
tmp = "";
}
}
if (!tmp.empty())
{
words.push_back(tmp);
}
for (const auto w : words)
{
std::cout << w << std::endl;
}
return 0;
}
one easy way is that replace all the non-alphabetical char to space than
split around space.

Replacing words in a sentence?

I'm trying to replace multiple words with their "pirate pair", for example:
Normal: "Hello sir, where is the hotel?"
Pirate: "Ahoy matey, whar be th' fleagbag inn?"
This is what I tried before:
#include<iostream>
#include<string>
#include<conio.h>
using namespace std;
void speakPirate(string s);
int main()
{
string phrase;
cout << "Enter the phrase to Pirate-Ize: ";
getline(cin, phrase);
speakPirate(phrase);
_getch();
return 0;
}
void speakPirate(string s)
{
int found;
// list of pirate words
string pirate[12] = { "ahoy", "matey", "proud beauty", "foul blaggart", "scurvy dog", "whar", "be", "th'", "me", "yer", "galley", "fleabag inn" };
// list of normal words
string normal[12] = { "hello", "sir", "madam", "officer", "stranger", "where", "is", "the", "my", "your", "restaurant", "hotel" };
for (int i = 0; i < s.length(); i++)
{
found = s.find(normal[i]);
if (found > -1)
{
string left = s.substr(0, found - 1); // get left of the string
string right = s.substr(found + pirate[i].length(), s.length()); // get right of string
s = left + " " + pirate[i] + " " + right; // add pirate word in place of normal word
}
}
cout << s;
}
But it didn't really work and was very buggy, so I tried using the replace() function instead:
#include<iostream>
#include<string>
#include<conio.h>
using namespace std;
void speakPirate(string s);
int main()
{
string phrase;
cout << "Enter the phrase to Pirate-Ize: ";
getline(cin, phrase);
speakPirate(phrase);
_getch();
return 0;
}
void speakPirate(string s)
{
int found;
// list of pirate words
string pirate[12] = { "ahoy", "matey", "proud beauty", "foul blaggart", "scurvy dog", "whar", "be", "th'", "me", "yer", "galley", "fleabag inn" };
// list of normal words
string normal[12] = { "hello", "sir", "madam", "officer", "stranger", "where", "is", "the", "my", "your", "restaurant", "hotel" };
for (int i = 0; i < s.length(); i++)
{
found = s.find(normal[i]);
if (found > -1)
{
s.replace(found, found + pirate[i].length(), pirate[i]);
}
}
cout << s;
}
I'm not sure why, but this doesn't really work either. I also notice that when I try changing a larger word into a smaller word, some of the original word is leftover, for example:
Enter the phrase to Pirate-Ize: hello
ahoyo
And I just noticed that it sometimes might not even change the word at all, for example:
Enter the phrase to Pirate-Ize: where
where
How come? Could someone please tell me what I need to do or a more effective solution that I could implement? Thanks a lot.
Here you iterate over the length of the text:
for (int i = 0; i < s.length(); i++)
It should be the length of the array of texts, something like
for (int i = 0; i < 12; i++)
However, you should use a std::map to model the mapping between the normal words and their pirate version.
std::map<std::string, std::string> words = {
{"hello", "ahoy"},
// .. and so on
};
for(auto const & kvp : words)
{
// replace kvp.first with kvp.second
}
Marius is correct that the major error is that you need to iterate over the length of the arrays. A different way than mapping would be to use erase() and insert() where you used replace(). replace() does not account for the lengths of the strings being different, but removing a substring and then adding in a new substring will. This can be done as follows
for (int i = 0; i < 12; i++)
{
found = s.find(normal[i]);
// Locate the substring to replace
int pos = s.find( normal[i], found );
if( pos == string::npos ) break;
// Replace by erasing and inserting
s.erase( pos, normal[i].length() );
s.insert( pos, pirate[i] );
}

How to extract words out of a string and store them in different array in c++

How to split a string and store the words in a separate array without using strtok or istringstream and find the greatest word?? I am only a beginner so I should accomplish this using basic functions in string.h like strlen, strcpy etc. only. Is it possible to do so?? I've tried to do this and I am posting what I have done. Please correct my mistakes.
#include<iostream.h>
#include<stdio.h>
#include<string.h>
void count(char n[])
{
char a[50], b[50];
for(int i=0; n[i]!= '\0'; i++)
{
static int j=0;
for(j=0;n[j]!=' ';j++)
{
a[j]=n[j];
}
static int x=0;
if(strlen(a)>x)
{
strcpy(b,a);
x=strlen(a);
}
}
cout<<"Greatest word is:"<<b;
}
int main( int, char** )
{
char n[100];
gets(n);
count(n);
}
The code in your example looks like it's written in C. Functions like strlen and strcpy originates in C (although they are also part of the C++ standard library for compatibility via the header cstring).
You should start learning C++ using the Standard Library and things will get much easier. Things like splitting strings and finding the greatest element can be done using a few lines of code if you use the functions in the standard library, e.g:
// The text
std::string text = "foo bar foobar";
// Wrap text in stream.
std::istringstream iss{text};
// Read tokens from stream into vector (split at whitespace).
std::vector<std::string> words{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
// Get the greatest word.
auto greatestWord = *std::max_element(std::begin(words), std::end(words), [] (const std::string& lhs, const std::string& rhs) { return lhs.size() < rhs.size(); });
Edit:
If you really want to dig down in the nitty-gritty parts using only functions from std::string, here's how you can do to split the text into words (I leave finding the greatest word to you, which shouldn't be too hard):
// Use vector to store words.
std::vector<std::string> words;
std::string text = "foo bar foobar";
std::string::size_type beg = 0, end;
do {
end = text.find(' ', beg);
if (end == std::string::npos) {
end = text.size();
}
words.emplace_back(text.substr(beg, end - beg));
beg = end + 1;
} while (beg < text.size());
I would write two functions. The first one skips blank characters for example
const char * SkipSpaces( const char *p )
{
while ( *p == ' ' || *p == '\t' ) ++p;
return ( p );
}
And the second one copies non blank characters
const char * CopyWord( char *s1, const char *s2 )
{
while ( *s2 != ' ' && *s2 != '\t' && *s2 != '\0' ) *s1++ = *s2++;
*s1 = '\0';
return ( s2 );
}
try to get a word in a small array(obviously no word is >35 characters) you can get the word by checking two successive spaces and then put that array in strlen() function and then check if the previous word was larger then drop that word else keep the new word
after all this do not forget to initialize the word array with '\0' or null character after every word catch or this would happen:-
let's say 1st word in that array was 'happen' and 2nd 'to' if you don't initialize then your array will be after 1st catch :
happen
and 2nd catch :
*to*ppen
Try this. Here ctr will be the number of elements in the array(or vector) of individual words of the sentence. You can split the sentence from whatever letter you want by changing function call in main.
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void split(string s, char ch){
vector <string> vec;
string tempStr;
int ctr{};
int index{s.length()};
for(int i{}; i<=index; i++){
tempStr += s[i];
if(s[i]==ch || s[i]=='\0'){
vec.push_back(tempStr);
ctr++;
tempStr="";
continue;
}
}
for(string S: vec)
cout<<S<<endl;
}
int main(){
string s;
getline(cin, s);
split(s, ' ');
return 0;
}

C++ Counting words in a file between two words

I am currently trying to count the number of words in a file. After this, I plan to make it count the words between two words in the file. For example. My file may contain. "Hello my name is James". I want to count the words, so 5. And then I would like to count the number of words between "Hello" and "James", so the answer would be 3. I am having trouble with accomplishing both tasks.
Mainly due to not being exactly sure how to structure my code.
Any help on here would be greatly appreciated. The code I am currently using is using spaces to count the words.
Here is my code:
readwords.cpp
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
return nextword;
}
}
bool ReadWords::isNextWord()
{
if(!wordfile.eof())
{
return true;
}
else
{
return false;
}
}
main.cpp
main()
{
int count = 0;
ReadWords rw("hamlet.txt");
while(rw.isNextWord()){
rw.getNextWord();
count++;
}
cout << count;
rw.close();
}
What it does at the moment is counts the number of characters. I'm sure its just a simple fix and something silly that I'm missing. But I've been trying for long enough to go searching for some help.
Any help is greatly appreciated. :)
Rather than parse the file character-by-character, you can simply use istream::operator<<() to read whitespace-separated words. << returns the stream, which evaluates to true as a bool when the stream can still be read from.
vector<string> words;
string word;
while (wordfile >> word)
words.push_back(word);
There is a common formulation of this using the <iterator> and <algorithm> utilities, which is more verbose, but can be composed with other iterator algorithms:
istream_iterator<string> input(wordfile), end;
copy(input, end, back_inserter(words));
Then you have the number of words and can do with them whatever you like:
words.size()
If you want to find "Hello" and "James", use find() from the <algorithm> header to get iterators to their positions:
// Find "Hello" anywhere in 'words'.
const auto hello = find(words.begin(), words.end(), "Hello");
// Find "James" anywhere after 'hello' in 'words'.
const auto james = find(hello, words.end(), "James");
If they’re not in the vector, find() will return words.end(); ignoring error checking for the purpose of illustration, you can count the number of words between them by taking their difference, adjusting for the inclusion of "Hello" in the range:
const auto count = james - (hello + 1);
You can use operator-() here because std::vector::iterator is a “random-access iterator”. More generally, you could use std::distance() from <iterator>:
const auto count = distance(hello, james) - 1;
Which has the advantage of being more descriptive of what you’re actually doing. Also, for future reference, this kind of code:
bool f() {
if (x) {
return true;
} else {
return false;
}
}
Can be simplified to just:
bool f() {
return x;
}
Since x is already being converted to bool for the if.
To count:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
for (std::string word; infile >> word; ++count) { }
To count only between start and stop:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
bool active = false;
for (std::string word; infile >> word; )
{
if (!active && word == "Hello") { active = true; }
if (!active) continue;
if (word == "James") break;
++count;
}
I think "return nextword;" should instead be "else return nextword;" or else you are returning from the function getNextWord every time, no matter what the char is.
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
else return nextword;//only returns on a space
}
}
To count all words:
std::ifstream f("hamlet.txt");
std::cout << std::distance (std::istream_iterator<std::string>(f),
std::istream_iterator<std::string>()) << '\n';
To count between two words:
std::ifstream f("hamlet.txt");
std::istream_iterator<std::string> it(f), end;
int count = 0;
while (std::find(it, end, "Hello") != end)
while (++it != end && *it != "James")
++count;
std::cout << count;
Try this:
below the line
nextword.append(1, c);
add
continue;