string.find() doesn't return -1 - c++

The code below is simple. As I know, if string::find() didn't find matches it returns -1. But for some reasons the code below doesn't work. Everytime I run this code I get endless loop. Thank you for help!
#include <string>
#include <iostream>
using namespace std;
int main()
{
string text;
text = "asdasd ijk asdasd";
string toReplace = "ijk";
cout<<text<<endl;
int counter = 0;
while ( text.find(toReplace) != -1)
counter++;
cout<<counter<<endl;
system("pause");
}

Aside from the other answers which are completely correct, I just wanted to add that your while loop would have produced an endless loop anyway. For example:
while(text.find(toReplace) != std::string::npos)
counter++;
will be an endless loop because it will keep trying to find the toReplace string in text and it will always find it (that's because find starts from the beginning of the string each time). This is probably not what you intended.

std::string::find returns std::string::npos if the searched substring is not found, not -1. The exact value of npos is implementation-defined, so use npos, as in
while ( text.find(toReplace) != std::string::npos)
Come to think of it, find couldn't return -1 even if it wanted to because the return type of find is specified to be std::size_t which is an unsigned type.
Additionally, find will always search for the first occurrence of the substring, no matter how many times you call it. If you want to iterate through all the occurrences you should use the overload of find which takes a second parameter - the position from which to start searching.

Whoever told you this or wherever you read it, it lied to you.
If std::string::find fails, it returns std::string::npos, which is not -1.
You should check the documentation about such things, when you're not sure.
So, your while will be something like:
while ( std::string::npos != text.find(toReplace) )
Regarding your comment:
UPDATE: I tried to use while ( text.find(toReplace) != string::npos ) but I still get endless loop :( – user2167403 10 secs ago
You should really learn to read the documentation. Use a variable to store the last result of std::string::find (different from std::string::npos) and use std::string::find's second parameter - pos ( by passing value - last_match_position + 1).
Omitting the second parameter, std::string::find always starts from the beginning of the string, which causes the endless loop.

In the code snippet you provided text variable contains substring "ijk" which is stored in the toReplace variable. As long as in while cycle neither text or toReplace variables are changed, find method will always return not a -1 value which is the condition for while cycle to continue.
As already metioned in other comments you should check not for -1 but for std::string::npos.

It does help to read the manual page (string::npos is the answer).
See http://www.cplusplus.com/reference/string/string/find/

Related

Check string for recurrence of specific character

How can I search inside of a string for more than one occurrence of a specific character (in this case a period .)?
I have already tried adapting the answer from this question, but I think I am doing it wrong.
std::string periodCheck = i.convert_to<std::string>();
char subString = '.';
std::size_t pos = periodCheck.find(subString, 0);
int counter;
while(pos != std::string::npos){
counter++;
if(counter > 1){
std::cout << "\nError: Multiple periods\n";
return false;
}
}
The first line simply converts from a Boost multi-precision cpp_dec_float (named i) to a string. I know that this part of the code works, because I use it effectively elsewhere in the program.
I am trying to check if a string contains more than one period. If the string has more than one period in it, the function returns false.
How can I achieve this?
If you find a period, then your next logical step would also be to search again, starting with the next character position.
However, if you review your code, you will not be able to find any place where it is actually searching again. There's no call to find() inside the while loop.
A while loop is not required at all. All you need to do is to call find() a second time, specifying pos+1 as the starting position for the second search, and check the results again. If you find another period, you can call it a wrap. Nothing is to be gained by searching for any remaining periods in the string. You have your answer.
std::size_t pos = periodCheck.find(subString, 0);
if (pos != std::string::npos)
{
pos=periodCheck.find(subString, pos+1);
if (pos != std::string::npos)
return false;
}

C++ check if string is beginning of an english word

I've found a couple answers for how to check if a string is a full word, but nothing for how to check if a string is the first part of a word.
For example, I need a function that will return true for "c", "b", "cong" (congratulations, congruent, etc.), or "exa" (example, examine, etc.), but false for "congx", "qt", or other gibberish.
I'd imagine there are a number of ways to go about this. If you could provide a rough outline for a strategy, I would really appreciate it.
I'm trying to make a Boggle solver.
Thanks!
Is std::string part contained in std::string word?
if(word.find(part) != std::string::npos)
{
// part is in word somethere
}
Is std::string part at the beginning of std::string word?
if(word.find(part) == 0)
{
// word starts with part
}
By way of explanation, std::string::find() returns the position of what was found. So 0 means it was found at the beginning. The value std::string::npos is a special value that indicates nothing was found at all.

How to find out particular word in a string

Problem : I am getting Problem while pass string and find out word in that string.
I have tried below code:
if(string.find("Z03"))
{
// field exists
return true;
}
String :Z030000000057
Here's what I'm trying to do:
if(string.find("Z03"))
{
// field exists
return true;
}
when i pass string in message like ";Z030000000057" then its enter in the loop but when i simply pass "Z030000000057" its go into loop.
Kindly help me for this.
find() returns the index of the first occurrence, or string::npos. Your if is testing if find() returned zero (i.e. first occurrence at beginning of string) or not (i.e. search string occurs later, or not at all).
You are probably looking for...
if ( string.find( "Z03" ) != std::string::npos )
{
// field exists
return true;
}
...which perhaps could be shortened to...
return ( string.find( "Z03" ) != std::string::npos );
...if neither the true nor the false branch do anything else.
Check the documentation on the 'find' method: http://en.cppreference.com/w/cpp/string/basic_string/find
The method returns position of the first character of the found substring or std::string::npos if the substring is not found.
Regarding your examples:
std::string s("Z030000000057");
if(s.find("Z03"))
{
// execution DOES NOT goes here because find returns 0 as found position
}
s = ";Z030000000057";
if(s.find("Z03"))
{
// execution goes here because find returns 1 as found position
}
The correct code would be:
if (s.find("Z03") != std::string::npos)
{
// field exists
}
I recommend using cppreference for further checking standard functions, it's very useful.

CString::find... iterative use issue?

I'm using a CString to search a text block... here's my code:
// locate file name in dir listing
in = *buf;
i = in.Find("DOWNLD .DAT ");// find start of name, two spaces (0x20) as delim
// size of search text here is 14
if (i == -1) return 0;
j = in.Find(' ',i);// now find next space char *after* file size...
// why don't I have to add to i here? There are spaces in my search string.
if (j == -1) return 0;
fileSize = in.Mid((i+14),j-i);// extract file size string, note indexing past found string
return atoi(fileSize.GetBuffer());
Here's what MSDN has to say about the return value of find:
" Return Value
The zero-based index of the first character in this CString object that matches the requested substring or characters; -1 if the substring or character is not found."
Now the way I read this, I have to index past the string I found before doing another find... but the way it actually works, I use the 'i' returned before as the start position for a new search. I'm using this in other places in my program, and I definitely have to index past it (when using ::mid(), for instance)... I'd like to know why this is happening, if by design or bug. The original string can be large; I've seen it near 300chars... is this the problem?
Your second Find call finds the space after "DOWNLD", not the one after ".DAT ". You want to increment i before the second Find call, so that it refers to the first character past the string your first call searched for.
So I didn't find a bug in CString... my code was in error. Here's the code changed that works:
j = in.Find(' ',i+14);// index past searched string
if (j == -1) return 0;
fileSize = in.Mid((i+14),j-i-14);// note -14 added
return atoi(fileSize.GetBuffer());
It was the missing -14 in the mid that was confusing me... the resulting string was 14 past where it should have been, and was missing the portion of interest. Why my original fix worked? Just a coincidence I guess.
Thanks for helping!

CString extract file path

Hey I'm trying to extract the file path but the problem is that I'm stuck in an infinite loop don't understand why. Please have a look at my code.
CString myString(_T("C:\\Documents and Settings\\admin\\Desktop\\Elite\\Elite\\IvrEngine\\dxxxB1C1.log"));
int pos = myString.Find(_T("\\"));
while (pos != -1)
{
pos = myString.Find(_T("\\"), pos); // it keeps returning 2
}
CString folderPath = myString.Mid(pos);
Now the problem is that, Find() returns 2 the first time I run, but then in the while loop it keeps returning 2, why is the function unable to find the rest '\' ? So now I'm in an infinite loop :(.
It sounds like Find includes the character at the position you give it when searching. So if you give it the position of a character that matches the search, then it will return that same position.
You probably need to change it to:
pos = myString.Find(_T("\\"), pos + 1);
your code will never work! When the while loop finished, the contend of pos can not be used.
Here is a solution which will work:
CString folderPath;
int pos = myString.ReverseFind('\\');
if (pos != -1)
{
folderPath = myString.Left(pos);
}
You can fix the code (see the pos + 1 answers) but I think that you should use _splitpath_s instead which was intended for this kind of operations.
CString::Find always returns the first occurence of the character you're searching for. So it keeps finding the the first "\\" which is at index 2 infinitely since you're searching from 2 which includes that "\\"
I can understand your initial implementation, as the behaviour of CString::Find() seem to have changed over time.
Take a look at the MSDN docs for MFC implementation shipped with VC6 here and at the current implementation here. Especially look at the differences of the description of the 2nd offset parameter.
The solution to your problem is, as already stated above, to add 1 to the search offset of the successive Find() calls. You can also search for single chars (or wchar_ts) like that:
myString.Find(_T('\\'), pos+1);
EDIT:
BTW, take a look at the Path* familly of functions exposed by the shlwapi.dll, declared in shlwapi.h. Especially the PathRemoveFileSpec function might be of interest to you.
in MFC, example to get folder which including executable file:
char ownPth[MAX_PATH];
// Will contain exe path
HMODULE hModule = GetModuleHandle(NULL);
if(NULL == hModule){
return __LINE__;
}
// When passing NULL to GetModuleHandle, it returns handle of exe itself
GetModuleFileName(hModule,ownPth, (sizeof(ownPth)));
modulePath = (LPCSTR)ownPth;
modulePath = modulePath.Left(modulePath.ReverseFind(_T('\\')));
return 0;