Check user input by each char if exists in char array [duplicate] - c++

I want to write a function that determines if all the letters of an inputted word are contained in another string of acceptable letters.
bool ContainsOnly(std::string inputtedWord, std::string acceptableLetters)
{
// ... how do I write this?
}
Here's my testing framework:
bool Tester(std::string inputtedWord, std::string acceptableLetters)
{
if (ContainsOnly(inputtedWord, acceptableLetters)) {
std::cout << "Good!" << std::endl;
return true;
}
else {
std::cout << "No good!" << std::endl;
return false;
}
}
int main()
{
std::string acceptableLetters;
std::string inputtedWord;
std::cout << "Please input the acceptable letters in your words: " << std::endl;
std::cin >> acceptableLetters;
while (inputtedWord != "STOP")
{
std::cout << "Please input the word you would like to test: (type STOP to end testing): " << std::endl;
std::cin >> inputtedWord;
Tester(inputtedWord, acceptableLetters);
}
return 0;
}
I want the following output:
Please input the acceptable letters in your words: CODING
Please input the word you would like to test: (type STOP to end testing): COIN
Good!
Please input the word you would like to test: (type STOP to end testing): COP
No good!

You can use find_first_not_of like this:
bool ContainsOnly(std::string inputtedWord, std::string acceptableLetters)
{
return inputtedWord.find_first_not_of(acceptableLetters) == std::string::npos;
}
Here's a demo.

Put all the acceptable characters to std::set.
Judge if all characters in the strings are in the set via std::all_of.
#include <set>
#include <algorithm>
bool ContainsOnly(std::string inputtedWord, std::string acceptableLetters)
{
std::set<char> okSet(acceptableLetters.begin(), acceptableLetters.end());
return std::all_of(inputtedWord.begin(), inputtedWord.end(),
[&okSet](char c)
{
return okSet.find(c) != okSet.end();
});
}

Related

Why does string find not display the intended output

