'Eject excess space from string in C
I need to write a function which will eject excess space from string in C.
Example:
char s[]=" abcde abcde ";
OUTPUT:
"abcde abcde"
Code:
#include <stdio.h>
#include <ctype.h>
char *eject(char *str) {
int i, x;
for (i = x = 0; str[i]; ++i)
if (!isspace(str[i]) || (i > 0 && !isspace(str[i - 1])))
str[x++] = str[i];
if(x > 0 && str[x-1] == ' ') str[x-1] = '\0';
return str;
}
int main() {
char s[] = " abcde abcde ";
printf("\"%s\"", eject(s));
return 0;
}
This code doesn't work for string " "
If this string is found program should print:
""
How to fix this?
Solution 1:[1]
You could write two functions which trim leading and trailing whitespace characters.
void trim_front(char *src) {
size_t i = 0, j = 0;
while (isspace(src[i])) i++;
while (i < strlen(src)) src[j++] = src[i++];
src[j] = '\0';
}
void trim_back(char *src) {
char *ch = src + strlen(src) - 1;
while (isspace(*ch)) *ch-- = '\0';
}
If you know you don't have to deal with trailing or leading spaces, your task becomes much simpler.
void reduce_spaces(char *src) {
size_t i = 0, j = 0;
for (; i < strlen(src); ++i) {
if (i == strlen(src) - 1 ||
(isspace(src[i]) && !isspace(src[i + 1])) ||
!isspace(src[i])) {
src[j++] = src[i];
}
}
src[j] = '\0';
}
And testing this:
int main(void) {
char s[] = " hello world ";
trim_front(s);
trim_back(s);
reduce_spaces(s);
printf(">%s<\n", s);
return 0;
}
% gcc test.c
% ./a.out
>hello world<
%
Of course, if you really want to, you can transplant the code from those functions into reduce_spaces, but decomposing a problem into multiple smaller problems can make things much easier.
Solution 2:[2]
A slightly more advanced answer just for reference - suppose you were tasked in writing a professional library for the use in real world programs. Then one would first list all requirements that make sense:
- It's good practice to treat strings as "immutable" - that is, build up a new string based on the old one rather than in-place replacement.
- Take the destination string as parameter but also return a pointer to it (similar to
strcpyetc functions). - In case of empty strings, set the destination string empty too.
- Remove all "white space" not just the
' 'character. - Instead of always inserting a space character after each word, why not insert a variable delimiter? Might as well be something like
,or;. - No delimiter should be inserted after the last word.
- The algorithm should only traverse the data once for performance reasons. That is, internal calls like
strlenetc are unacceptable. - Byte by byte iteration is fine - we need not care about alignment.
Then we might come up with something like this:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
char* trim_delimit (char* restrict dst, const char* restrict src, char delim)
{
char* start = dst;
*dst = '\0';
bool remove_spaces = true;
char* insert_delim_pos = NULL;
for(; *src != '\0'; src++)
{
if(remove_spaces)
{
if(!isspace(*src))
{
remove_spaces = false;
if(insert_delim_pos != NULL)
{
// we only get here if more words were found, not yet at the end of the string
*insert_delim_pos = delim;
insert_delim_pos = NULL;
}
}
}
if(!remove_spaces)
{
if(isspace(*src))
{
remove_spaces = true;
insert_delim_pos = dst; // remember where to insert delimiter for later
}
else
{
*dst = *src;
}
dst++;
}
}
return start;
}
Test cases:
int main (void)
{
char s[]=" abcde abcde ";
char trimmed[100];
puts(trim_delimit(trimmed, s, ' '));
puts(trim_delimit(trimmed, "", ' '));
puts(trim_delimit(trimmed, s, ';'));
}
Output:
abcde abcde
abcde;abcde
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Lundin |
