For example, if the string is "Only for Geeky People"
and I am looking for only "Geek"
substring not "Geeky"
, it would say the word is not present.
ie strstr("Only for Geeky People", "Geek")
would be NULL.
How do I address such an issue?
For example, if the string is "Only for Geeky People"
and I am looking for only "Geek"
substring not "Geeky"
, it would say the word is not present.
ie strstr("Only for Geeky People", "Geek")
would be NULL.
How do I address such an issue?
You have to deal with it by wrapping strstr()
in a function, perhaps str_word()
(which avoids reserved names), that does extra checking after finding the word. Or, at least, that is probably the most sensible way to deal with it.
Padding the search string with spaces won't work. Leading padding would prevent the code from finding "Geek"
or "(Geek is not pejorative)"
; trailing padding would prevent it from finding "Ozymandias is a Geek"
. Etc. If you want to go OTT, you could consider going for a powerful regular expression library like PCRE, but it is overkill for this task (and the POSIX <regex.h>
isn't sufficiently powerful — it doesn't recognize word boundaries).
char *str_word(char *haystack, const char *needle)
{
char *from = haystack;
size_t length = strlen(needle);
char *found;
while ((found = strstr(from, needle)) != NULL)
{
if (found > haystack && isalpha((unsigned char)found[-1]))
from += length;
else if (isalpha((unsigned char)found[length]))
from += length;
else
return found;
}
return NULL;
}
Note that this allows the function to find the Geek in "Ozymandias is such a Geeky Geek"
.
Beware trying to add const-correctness to this. You can use this easily enough:
const char *str_word(const char *haystack, const char *needle);
However, you can't return a non-const char *
when passed a const char *
without a cast that removes the const-ness somewhere along the line. Returning a const char *
punts the process of removing const-ness to the calling code. This matters in a context such as:
char *word = str_word(line, "Geek");
You have a variable array containing a line of input; you want to search for the word in that line, and get a non-const pointer back.
Test code:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
extern char *str_word(char *haystack, const char *needle);
char *str_word(char *haystack, const char *needle)
{
char *from = haystack;
size_t length = strlen(needle);
char *found;
while ((found = strstr(from, needle)) != NULL)
{
if (found > haystack && isalpha((unsigned char)found[-1]))
from += length;
else if (isalpha((unsigned char)found[length]))
from += length;
else
return found;
}
return NULL;
}
int main(void)
{
const char search[] = "Geek";
char haystacks[][64] =
{
"Geek",
"(Geek is not pejorative)",
"Ozymandias is a Geek",
"Ozymandias is such a Geeky Geek",
"No prizes for Geekiness",
"Only for Geeky people",
"Howling 'Geek' gets you nowhere",
"A Geek is a human",
"Geeky people run the tech world",
};
enum { NUM_HAYSTACKS = sizeof(haystacks) / sizeof(haystacks[0]) };
for (int i = 0; i < NUM_HAYSTACKS; i++)
{
char *word = str_word(haystacks[i], search);
if (word == NULL)
printf("Did not find '%s' in [%s]\n", search, haystacks[i]);
else
printf("Found '%s' at [%s] in [%s]\n", search, word, haystacks[i]);
}
return 0;
}
Test results:
Found 'Geek' at [Geek] in [Geek]
Found 'Geek' at [Geek is not pejorative)] in [(Geek is not pejorative)]
Found 'Geek' at [Geek] in [Ozymandias is a Geek]
Found 'Geek' at [Geek] in [Ozymandias is such a Geeky Geek]
Did not find 'Geek' in [No prizes for Geekiness]
Did not find 'Geek' in [Only for Geeky people]
Found 'Geek' at [Geek' gets you nowhere] in [Howling 'Geek' gets you nowhere]
Found 'Geek' at [Geek is a human] in [A Geek is a human]
Did not find 'Geek' in [Geeky people run the tech world]