What am I doing wrong here with find and string? - c++

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.

Related

How would I make an underline exactly the length of any text inputted as well as capitalizing every letter

Sorry I'm really new to programming and need some assistance. How would I make this happen. This is the function I currently have.
void DisplayTitle(string aTitle) {
cout << "\t" << aTitle << endl;
cout << "\t--------------\n\n";
}
How would I go about making sure that no matter which title is inputted, every character will be capitalized and the underscores will be the same amount of characters as the displayed title above.
You can use std::setfill combined with std::setw from <iomanip> as follows:
std::cout << std::setfill('-') << std::setw(title.size()) << "";
Here, you're telling the stream to use a padding character of '-', then a padded output size that's the length of your title, and then output an empty string. Because the string is empty, it will pad that entire area.
#include <iostream>
#include <iomanip>
#include <string>
void DisplayTitle(const std::string& title, const char* prefix = "\t")
{
std::cout << prefix << title << "\n";
std::cout << prefix << std::setfill('-') << std::setw(title.size()) << "" << "\n\n";
}
int main()
{
for (std::string title; std::getline(std::cin, title); )
{
DisplayTitle(title);
}
}
Example input:
One flew over the cuckoo's nest
The birds and the bees
Example output:
One flew over the cuckoo's nest
-------------------------------
The birds and the bees
----------------------
Here is a live demo of the above.
Oh, it seems I missed the fact your question was asking two things. You also want to capitalize the title. You can do that with std::transform, and in fact it can even be done without modifying the string:
void DisplayTitle(const std::string& title, const char* prefix = "\t")
{
// Write title in all-caps
std::cout << prefix;
std::transform(title.begin(), title.end(),
std::ostream_iterator<char>(std::cout),
[](char c) { return std::toupper(c); });
std::cout << "\n";
// Underline title
std::cout << prefix << std::setfill('-') << std::setw(title.size()) << "" << "\n\n";
}
Here is the updated live demo with the above change.
You can use std::transform and to_upper to capitalize the string.
You can use std::string's two-parameter constructor which takes a length and a character to generate a sequence of - of the same length as the title
Together we get:
#include <iostream>
#include <string>
#include <algorithm>
void DisplayTitle(std::string aTitle) {
std::transform(aTitle.begin(), aTitle.end(), aTitle.begin(), toupper);
std::cout << "\t" << aTitle << "\n";
std::cout << "\t" << std::string(aTitle.length(), '-') << "\n\n";
}
int main()
{
for (std::string title; std::getline(std::cin, title); )
{
DisplayTitle(title);
}
}
demo on godbolt

Find an exact substr in a string

