• Advertisement
Sign in to follow this  

how do I know if std::string really empty?

This topic is 3003 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi I want to know how can i get an empty srting when there are no digits or alpha characters. Can't use str.empty() if spaces or tabs are part of the string?

Share this post


Link to post
Share on other sites
Advertisement
You can do something like:

bool isEmpty(const std::string &str)
{
for (int i = 0; i < str.size(); ++i)
// check if the character is inside the a-z or A-Z or 0-9
if ((str >= 'a' && str <= 'z') || (str >= 'A' && str <= 'Z') || (str >= '0' && str <= '9'))
return false; // we found an alphanumeric character

return true;
}


Edit: Made several edits to fix the logic a bit.

Share this post


Link to post
Share on other sites
Quote:
Original post by nullsquared
You can do something like:

bool isEmpty(const std::string &str)
{
for (int i = 0; i < str.size(); ++i)
// check if the character is inside the a-z or A-Z or 0-9
if ((str >= 'a' && str <= 'z') || (str >= 'A' && str <= 'Z') || (str >= '0' && str <= '9'))
return false; // we found an alphanumeric character

return true;
}


Edit: Made several edits to fix the logic a bit.


Your code is buggy, at least you should have used the functions from cctype.

Further, I guess monchito is looking for a function that checks whether a string is made of zero or more whitespace, and not for a string that does not include any of [a-zA-Z0-9], so your code is wrong by principle. E.g. it fails for "!", for which you return true, but where the OP wants false.


#include <string>
bool is_whitespace_or_empty (std::string const &str) {
if (str.empty()) return true;
for (std::string::iterator it=str.begin();
it != str.end();
++it
) {
switch (*it) {
case ' ':
case '\n':
case '\t': break;
default: return false;
};
}
return true;
}


Let only pass what you want, and don't even try to block what is not wanted (think of unicode!). See also "Pretty Basic Validation", which is similar to your post.

Fix in spirit of my above statement:

#include <cctype>
#include <string>
bool is_whitespace_or_empty (std::string const &str) {
if (str.empty()) return true;
for (std::string::iterator it=str.begin();
it != str.end();
++it
) {
if (!std::isspace (*it)) return false;
}
return true;
}



(disclaimer: functions not tested)

Share this post


Link to post
Share on other sites

bool is_empty(const std::string &value)
{
return value.find_first_not_of(" \t\n\r") == std::string::npos;
}




Does this work? I can't test it at the moment...

Share this post


Link to post
Share on other sites
Should work.

I was going to suggest something that takes advantage of isspace, but it didn't turn out particularly elegant.


bool is_empty_or_ws(const std::string& s)
{
int (*spaces)(int) = &std::isspace; //this sucker is overloaded
return s.empty() || std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(spaces))) == s.end();
}

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
Should work.

I was going to suggest something that takes advantage of isspace, but it didn't turn out particularly elegant.


bool is_empty_or_ws(const std::string& s)
{
int (*spaces)(int) = &std::isspace; //this sucker is overloaded
return s.empty() || std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(spaces))) == s.end();
}


IMHO, using trivial algorithms like std::find_if often makes things more obscure than the loops they replace:

bool is_empty_or_ws(const std::string &s) {
for (std::string::const_iterator it=s.begin(), end=s.end(); it!=end; ++it) {
if (!std::isspace(*it))
return false;
}
return true;
}



Share this post


Link to post
Share on other sites
IMO you should write the following functions, as they are extremely useful:


template<class InIter, class Pred>
bool exists(InIter first, InIter second, Pred p)
{
while (first != second)
{
if (p(*first)) return true;
++first;
}
return false;
}

template<class InIter, class Pred>
bool every(InIter first, InIter second, Pred p)
{
while (first != second)
{
if (!p(*first)) return false;
++first;
}
return true;
}




Then you can write your function like this:


if (!every(str.begin(), str.end(), std::isspace))
{
//There's a non whitespace character
}





Plus, you can use these two generic template functions for just about anything.

Share this post


Link to post
Share on other sites
Quote:
Original post by monchito
Hi
I want to know how can i get an empty srting when there are no
digits or alpha characters. Can't use str.empty() if spaces or tabs
are part of the string?


0) which language? The rest assumes C++.

1) Are you checking for string having length of 0, or whether string contains only alphanumeric symbols
2) Do you use US ASCII set, specific codepage, or unicode?
3) Which characters do you wish to ignore? Aside from space and tab, there are other invisible characters which may appear, including \n and \0
4) How is string represented? Using std::basic_string variants? C-style string?

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
IMO you should write the following functions, as they are extremely useful:

*** Source Snippet Removed ***

Then you can write your function like this:

*** Source Snippet Removed ***


Plus, you can use these two generic template functions for just about anything.


Oh, that is pretty neat. However, it's still a lot less flexible than writing a loop.

For instance (real-world example), I may want to consider a line to be blank if the first non-space character is a '#', because we'll accept Perl-style comments.

bool is_blank_or_comment(const std::string &s) {
for (std::string::const_iterator it=s.begin(), end=s.end(); it!=end; ++it) {
if (*it=='#')
return true;
if (!std::isspace(*it))
return false;
}
return true;
}




Do you have a good way to write something like that?

Share this post


Link to post
Share on other sites
Quote:
Original post by alvaro
Oh, that is pretty neat. However, it's still a lot less flexible than writing a loop.

For instance (real-world example), I may want to consider a line to be blank if the first non-space character is a '#', because we'll accept Perl-style comments.

*** Source Snippet Removed ***

Do you have a good way to write something like that?


