Reputation: 49882
I am doing a series of searches in a string, and somewhere along the line one of the strings will be missed, and my set of searches should fail.
I had expected that once the position reached std::string::npos it would stay there, but it does not. Passing std::string::npos to std::string.find seems to start the search at the beginning again
std::string str("frederick");
std::string::size_type pos = str.find("der",std::string::npos);
TS_ASSERT_EQUALS(pos, std::string::npos); // FAIL, 3 is returned
Why is it not being taken to indicate the end of the string?
Update: The intention is search for a series of strings in order, and check the result at the end
pos = str.find(string1, pos)
pos = str.find(string2, pos)
pos = str.find(string3, pos)
if (pos != std:string::npos)
{ // All strings found
Upvotes: 3
Views: 11937
Reputation: 41116
Behavior is undefined if you pass npos
:
[update]
STL documentation (the two reproductions I can find, anyway) mention string::npos
only as possible return value, not as a valid value for pos
. The latter is the index where search starts.
But see also comments below (I'm not an expert on the ISO standard, I am limiting my expectations based on the docs I have).
The STL implementation would typically use an clearly-out-of-range value (such as ((size_type)-1)
. How this is handled as parameter is not clearly stated, so I wouldn't rely on that behavior.
[/update]
So you need to start at 0, and check for pos != npos
after every call to find:
pos = str.find(string1, 0)
if (pos != std:string::npos)
pos = str.find(string2, pos)
if (pos != std:string::npos)
pos = str.find(string3, pos)
if (pos != std:string::npos)
{
// All strings found
}
Upvotes: 1
Reputation: 180135
Compare string::find() and string::copy(). (In N2798, that's 21.3.7.2 and 21.3.6.7, pages 686/687) Both take a position argument. Yet only string::copy has a "Requires: pos <= size()" clause. Hence, string::find does not require pos <= size().
From that point on, Charles Bailey has the correct logic. Look at the range of valid return values, and it becomes clear that only the only return value which matches the rqeuirements is string::npos. Any other value returned is smaller than string::npos, failing 21.3.7.2/1.
From N2798=08-0308, copyright ISO/IEC:
21.3.7.2 basic_string::find [string::find]
size_type find(const basic_string<charT,traits,Allocator>& str,
size_type pos = 0) const;
1 Effects: Determines the lowest position xpos
, if possible, such that both of the following conditions obtain:
— pos <= xpos
and xpos + str.size() <= size();
— traits::eq(at(xpos+I), str.at(I))
for all elements I
of the string controlled by str
.
2 Returns: xpos
if the function can determine such a value for xpos
. Otherwise, returns npos
.
3 Remarks: Uses traits::eq()
.
Upvotes: 4
Reputation: 792837
You may find that the free function std::search is easier to use in this situation. E.g.
std::string::const_iterator iter = str.begin();
iter = std::search( iter, str.end(), string1.begin(), string1.end() );
iter = std::search( iter, str.end(), string2.begin(), string2.end() );
iter = std::search( iter, str.end(), string3.begin(), string3.end() );
Upvotes: 3
Reputation: 20881
Passing std::string::npos as the second argument to find means "start finding on or after std::string::npos position in the string".
Clearly this is not what you intended.
EDIT:
This might do what you originally intended:
string s;
string::size_type pos;
if ((pos = s.find(s1)) != string::npos && (pos = s.find(s2, pos)) != npos &&
(pos = s.find(s3,pos)) != string::npos)
{
// okay
}
I haven't tested it but it should work, you might prefer peterchen style as it's more readable.
Upvotes: 0
Reputation: 792837
Looking at the spec, I think that there may be a bug in your implementation.
basic_string::find
should return the lowest position xpos
such that pos <= xpos
and xpos + str.size() <= size()
and at(xpos + I) == str.at(I)
for all elements I
controlled by str
.
basic_string::npos
is -1 converted to an unsigned type so must be the largest number representable by that unsigned type. Given that no other position xpos
can satisfy even the first part of npos
<= xpos
and find
must return npos
on failure, as far as I can see npos
is the only valid return value for basic_string::find
when passed npos
as the second parameter.
Upvotes: 10
Reputation: 13973
std::string::npos
is not a valid argument for std::string::find
.
The definition of find
in the Standard only mentions npos
as a possible return value, not a start position.
Upvotes: 3
Reputation: 57242
You should rather use as starting position the length of the string.
Upvotes: 0