I have a text file which contains the following text
License = "123456"
GeneralLicense = "56475655"
I want to search for License as well as for GeneralLicense.
while (getline(FileStream, CurrentReadLine))
{
if (CurrentReadLine.find("License") != std::string::npos)
{
std::cout << "License Line: " << CurrentReadLine;
}
if (CurrentReadLine.find("GeneralLicense") != std::string::npos)
{
std::cout << "General License Line: " << CurrentReadLine;
}
}
Since the word License also present in the word GeneralLicense so if-statement in the line if (CurrentReadLine.find("License") != std::string::npos) becomes true two times.
How can I specify that I want to search for the exact sub-string?
UPDATE: I can reverse the order as mentioned by some Answers OR check if the License is at Index zero. But isn't there anything ROBOUST (flag or something) which we can speficy to look for the exact match (Something like we have in most of the editors e.g. MS Word etc.).
while (getline(FileStream, CurrentReadLine))
{
if (CurrentReadLine.find("GeneralLicense") != std::string::npos)
{
std::cout << "General License Line: " << CurrentReadLine;
}
else if (CurrentReadLine.find("License") != std::string::npos)
{
std::cout << "License Line: " << CurrentReadLine;
}
}
The more ROBUST search is called a regex:
#include <regex>
while (getline(FileStream, CurrentReadLine))
{
if(std::regex_match(CurrentReadLine,
std::regex(".*\\bLicense\\b.*=.*")))
{
std::cout << "License Line: " << CurrentReadLine << std::endl;
}
if(std::regex_match(CurrentReadLine,
std::regex(".*\\bGeneralLicense\\b.*=.*")))
{
std::cout << "General License Line: " << CurrentReadLine << std::endl;
}
}
The \b escape sequences denote word boundaries.
.* means "any sequence of characters, including zero characters"
EDIT: You could also use regex_search instead of regex_match to search for substrings that match instead of using .* to cover the parts that don't match:
#include <regex>
while (getline(FileStream, CurrentReadLine))
{
if(std::regex_search(CurrentReadLine, std::regex("\\bLicense\\b")))
{
std::cout << "License Line: " << CurrentReadLine << std::endl;
}
if(std::regex_search(CurrentReadLine, std::regex("\\bGeneralLicense\\b")))
{
std::cout << "General License Line: " << CurrentReadLine << std::endl;
}
}
This more closely matches your code, but note that it will get tripped up if the keywords are also found after the equals sign. If you want maximum robustness, use regex_match and specify exactly what the whole line should match.
You can check if the position at which the substring appears is at index zero, or that the character preceding the initial position is a space:
bool findAtWordBoundary(const std::string& line, const std::string& search) {
size_t pos = line.find(search);
return (pos != std::string::npos) && (pos== 0 || isspace(line[pos-1]));
}
Isn't there anything ROBUST (flag or something) which we can specify to look for the exact match?
In a way, find already looks for exact match. However, it treats a string as a sequence of meaningless numbers that represent individual characters. That is why std::string class lacks the concept of "full word", which is present in other parts of the library, such as regular expressions.
You could write a function that tests for the largest match first and then returns what ever information you want about the match.
Something a bit like:
// find the largest matching element from the set and return it
std::string find_one_of(std::set<std::string, std::greater<std::string>> const& tests, std::string const& s)
{
for(auto const& test: tests)
if(s.find(test) != std::string::npos)
return test;
return {};
}
int main()
{
std::string text = "abcdef";
auto found = find_one_of({"a", "abc", "ab"}, text);
std::cout << "found: " << found << '\n'; // prints "abc"
}
If all matches start on pos 0 and none is prefix of an other, then the following might work
if (CurrentReadLine.substr( 0, 7 ) == "License")
You can tokenize your string and do a full comparison with your search key and the tokens
Example:
#include <string>
#include <sstream>
#include <vector>
#include <iostream>
auto tokenizer(const std::string& line)
{
std::vector<std::string> results;
std::istringstream ss(line);
std::string s;
while(std::getline(ss, s, ' '))
results.push_back(s);
return results;
}
auto compare(const std::vector<std::string>& tokens, const std::string& key)
{
for (auto&& i : tokens)
if ( i == key )
return true;
return false;
}
int main()
{
std::string x = "License = \"12345\"";
auto token = tokenizer(x);
std::cout << compare(token, "License") << std::endl;
std::cout << compare(token, "GeneralLicense") << std::endl;
}

C++ error: no matching function for call to 'regex_match()'