Loops are definitely more flexible. For the concrete example you mention I'd just use std::string::find_first_not_of and check whether it's equal to '#'.

But yea, in general those types of problems require that the loop maintain state, which is why they're more flexible. Sometimes you can encapsulate this state in an accumulator that is threaded through the operation (usually called a 'fold' in the context of functional programming), or a more simple accumulation like what you can get with std::accumulate.

But sometimes you need a hand-rolled loop, as you mention.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
0) which language? The rest assumes C++.

Quote:
Original post by Topic Title
how do I know if std::string really empty?



Share this post


Link to post
Share on other sites
Thanks everyone for the solutions. They tested ok with my small project.
I learn more here, asking in the forum than in countless hours searching.
The simple code is reading a text file and make sure that lines that contains
real text and no comments symbol '
(Sorry i don't know how to set code in the post, anyone please show me )

void ReadFile ( )
{
string s;
linecount = 0;
while( !inFile.eof() )
{
getline( inFile, s ); // read line from file

size_t found = s.find( '\''); // erase comment part of line
if ( found != string::npos )
s.erase ( s.begin() + int(found), s.end() );

if ( !isEmpty( s ) ) // line contains any alphanum
{
Buffer += s + '\n'; // add to the main buffer + end of line indicator
linecount++; // how many?
}
}
inFile.close();
}

Share this post


Link to post
Share on other sites
From this description it sounds like you are trying to parse Visual Basic source code.

The simplest solution would be to use boost's function.
#include <vector>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>

std::string parse(const std::string & line)
{
using namespace std;
using namespace boost::algorithm;

vector<string> result;

split(result, line, is_any_of("\'"));
trim(result.front());

return result.front();
}

void print(const std::string & s, bool test) {
std::string copy = parse(s);
std::cout << (test == copy.empty() ? "pass" : "fail") << " : ";
std::cout << (copy.empty() ? "String is empty" : copy) << "\n";
}

int main()
{
print("", true);
print("Hello World", false);
print("sub foo() \' comment", false);
print("\' full line comment", true);
print("\t\t ' \t mixed bag", true);
}


Split breaks the string at each '
We take the first string from this result
Trim this string, which removes spaces (and apparently tabs) from beginning and end of string. For empty strings, this clears the string, for others, it preserves the contents (doesn't remove spaces from middle).

If trim is performed on a copy of front(), then result can be returned verbatim, with leading spaces intact.

Sadly, robust string processing in C++ is a pain at best. Obviously, the above can be done in more than one way and without using boost.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
From this description it sounds like you are trying to parse Visual Basic source code.

The simplest solution would be to use boost's function.

Well, if he's really trying to parse Visual Basic source code, then Boost.Spirit2 would be even better as it's a complete grammar parser.

Share this post


Link to post
Share on other sites
Quote:
Original post by phresnel
Your code is buggy, at least you should have used the functions from cctype.

You're right, even though that is a pretty obscure and uncommon case.

Quote:

Further, I guess monchito is looking for a function that checks whether a string is made of zero or more whitespace, and not for a string that does not include any of [a-zA-Z0-9], so your code is wrong by principle. E.g. it fails for "!", for which you return true, but where the OP wants false.

Your statements seem to contradict themselves.

Also, according to OP:
Quote:

an empty srting when there are no
digits or alpha characters

It seems OP wants to check for alphanumeric characters (i.e. letters and numbers)

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
IMO you should write the following functions, as they are extremely useful:

*** Source Snippet Removed ***

Then you can write your function like this:

*** Source Snippet Removed ***


Plus, you can use these two generic template functions for just about anything.


Indeed a very good idea, but you fall for the same thing as I did initially: isspace is overloaded (one version taking std::locale if I'm not mistaken). So the function pointer needs to be stored in a variable, or casted.

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
Quote:
Original post by cache_hit
IMO you should write the following functions, as they are extremely useful:

*** Source Snippet Removed ***

Then you can write your function like this:

*** Source Snippet Removed ***


Plus, you can use these two generic template functions for just about anything.


Indeed a very good idea, but you fall for the same thing as I did initially: isspace is overloaded (one version taking std::locale if I'm not mistaken). So the function pointer needs to be stored in a variable, or casted.


Ahh yea, that sucks. I guess alternatively you could write a throwaway wrapper. The neat thing about this is that you can make it automatically work with wide strings this way as well


struct is_space
{
bool operator()(char c) const { return std::isspace(c); }
bool operator()(wchar_t c) const { return std::iswspace(c); }
};


std::string str;
std::wstring wstr;
if (!every(str.begin(), str.end(), is_space())
{
}

if (!every(wstr.begin(), wstr.end(), is_space())
{
}

Share this post


Link to post
Share on other sites

// Attempt to read from a stream constructed from the string into a local
// string. Since this attempts to read a "word", the string contains
// non-whitespace if and only if this is successful. We test for success using
// the implicit bool conversion of the stream.
bool contains_non_whitespace(const std::string& str) {
std::istringstream ss(str);
std::string non_whitespace;
return ss >> non_whitespace;
}
// This doesn't work with temporaries because neither the stringstream nor the
// local string are const. The resulting error messages can be quite confusing.

Share this post


Link to post
Share on other sites
Quote:
Original post by cache_hit
Quote:
Original post by Antheus
From this description it sounds like you are trying to parse Visual Basic source code.

The simplest solution would be to use boost's function.

Well, if he's really trying to parse Visual Basic source code, then Boost.Spirit2 would be even better as it's a complete grammar parser.


Yeah, but then he would have to learn how to understand that library and he would probably drive himself crazy and forget his last-name.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement