strpbrk
tags: strchr, strcspn, string.h, strpbrk
The strpbrk
function provides a simpler method of calling strchr
when
searching for any one of several characters in a given string. It searches one
string for the first occurrence of any character in another string.
char *
strpbrk(const char *s1, const char *s2);
The return value is a pointer to the found character, or NULL
if no characters
were found.
Suppose you wanted to split a string on any one of a set of characters, but you
wanted to know whether you could perform a split before doing the work (e.g.
before calling strtok
). strpbrk
will return the pointer to the split
location assuming you wanted to split on whichever of your characters came
first, then you could do you more advanced logic of breaking the string into two
pieces.
char *phrase = "Goodbye, cruel world";
char *set = "abc";
if (strpbrk(phrase, set))
{
/* Advanced split logic */
}
You may think that this sounds very similar to strcspn
and that's because it
is! The difference is that strcspn
indicates a length between the start of the
string and the first match while strpbrk
returns a pointer to the first match.
Local Variables
We'll be utilizing the strcspn
function to do the core work and we want to
store the return value so we can index into the string being searched.
size_t idx = 0;
Error Checking
Since strcspn
can indicate an error by returning 0
, we wouldn't know whether
a character was found in the first location or if an error occurred, so we need
to validate s1
before passing it to strcspn
. Normally we would want to check
for a NULL
s2
pointer, however strcspn
will do that for us so we can skip
that check.
if (!s1)
{
return NULL;
}
Implementation
We'll leverage strcspn
to find the length to the first match which allows us
to validate no match if the length is equal to the length of our string being
searched. In that case we return NULL
, otherwise we return a pointer to the
matched character which is the string pointer plus the length returned by
strcspn
.
idx = strcspn(s1, s2);
if ('\0' == s1[idx])
{
return NULL;
}
return (char *)(s1 + idx);
Testing
Due to the similar functionality, the testing is nearly identical to that of
strcspn
. We'll test input validation and then cases where there are no matches
and then matches at the beginning, middle, and end of the string being searched.
int
strpbrkTest(void)
{
int ret = 1;
char str[] = "ABCDEFGabcdefg";
do
{
/* NULL search string */
if (NULL != strpbrk(NULL, "abcd"))
{
ret = 2;
break;
}
/* NULL search set */
if (NULL != strpbrk(str, NULL))
{
ret = 3;
break;
}
/* Empty search string */
if (NULL != strpbrk("", "abcd"))
{
ret = 4;
break;
}
/* Empty search set */
if (NULL != strpbrk(str, ""))
{
ret = 5;
break;
}
/* Characters not in search string */
if (NULL != strpbrk(str, "hijk"))
{
ret = 6;
break;
}
/* First character matches */
if (str != strpbrk(str, "hijAklm"))
{
ret = 7;
break;
}
/* Last character matches */
if ((str + strlen(str) - 1) != strpbrk(str, "hijgklm"))
{
ret = 8;
break;
}
/* Match in middle */
if (strchr(str, 'a') != strpbrk(str, "hijaklm"))
{
ret = 9;
break;
}
ret = 0;
} while (0);
return ret;
}
Conclusion
The name wasn't immediately obvious to me but strpbrk
stands for "string
pointer break" which likely comes from the SNOBOL language which had a BREAK()
function to perform the same task (and it had a SPAN()
function that mirrors
strcspn
). Due to the commanality with strcspn
, you could swap which function
does the main work and then implement strcpsn
by calling this function
instead.
char *
strpbrk(const char *s1, const char *s2)
{
size_t idx = 0;
if (!s1)
{
return NULL;
}
idx = strcspn(s1, s2);
if ('\0' == s1[idx])
{
return NULL;
}
return (char *)(s1 + idx);
}