I want to print an error message if the user's input string does not match what is intended. However, std::string::npos does not print it.
void AdvisorBot::printHelpCMD() {
std::string prod ("prod");
std::string min ("min");
std::string max ("max");
std::string checkInput("prod min max");
std::cout << "\nEnter the command you need help with e.g <prod>: " << std::endl;
std::string cmd;
std::getline(std::cin, cmd); //takes input and store into string cmd
if (cmd == prod) {
std::cout << "\nThis command lists all the available products on the exchange.\n" << std::endl;
}
if (cmd.find(checkInput) != std::string::npos) { //to loop over inputted strings and check if matches above NOT WORKING
std::cout << "\nCommand does not exist\n" << std::endl;
}
cmd.find(checkInput) looks for the whole string checkInput in cmd which is presumably not what you want.
If you want to check whether your string is one of a list of values std::set might work better:
#include <set>
...
std::set<std::string> checkInput { "prod", "min", "max" };
if (checkInput.find(cmd) == checkInput.end()) {
std::cout << "\nCommand does not exist\n" << std::endl;
}

Check all occurrences of a letter appear before another letter C++

I have a string S consisting of N letters 'a' or 'b'. This should return true when all occurrences of 'a' are before all occurrences of 'b' and return false otherwise.
b does not need to occur in S and a does not need to occur in S
For example
S='aabbb' returns true
S = 'ba' returns false
S = 'aaa' returns true
S= 'b' returns true
S='abba' returns false
this is my solution but it displays 1 extra true. I don't know why.
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector <string> vec;
int n;
string item;
int contora=0,contorb=0;
cout<<"n: ";
cin>>n;
cout << "Enter a string: ";
for(int i=0;i<= n;i++){
getline(cin, item);
//cin>>item;
vec.push_back(item);
}
for (int j=0; j <= n; j++) {
cout << vec[j];
}
cout<<endl;
for (auto of:vec) {
if (of.find("ba") != std::string::npos)
cout << "false";
else
cout<<"true";
}
return 0;
}
Wording it differently, you're trying to check if there are any characters in the string that come after a. If the answer is no, your function will return true, and false otherwise.
bool HasCorrectOrder(char prefix_char, char suffix_char, std::string_view str) {
if (str.empty()) {
return true;
}
// Run through all the preceeding characters.
int index = 0;
while (str[index] == prefix_char && index < str.size()) {
++index;
}
// At this point, if we've reached the end of the string, that means there are
// no characters after the preceeding character. So we can return true.
if (index == str.size()) {
return true;
}
// As there are more characters left, they should all be equal to the
// suffix_char in order for the ordering to be correct.
while (str[index] == suffix_char && index < str.size()) {
++index;
}
return (index == str.size());
}
Running a quick check:
void RunTest() {
std::vector<std::string> test_strings = {"aabbb", "ba", "aaa", "b", "abba"};
for (std::string_view str : test_strings) {
std::cout << "S = " << str << " returns "
<< (HasCorrectOrder(/*prefix_char=*/'a',
/*suffix_char=*/'b', str) ? "true" : "false")
<< std::endl;
}
}
returns:
S = aabbb returns true
S = ba returns false
S = aaa returns true
S = b returns true
S = abba returns false
Adding some debug output to the code shows a couple of issues:
The first for loop reads in n+1 strings, while we are expecting the user to enter only n strings. The second for loop also prints n+1 strings, although that's not a problem, because the vector contains n+1 elements.
Due to mixing both std::cin >> and std::getline for reading user input, the first string read with std::getline is empty. You would need whether to:
use std::getline for all the user input readings (and, for n, convert the string to a number), or
flush the input buffer with cin.ignore after the std::cin >>, as explained in this answer.
The code below fixes those two issues and adds some debug output (it also follows a few best practices such as, not using namespace std;, defining variables next to their first use, value-initializing local variables, and using block braces even for one-line blocks).
[Demo]
#include <iostream> // cin, cout
#include <limits>
#include <string> // getline
#include <vector>
int main() {
int n{};
std::cout << "n: ";
std::cin >> n;
std::cout << n << "\n\n";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::vector<std::string> vec{};
for (int i = 0; i < n; i++) {
std::cout << "Enter a string: ";
std::string item{};
std::getline(std::cin, item);
std::cout << "item: " << i << ": '" << item << "'\n";
vec.push_back(item);
}
std::cout << "\n";
for (auto& of : vec) {
std::cout << "'" << of << "': ";
if (of.find("ba") != std::string::npos) {
std::cout << "false\n";
} else {
std::cout << "true\n";
}
}
}
// Outputs:
//
// n: 5
//
// Enter a string: item: 0: 'aabbb'
// Enter a string: item: 1: 'ba'
// Enter a string: item: 2: 'aaa'
// Enter a string: item: 3: 'b'
// Enter a string: item: 4: 'abba'
//
// 'aabbb': true
// 'ba': false
// 'aaa': true
// 'b': true
// 'abba': false
For this particular case, you could also use std::is_partitioned. This algorithm tells you if all the elements of a range that satisfy a given predicate appear before all the elements that don't (see here). The predicate would check if a character is equal to 'a'.
[Demo]
#include <algorithm> // is_partitioned
#include <cstring> // strlen
#include <fmt/core.h>
int main() {
for (auto&& s : { "aabbb", "ba", "aaa", "b", "abba" }) {
fmt::print("'{}': {}\n", s, std::is_partitioned(s, s + strlen(s),
[](unsigned char c) { return c == 'a'; }));
}
}
After fixing the loop logic, here is another simple solution you could use, with the is_sorted algorithm:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
int main() {
// ...
for (auto of : vec)
std::cout << std::boolalpha << std::ranges::is_sorted(of);
}
This compiles with C++20 support, and it works because strings are ranges of characters, for which an operator< is defined. It happens to be the case that 'a' < 'b', so this simple expression is all you need.
You just need to find "ba" occurrences.
C++ string type already provides such function. Complexity is linear on string length O(n)
#include <iostream>
#include <string>
void checker(const std::string S)
{
if (S.find("ba") != std::string::npos) {
std::cout << "false" << '\n';
} else {
std::cout << "true" << '\n';
}
}

How would I search an element in a vector string?

I'm trying to search a vector string for certain words.
For example,
vector<string> sentences = ["This is a test string","Welcome to C++!"];
string searchString = "This";
I tried
if (std::find(sentences.begin(), sentences.end(), searchString) != sentences.end()) {
cout << "Found!";
}
else {
cout << "Not Found!";
}
Now this does work but only if the searchString matches the element word for word.
For example if we set
string searchString = "This is a test string";
This will return found.
How do I search the elements individually?
Thanks!
for(std::string& s : sentences)
{
if(s.find(searchString) != std::string::npos)
{
//substring found
}
else
{
//substring not found
}
}
this should work for looking for a word in each string in the vector
There is std::find_if that lets you pass a predicate to be used instead of directly comparing elements for equality with a searchString:
auto matcher = [searchString](const std::string& element) {
return element.find(searchString) != std::string::npos;
};
if (std::find_if(sentences.begin(), sentences.end(), matcher) != sentences.end()){
cout << "Found!";
} else {
cout<< "Not Found!";
}
You can iterate over all the strings in your vector and check each string one by one if it contains the string you want to find. If the string contains the search term, you can return the whole element:
#include <iostream>
#include <vector>
#include <string>
std::string findSubstr(const std::vector<std::string>& list, const std::string& search) {
for (const std::string& str : list) {
if (str.find(search) != std::string::npos) {
return str;
}
}
return "Not found";
}
int main(int argc, const char** argv) {
if (argc < 2) {
std::clog << "Usage: " << argv[0] << " <search term>\n";
return 1;
}
std::vector<std::string> test{"This is a test string", "Welcome to C++!"};
std::cout << findSubstr(test, argv[1]) << std::endl;
}

What am I doing wrong here with find and string?

I am asking user to enter date in format with slashes. Then I try to find the slashes in the string using find. I get error saying I cannot compare pointer with integer on my if statement. Here is code.
// test inputing string date formats
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string dateString;
int month,day,year;
std::cout << "Enter a date in format of 5/14/1999: ";
std::getline(std::cin,dateString);
std::cout << "You entered " << dateString << std::endl;
if (std::find(dateString.begin(),dateString.end(),"/") != dateString.end()) {
std::cout << "Found slash in date.\n";
}
else {
std::cout << "screwed it up.\n";
}
}
Any help is appreciated.
if (std::find(dateString.begin(),dateString.end(),"/") != dateString.end()) {
"/" is a literal string, or a const char * (actually a const char[2] in this case, to be pedantic, but this is not germane) . The third parameter to std::find, in this case, should be a char, a single character.
You probably meant
if (std::find(dateString.begin(),dateString.end(),'/') != dateString.end()) {
I think you can use
if (dateString.find("/") != std::string::npos) {
std::cout << "Found slash in date.\n";
} else {
std::cout << "screwed it up.\n";
}
to find substring/char in a string. Note that std::string::find() works for char, const char * and std::string.

Program To Identify Lower Case Strings

Beginner C++ student here, first ever programming class. I am trying to put together a program that will identify if a string is all lower case or not. I got as far as the code below. However, I need to account for spaces " ". If there is a space in the string that is input by the user, the program is suppose to return that it is not all lower case. Example:
input: abc def
return: The string is not lower case.
Would any of you ever so kindly advise what would be the best way to account for this in the code below?
NOTE: I know I have 'included' some extra header files, but that is because this is going to be part of another program and this is just an excerpt to get things running.
Thank you so very much all!!
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cctype>
#include <iomanip>
using namespace std;
bool die(const string & msg);
bool allLower(const string & l);
int main() {
string l;
cout << "\nEnter a string (all lower case?): ";
cin >> l;
if (allLower(l) == true)
{
cout << "The string is lower case." << endl;
}
else
{
cout << "The string is not lower case." << endl;
}
}
bool allLower(const string & l) {
struct IsUpper {
bool operator()(int value) {
return ::isupper((unsigned char)value);
}
};
return std::find_if(l.begin(), l.end(), IsUpper()) == l.end();
}
bool die(const string & msg){
cout << "Fatal error: " << msg << endl;
exit(EXIT_FAILURE);
}
You could use a good old fashion for-loop.
bool allLower(const std::string & l)
{
for(unsigned int i = 0; i < l.size(); i++)
{
if(l[i] == ' ')
{
return false;
}
else if(isalpha(l[i]))
{
if(isupper(l[i]))
return false;
}
}
return true;
}
Note that if you feed it in something like "2" it will return true. You could add a final else statement that returns false if you so desire.
You can check to see if a character is alphabetic using the function std::isalpha() prior to using std::isupper() or std::islower() to checking whether all letters within your string are uppercase/lowercase, etc
A range-based for loop would be clearer than indices IMO
bool allLower(const std::string &l)
{
for (auto c : l)
{
if ((c == ' ') ||
(std::isalpha(c) && std::isupper(c)))
{
return false;
}
}
return true;
}