How to check if a string contains punctuation c++ - c++

I am attempting to iterate over a string to check for punctuation. I've tried to use ispunct() but am receiving an error that there is no matching fucntion for call to ispunct. Is there a better way to implement this?
for(std::string::iterator it = oneWord.begin(); it != oneWord.end(); it++)
{
if(ispunct(it))
{
}
}

Is there a better way to implement this?
Use std::any_of:
#include <algorithm>
#include <cctype>
#include <iostream>
int main()
{
std::string s = "Contains punctuation!!";
std::string s2 = "No puncuation";
std::cout << std::any_of(s.begin(), s.end(), ::ispunct) << '\n';
std::cout << std::any_of(s2.begin(), s2.end(), ::ispunct) << '\n';
}
Live Example

it is an iterator; it points to a character in a string. You have to dereference it to get the thing it points to.
if(ispunct(static_cast<unsigned char>(*it)))

Related

The erase function of strings in c++

well I was doing this problem from leetcode " https://leetcode.com/problems/valid-palindrome/ " and to remove the punctuations I used this
for (auto i:s)
{
if (ispunct(i))
{
s.erase(remove(s.begin(), s.end(), i), s.end());
continue;
}
}
but when it runs it leaves some punctuation characters in the string like this:
ip-> "Marge, let's "[went]." I await {news} telegram."
op-> "margelets[wentiawaitnewstelegram"
Modifying a string (or any other collection) while looping over it is a poor idea. Your iterator into the string is based on the state of the string at the beginning of your loop. Changing the state of the string inside the loop may lead to unexpected behavior of your iterator.
Rather you may want to create a new string without the offending characters.
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
int main() {
std::string s1 = "Hello world!";
std::string s2;
std::copy_if(s1.begin(), s1.end(),
std::back_inserter(s2),
[](auto ch) { return !std::ispunct(ch); });
std::cout << s2 << std::endl;
return 0;
}

how connect regex replace to function in c++

#include <iostream>
#include <iterator>
#include <regex>
#include <string>
std::string ty(std::string text){
if(text == "brown")
return "true";
else
return "qw";
}
int main()
{
std::string text = "Quick $brown fox";
std::cout << '\n' << std::regex_replace(text, std::regex(R"(\\$(.*))"), ty("$&")) << '\n';
}
i use c++11 . I try without if worked but with if don't work ? i don't know what to do
There's a lot of different things wrong with the original code.
Firstly here's some working code
#include <iostream>
#include <iterator>
#include <regex>
#include <string>
std::string ty(std::string text){
if(text == "brown")
return "true";
else
return "qw";
}
int main()
{
std::string text = "Quick $brown fox";
std::smatch m;
if (std::regex_search(text, m, std::regex(R"(\$([[:alpha:]][[:alnum:]]*))")))
{
std::cout << '\n' << ty(std::string(m[1].first, m[1].second)) << '\n';
}
else
{
std::cout << "\nno match\n";
}
}
Some things that were wrong with the original code
Firstly the function being called was wrong. Use std::regex_search to search for matches in a string. Capture the results in an std::smatch object and then use those results to call the ty function.
The regex was wrong in two different ways. Firstly \\ is wrong because you are using a raw string literal, so only a single backslash is required. Secondly (.*) is wrong because that will match the entire rest of the string. You only want to match the word following the dollar. I've used ([[:alpha:]][[:alnum:]]*) instead. That might not be exactly what you want but it works for this example. You can modify it if you want.

How to use a vector to pass multiple strings into a function