I'm struggling with this C++ compiler error to get my regex_match() function to work. The code:
#include <iostream>
#include <string>
#include <regex>
using namespace std;
struct Person {
Person(string name, int age)
: n{name}, a{age}
{
regex r("^([!:*&%##^\\[\\]\"\'])+"); // :*[]"'&^%##!
for(char test : n) {
cout << "Character: " << test;
if(regex_match(test, r)) {
cout << endl << "Error: wrong character!" << endl;
}
}
}
string n;
int a;
};
int main() {
Person Goofy("Goofy",11);
return 0;
}
I want to check if n contains at least one of the characters I wrote in the regex r().
Btw, for people learning regex I've found the great website: https://regex101.com.
Any sugestions? Thx!!
test is a character. There's no overload of std::regex_match for a character.
I'm not sure if you want to check every character against the list of characters or just the first one. If it's them all, you can use std::any_of:
char const constexpr m[] = R"(:*[]"'&^%##!)";
for(char test : n) {
if(any_of(begin(m), end(m), [test](char c){ return c == test; })) {
cout << endl << "Error: wrong character!" << endl;
}
}
Based on the additional comments I think I understand what you wanted: check if the string n contained any of the "illegal" characters. For this task std::regex_search is better suited:
regex r{R"([:*\[\]"'&^%##!])"};
if(regex_search(n, r)){
cout << endl << "Error: wrong character!" << endl;
}

C++: converting wstring to double

Before converting wstring to double - how to validate it with regex? Java no problem, but C++ raising questions.. :)
I suppose you have a string and you want to know if it is a double or not. The following code does not use regular expressions. Instead it initializes a stringstream and reads a double from it. If the string starts with something non-numeric, then ss.fail() will be set. If it starts with a number, but does not read the whole string, then there's something non-numeric at the end of the string. So if everything went well and the string is really only a number, then ss.eof() && !ss.fail() will be true.
#include <iostream>
#include <sstream>
int main()
{
std::stringstream ss("123.456");
double mydouble;
ss >> mydouble;
if (ss.eof() && !ss.fail())
std::cout << "yay, success: " << mydouble << std::endl;
else
std::cout << "that was not a double." << std::endl;
return 0;
}
There's also std::wstringstream if you need to convert wide character strings.
You might also want to have a look at the boost libraries, especially at Boost.Lexical_Cast.
With this library you could do the following:
#include <boost/lexical_cast.hpp>
#include <iostream>
int main()
{
try
{
double mydouble = boost::lexical_cast<double>("123.456");
std::cout << "yay, success: " << mydouble << std::endl;
}
catch(const boost::bad_lexical_cast &)
{
std::cout << "that was not a double." << std::endl;
}
return 0;
}
Or maybe it is simpler to do that this way:
std::wstring strKeyValue = "147.sd44";
double value = (double) _wtof(strKeyValue.c_str());
And if strKeyValue==0 then it means it's not double.

Find substring in string using locale

I need to find if a string contains a substring, but according to the current locale's rules.
So, if I'm searching for the string "aba", with the Spanish locale, "cabalgar", "rábano" and "gabán" would all three contain it.
I know I can compare strings with locale information (collate), but is there any built-in or starightforward way to do the same with find, or do I have to write my own?
I'm fine using std::string (up to TR1) or MFC's CString
For reference, here is an implementation using boost locale compiled with ICU backend:
#include <iostream>
#include <boost/locale.hpp>
namespace bl = boost::locale;
std::locale usedLocale;
std::string normalize(const std::string& input)
{
const bl::collator<char>& collator = std::use_facet<bl::collator<char> >(usedLocale);
return collator.transform(bl::collator_base::primary, input);
}
bool contain(const std::string& op1, const std::string& op2){
std::string normOp2 = normalize(op2);
//Gotcha!! collator.transform() is returning an accessible null byte (\0) at
//the end of the string. Thats why we search till 'normOp2.length()-1'
return normalize(op1).find( normOp2.c_str(), 0, normOp2.length()-1 ) != std::string::npos;
}
int main()
{
bl::generator generator;
usedLocale = generator(""); //use default system locale
std::cout << std::boolalpha
<< contain("cabalgar", "aba") << "\n"
<< contain("rábano", "aba") << "\n"
<< contain("gabán", "aba") << "\n"
<< contain("gabán", "Âbã") << "\n"
<< contain("gabán", "aba.") << "\n"
}
Output:
true
true
true
true
false
You could loop over the string indices, and compare a substring with the string you want to find with std::strcoll.
I haven't used this before, but std::strxfrm looks to be what you could use:
http://en.cppreference.com/w/cpp/locale/collate/transform
#include <iostream>
#include <iomanip>
#include <cstring>
std::string xfrm(std::string const& input)
{
std::string result(1+std::strxfrm(nullptr, input.c_str(), 0), '\0');
std::strxfrm(&result[0], input.c_str(), result.size());
return result;
}
int main()
{
using namespace std;
setlocale(LC_ALL, "es_ES.UTF-8");
const string aba = "aba";
const string rabano = "rábano";
cout << "Without xfrm: " << aba << " in " << rabano << " == " <<
boolalpha << (string::npos != rabano.find(aba)) << "\n";
cout << "Using xfrm: " << aba << " in " << rabano << " == " <<
boolalpha << (string::npos != xfrm(rabano).find(xfrm(aba))) << "\n";
}
However, as you can see... This doesn't do what you want. See the comment at your question.