I have a function that reads a file to find a certain word. The system I currently have however searched for a specific word and isn't case sensitive. I can't simply use .find("word" && "Word")
As far as I can tell, the easiest way to do this would be with a vector with both versions of the word inside for the function to look for both however I can't figure out how to pass the vector into the function.
Any help would be appreciated. Thanks
You may just call find for every possible word in your vector. But i would suggest to use only lowercase if possible
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
std::string str = "HeLlo WorLd";
std::vector<std::string> vec{ "HELLO","HeLlo","hEllO","WORLD","WorLd" };
std::for_each(vec.begin(), vec.end(), [&](const std::string& comp)
{
auto found = str.find(comp);
if (found != std::string::npos)
std::cout << "Found World " << comp << " in str at " << std::distance(str.begin(), str.begin() + found) << std::endl;
});
return 0;
}
In c++ you can pass the vector to a function as a reference or absolute value. To pass as the reference, You can follow this approach.
int fun(std::vector<std::string>& arr) {
int value = 0;
// your operation
return value;
}
int main() {
std::vector<std::string> arr;
// your logic
int value = fun(arr);
return 0;
}

Reverse For loop Crashes

So I have this code and it crashes xcode
void strrev(const std::string& str)
{
for(size_t i=str.length();i>=0;i--)
{
std::cout << str[i];
}
}
It works fine if I do i>0 but then the first character does not get printed
Any suggestions on what is wrong with i>=0 ?
Problem
i is of type size_t (it is an unsigned integral), so when i is zero and i-- is performed, its value wraps around, getting i the highest possible value it can store. This i is then used in the expression str[i] causing a crash.
Solution
You can separately handle the case for i equal to zero. Also, since indices start at zero, the highest possible index is str.length()-1.
It should be then:
for(size_t i=str.length()-1; i > 0; i--)
std::cout << str[i];
std::cout << str[0];
Recommended alternatives
Consider using reverse iterators instead to avoid having to deal with indices:
void strrev(const std::string& str)
{
for (auto rit = str.rbegin(); rit != str.rend(); ++rit)
std::cout << *rit;
}
Note that you can also use std::copy in combination with reverse iterators and a std::ostream_iterator object for std::cout:
#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
void strrev(const std::string& str)
{
std::copy(str.rbegin(), str.rend(),
std::ostream_iterator<std::string::value_type>{std::cout});
}
or directly use std::reverse_copy instead of std::copy and therefore no need for reverse iterators:
std::reverse_copy(str.begin(), str.end(),
std::ostream_iterator<std::string::value_type>{std::cout});
It's better to do this in an idiomatic, index-free way using std::reverse.
#include <algorithm>
#include <iostream>
#include <string>
int main() {
std::string str = "Hello World!";
std::reverse(str.begin(), str.end());
std::cout << str << "\n"; // !dlroW olleH
}
Since the strings in c++ are base zero -the first character in a string is str[0]- therefor the index of the last character in a c++ string is always str.length()-1 or str.size()-1
So it should be
void strrev(const std::string& str)
{
for(size_t i=str.length()-1;i>=0;i--)
{
std::cout << str[i];
}
}

How to deal with last comma, when making comma separated string? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Don't print space after last number
Printing lists with commas C++
#include <vector>
#include <iostream>
#include <sstream>
#include <boost/foreach.hpp>
using namespace std;
int main()
{
vector<int> VecInts;
VecInts.push_back(1);
VecInts.push_back(2);
VecInts.push_back(3);
VecInts.push_back(4);
VecInts.push_back(5);
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
ss << i << ",";
}
cout << ss.str();
return 0;
}
This prints out: 1,2,3,4,5,
However I want: 1,2,3,4,5
How can I achieve that in an elegant way?
I see there is some confusion about what I mean with "elegant": E.g. no slowing down "if-clause" in my loop. Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone through the loop.
How about this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
std::ostringstream ss;
if(!v.empty()) {
std::copy(v.begin(), std::prev(v.end()), std::ostream_iterator<int>(ss, ", "));
ss << v.back();
}
std::cout << ss.str() << "\n";
}
No need to add extra variables and doesn't even depend on boost! Actually, in addition to the "no additional variable in the loop" requirement, one could say that there is not even a loop :)
Detecting the one before last is always tricky, detecting the first is very easy.
bool first = true;
stringstream ss;
BOOST_FOREACH(int i, VecInts)
{
if (!first) { ss << ","; }
first = false;
ss << i;
}
Using Karma from Boost Spirit - has a reputation for being fast.
#include <iostream>
#include <vector>
#include <boost/spirit/include/karma.hpp>
int main()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
using namespace boost::spirit::karma;
std::cout << format(int_ % ',', v) << std::endl;
}
Try:
if (ss.tellp ())
{
ss << ",";
}
ss << i;
Alternatively, if the "if" is making you worried:
char *comma = "";
BOOST_FOREACH(int i, VecInts)
{
ss << comma << i;
comma = ",";
}
Personally, I like a solution that does not cause potential memory allocations (because the string grows larger than needed). An extra-if within the loop body should be tractable thanks to branch target buffering, but I would do so:
#include <vector>
#include <iostream>
int main () {
using std::cout;
typedef std::vector<int>::iterator iterator;
std::vector<int> ints;
ints.push_back(5);
ints.push_back(1);
ints.push_back(4);
ints.push_back(2);
ints.push_back(3);
if (!ints.empty()) {
iterator it = ints.begin();
const iterator end = ints.end();
cout << *it;
for (++it; it!=end; ++it) {
cout << ", " << *it;
}
cout << std::endl;
}
}
Alternatively, BYORA (bring your own re-usable algorithm):
// Follow the signature of std::getline. Allows us to stay completely
// type agnostic.
template <typename Stream, typename Iter, typename Infix>
inline Stream& infix (Stream &os, Iter from, Iter to, Infix infix_) {
if (from == to) return os;
os << *from;
for (++from; from!=to; ++from) {
os << infix_ << *from;
}
return os;
}
template <typename Stream, typename Iter>
inline Stream& comma_seperated (Stream &os, Iter from, Iter to) {
return infix (os, from, to, ", ");
}
so that
...
comma_seperated(cout, ints.begin(), ints.end()) << std::endl;
infix(cout, ints.begin(), ints.end(), "-") << std::endl;
infix(cout, ints.begin(), ints.end(), "> <") << std::endl;
...
output:
5, 1, 4, 2, 3
5-1-4-2-3
5> <1> <4> <2> <3
The neat thing is it works for every output stream, any container that has forward iterators, with any infix, and with any infix type (interesting e.g. when you use wide strings).
I like moving the test outside the loop.
It only needs to be done once. So do it first.
Like this:
if (!VecInts.empty())
{
ss << VecInts[0]
for(any loop = ++(VecInts.begin()); loop != VecInts.end(); ++loop)
{
ss << "," << *loop;
}
}
You can either trim the string at the end, or using single for loop instead of foreach and dont concatenate at the last iteration
Well, if you format into a stringstream anyway, you can just trim the resulting string by one character:
cout << ss.str().substr(0, ss.str().size() - 1);
If the string is empty, than the second argument says -1, which means everything and does not crash and if the string is non-empty, it always ends with a comma.
But if you write to an output stream directly, I never found anything better than the first flag.
That is unless you want to use join from boost.string algo.
This would work
stringstream ss;
BOOST_FOREACH(int const& i, VecInts)
{
if(&i != &VecInts[0])
ss << ", ";
ss << i;
}
I suspect with "elegant" you mean "without introducing a new variable". But I think I would just do it "non-elegant" if I couldn't find anything else. It's still clear
stringstream ss;
bool comma = false;
BOOST_FOREACH(int i, VecInts)
{
if(comma)
ss << ", ";
ss << i;
comma = true;
}
Imagine 100.000 entries in the vector! If that is all you have to offer, I'd rather remove the last comma after I have gone thorough the loop.
You are saying that as if printing ss << i is one machine instruction. Come on, executing that expression will execute lots of if's and loops inside. Your if will be nothing compared to that.
cout << ss.str()<<"\b" <<" ";
You can add the "\b" backspace
This will overwrite the extra "," .
for Example :
int main()
{
cout<<"Hi";
cout<<'\b'; //Cursor moves 1 position backwards
cout<<" "; //Overwrites letter 'i' with space
}
So the output would be
H