#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* Trim (right-left) and returns a new allocated string or NULL */
char *sstrip(const char *s);
char *sstrip(const char *s)
{
char *value = NULL;
size_t len;
if (s) {
while (*s && isspace(*s)) s++;
for (len = strlen(s); isspace(s[len - 1]); len--);
value = malloc(len + 1);
if (!value) {
fprintf(stderr, "%s\n", "Buy more RAM!!");
exit(0);
}
strncpy(value, s, len);
value[len] = '\0';
}
return value;
}
int main(void)
{
char *s;
s = sstrip("test");
printf("<%s>\n", s);
if (s) free(s);
s = sstrip(" test ");
printf("<%s>\n", s);
if (s) free(s);
s = sstrip("test ");
printf("<%s>\n", s);
if (s) free(s);
s = sstrip(" test");
printf("<%s>\n", s);
if (s) free(s);
s = sstrip("");
printf("<%s>\n", s);
if (s) free(s);
s = sstrip(NULL);
printf("<%s>\n", s);
if (s) free(s);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* Trim left and right spaces returning a new allocated string or NULL
*/
char *sstrip(const char *s);
char *sstrip(const char *s)
{
char *value = NULL;
size_t len = 0;
if (s) {
while (*s && isspace(*s)) s++;
if (*s) for (len = strlen(s); isspace(s[len - 1]); len--);
value = malloc(len + 1);
if (value == NULL) {
What difference does it make
if it's trimmed from the other direction?
--
pete
Perhaps he means right-trim AND left-trim?
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
This line unintentionally left unblank
You can simplify the test to just isspace(*s), since
isspace() produces false for the '\0' at the end of the string.
Actually, that's not quite right: The <ctype.h> functions
should not be applied to ordinary char values. On systems
where char is signed, a char value in a string could be negative
(this won't happen for characters in the "basic execution set"
like 'a' and '/' and '5', but can happen for "extended" glyphs
like '�', '�', '�'). However, the <ctype.h> functions accept
only one negative argument: the value of the macro EOF. Feed
them a different negative value, and there's no telling what
will happen. So the test should actually be
isspace( (unsigned char)*s )
... with similar modifications elsewhere.
> if (*s) for (len = strlen(s); isspace(s[len - 1]); len--);
> value = malloc(len + 1);
> if (value == NULL) {
> fprintf(stderr, "%s\n", "Buy more RAM!!");
> exit(0);
Okay in a toy program. A production-quality function
would most likely return NULL to let the caller decide what
to do; a low-level function like this one is in a poor position
to make global decisions about the program's life or death.
> }
> strncpy(value, s, len);
Ugh. Well, there's nothing really *wrong* with this, but
I have a reflexive gag reaction to strncpy(), because it's so
often used incorrectly. In this instance you've made no mistake
(that I can see), but I'd still suggest using memcpy() as a
clearer statement of what you're doing: Copying a batch of
characters not terminated by a '\0'.
> value[len] = '\0';
> }
> return value;
> }
--
Eric Sosman
eso...@ieee-dot-org.invalid
Yes ;)
Could you clarify this point with a little example?
>
> ... with similar modifications elsewhere.
>
> > if (*s) for (len = strlen(s); isspace(s[len - 1]); len--);
> > value = malloc(len + 1);
> > if (value == NULL) {
> > fprintf(stderr, "%s\n", "Buy more RAM!!");
> > exit(0);
>
> Okay in a toy program. A production-quality function
> would most likely return NULL to let the caller decide what
> to do; a low-level function like this one is in a poor position
> to make global decisions about the program's life or death.
Yes, I use my own xmalloc in real life :)
>
> > }
> > strncpy(value, s, len);
>
> Ugh. Well, there's nothing really *wrong* with this, but
> I have a reflexive gag reaction to strncpy(), because it's so
> often used incorrectly. In this instance you've made no mistake
> (that I can see), but I'd still suggest using memcpy() as a
> clearer statement of what you're doing: Copying a batch of
> characters not terminated by a '\0'.
>
> > value[len] = '\0';
> > }
> > return value;
> > }
Thanks for the suggestions Pete
> Thanks for the suggestions Pete
ops, thanks for the suggestions Eric
> Hi, anybody knows a better way to (right-left) trim a string?
Whether this way is better depends on what you mean by "better", but
it's perhaps worth considering. I will take it as read that you wish
to have a fresh string, by the way.
The advantage of the following approach is that it lets you set your
left/right delimiters arbitrarily. (If you want separate delimiters
for left and right, it's easy to add this by changing wrappings to
lwrappings, adding rwrappings to the parmlist, and changing the
strchr call to use rwrappings.)
You should free the allocated string when you're done with it.
#include <stdlib.h>
#include <string.h>
char *lrtrim(const char *s, const char *wrappings)
{
char *new = NULL;
if(s != NULL)
{
size_t start = 0;
size_t len = 0;
const char *p = s;
const char *q = p;
if(wrappings != NULL)
{
start = strspn(s, wrappings);
p += start; /* p now points to first character to keep */
q = p + strlen(p); /* q points to terminator */
while(q > p && strchr(wrappings, *--q) != NULL)
{
continue;
}
}
else
{
q = p + strlen(p);
}
/* q now points to the last character to keep */
/* there are 1 + q - p characters to keep, and we want
* one space for the null terminator */
len = 1 + q - p;
new = malloc(len + 1);
if(new != NULL)
{
memcpy(new, p, len);
new[len] = '\0';
}
}
return new;
}
#include <stdio.h>
int main(void)
{
const char *testA = NULL;
const char *wrapA = NULL;
char *resultA = lrtrim(testA, wrapA);
const char *testB = "ALLTHISSHOULDGOall this should
stayTHISTOOSHOULDGO";
const char *wrapB = "ALTHISOUDG";
const char *testC = "Everything should stay";
char *resultB = lrtrim(testB, wrapB);
char *resultC = lrtrim(testC, wrapA);
if(resultA != NULL)
{
printf("[%s] - [%s] = [%s]\n", testA, wrapA, resultA);
}
else
{
puts("Test A: null return");
}
if(resultB != NULL)
{
printf("[%s] - [%s] = [%s]\n", testB, wrapB, resultB);
}
else
{
puts("Test B: null return");
}
if(resultC != NULL)
{
printf("[%s] - [%s] = [%s]\n", testC, "NULL", resultC);
}
else
{
puts("Test C: null return");
}
free(resultC);
free(resultB);
free(resultA);
return 0;
}
(I have done a little testing of this code, but bug reports are
welcome.)
What's unclear? Here's a re-cap:
1) On some systems, the `char' type is signed. On these
systems, some character values are positive, some are negative.
1a) Negative character values sometimes go unnoticed because
the characters in the "basic execution set" -- roughly speaking,
those that the Standard requires -- are all non-negative. Merkuns
are particularly likely to forget about negative characters, since
their impoverished repertoire of characters is mostly covered by
the basic execution set, and hence non-negative.
1b) ... but many (most?) systems support a wider range of
characters than the C Standard insists upon. Even systems that
are only "mildly international" usually support accented letters
that look funny to Merkuns but are important in European languages.
And then there are things like the Pound Sterling symbol, the Euro
symbol, the upside-down question and exlamation marks, ... On
many systems, the codes for some of these characters are negative.
2) isspace() and the other <ctype.h> functions take `int'
arguments, but not every possible `int' value. Their behavior
is defined only for arguments that are
2a) ... in the range 0 through UCHAR_MAX, inclusive, or
2b) ... equal to the value of the macro EOF from <stdio.h>.
This value is a negative `int', usually (but not necessarily)
negative one.
2c) If you feed a <ctype.h> function a value other than
those mentioned in (2a) and (2b), the function's behavior is
undefined, and there's no telling what it might do.
2c') In particular, if you feed the function a negative
value other than EOF, there's no telling what will happen.
3) Taking (1*) and (2*) together, we see that it is unsafe
to just pluck a character out of a string and hand it to a
<ctype.h> function: The character might be negative, and then
you'd be out of luck.
3a) The way to avoid the harsh fate of (3) is to say "Aha!
I know this string-resident char is a real character, not an
indication of I/O failure, so I need to convert it to a nice,
non-negative value in the (2a) range." That's what the cast
does.
It's a sad and sorry state of affairs, the remnants of a
prehistoric <ctype.h> whose design was not well thought-out.
(The usual remark about hindsight being 20-20 applies here.)
If the original <ctype.h> designers had said "The argument
must be a char, period, and not an EOF" all would be well.
Or if they'd decided to allow EOF but insisted that EOF have
a value unequal to any possible char, that would have been
all right, too. But they didn't, and we're stuck with the
fallout.
--
Eric Sosman
eso...@ieee-dot-org.invalid
I must cast all params passed to ctype or is better to made my own
safe functions?
Thanks for the advise
Pardon my ignorance please, it's hard to me to speak english:
int cisspace(int c)
{
return ((c == ' ') || (c == '\n') || (c == '\t'));
}
this solve the problem?
Either way will work: You can write wrappers for almost
any Standard library function to "condition" the arguments
if you like. My own preference is to write the clumsy cast
and call the <ctype.h> function directly, but my preferences
aren't binding on you. There may be a speed advantage in
my way, but in the context of a full-scale program (where the
strings most likely come from slow I/O operations), any speed
difference is likely to be unimportant.
--
Eric Sosman
eso...@ieee-dot-org.invalid
The comment is not true in the "else" case. It is entirely harmless
9as far as I can tell) since you just allocate and extra char and end
up with two null bytes at the end, but it's not "pretty".
> /* there are 1 + q - p characters to keep, and we want
> * one space for the null terminator */
> len = 1 + q - p;
> new = malloc(len + 1);
> if(new != NULL)
> {
> memcpy(new, p, len);
> new[len] = '\0';
> }
> }
>
> return new;
> }
<snip>
--
Ben.
> Richard Heathfield <r...@see.sig.invalid> writes:
<snip>
>> else
>> {
>> q = p + strlen(p);
>> }
>> /* q now points to the last character to keep */
>
> The comment is not true in the "else" case.
Good spot. Thanks, Ben. The (rather ugly) fix is:
else
{
q = p + strlen(p);
if(q > p)
{
--q;
}
}
You know and I know that the (inelegant) check is to ensure that we
don't run off the beginning of an empty string and invoking undefined
behaviour, but I thought I'd just mention it in case anyone is
reading who didn't know this.
<snip>
If you look at 7.4.1.10 in the C99 standard, you will find that there
are other standard characters which are considered to be "spaces", \f,
\r, etc. There are also differences based on locale. If you never
have to deal with them, then you can limit you code to you do deal
with. If you want your function to be equivalent to the one in the
standard library, you have to do a bit more work.
--
Remove del for email
The if test belongs on the call to printf. If s is NULL, the call to
printf invokes undefined behavior. On the other had, if s is NULL,
passing it to free causes no problem.
> Ben Bacarisse said:
>
>> Richard Heathfield <r...@see.sig.invalid> writes:
> <snip>
>>> else
>>> {
>>> q = p + strlen(p);
>>> }
>>> /* q now points to the last character to keep */
>>
>> The comment is not true in the "else" case.
>
> Good spot. Thanks, Ben. The (rather ugly) fix is:
>
> else
> {
> q = p + strlen(p);
> if(q > p)
> {
> --q;
> }
> }
This may be just part of the "ugly", but that still goes on to
allocate a two-byte null string if s is zero-length to start with.
> You know and I know that the (inelegant) check is to ensure that we
> don't run off the beginning of an empty string and invoking undefined
> behaviour, but I thought I'd just mention it in case anyone is
> reading who didn't know this.
Because of this, I prefer to mark the end of sub-strings with a "just
past" pointer rather than a "last needed" pointer. I think it tidies
up the code a little. For example, the comment about why we need +1
twice now looks redundant. I've duped your style for a fair
comparison:
char *lrtrim(const char *s, const char *wrappings)
{
char *new = NULL;
if(s != NULL)
{
size_t start = 0;
size_t len = 0;
const char *p = s;
const char *q = p;
if(wrappings != NULL)
{
start = strspn(s, wrappings);
p += start; /* p now points to first character to keep */
q = p + strlen(p); /* q points to terminator */
while(q > p && strchr(wrappings, q[-1]) != NULL)
{
--q;
}
}
else
{
q = p + strlen(p);
}
/* q now points just past the last character to keep */
/* there are q - p characters to keep, and we want
* one space for the null terminator */
len = q - p;
new = malloc(len + 1);
if(new != NULL)
{
memcpy(new, p, len);
new[len] = '\0';
}
}
return new;
}
[The laws of the Internet mean I'll introduced some bugs, but it is
worth a shot.]
--
Ben.
<snip>
> Because of this, I prefer to mark the end of sub-strings with a
> "just past" pointer rather than a "last needed" pointer.
I was going to do that (and in fact it's how my own "stretchy string"
library works), but I chickened out when it came to doing...
<snip>
> while(q > p && strchr(wrappings, q[-1]) != NULL)
^^^^^
...this, because I guessed I'd attract some stick for it. Well, now
you can have it instead. :-)
Incidentally, I guess the OP is long gone.
I'm still here, as voyeur but I'm still here :)
> On 28 ago, 19:35, Richard Heathfield <r...@see.sig.invalid> wrote:
>> Por cierto, creo que el PO se ha ido.
Did I really say that? :-)
>
> I'm still here, as voyeur but I'm still here :)
Sorry about that. We lose a lot of OPs for some reason.
Anyway, I hope my version has at least given you food for thought.
> /* Trim (right-left) and returns a new allocated string or NULL */
> char *sstrip(const char *s);
> char *sstrip(const char *s)
I'd be tempted to have a destination parameter here, so that the
caller can avoid the nuisance of dealing with allocated strings (by
using a fixed length buffer).
Passing a NULL destination can be be used to request an allocated
string.
If the source and destination strings are in the same place, then this
can also be dealt with, with a bit of extra care, and is even more
convenient.
The actual trimming operation: I haven't tried your code. If it works,
and is fast enough, then fine. Although, when I did something like
this, I made it possible to trim only one end, but I can't at the
minute tell you why that was a good idea...
--
Bartc
You could try doing it in place; something like this:
typed directly in newsreader, try and forgive any typos ;^o
_______________________________________________________________
#include <string.h>
#include <ctype.h>
#define xisspace(c) isspace((int)(c))
char*
trim_string(char* const buffer)
{
char* cur = buffer;
while (*cur && xisspace(*cur))
{
++cur;
}
if (*cur)
{
char* end = NULL;
char* start = cur;
++cur;
while (*cur)
{
if (xisspace(*cur))
{
if (! end)
{
end = cur;
}
}
else
{
end = NULL;
}
++cur;
}
if (start != buffer)
{
memmove(buffer, start, cur - start);
if (! end)
{
start = buffer + (cur - start);
*start = '\0';
}
}
if (end)
{
end -= (cur - buffer) - (cur - start);
*end = '\0';
}
}
return buffer;
}
_______________________________________________________________
You could use it like:
_______________________________________________________________
#include <stdio.h>
int main(void)
{
char name1[] = " Hello World! ";
char name2[] = "123 - 456 - 768 ";
char name3[] = " a b c d";
printf("->%s<-\n", trim_string(name1));
printf("->%s<-\n", trim_string(name2));
printf("->%s<-\n", trim_string(name3));
return 0;
}
_______________________________________________________________
That should be:
#define xisspace(c) isspace((unsigned char)(c))
ARGHG!%$#!@
;^o
This isn't a typo; it's a thinko.
> char* cur = buffer;
> while (*cur && xisspace(*cur))
... and this is still wrong, for all the same old reasons.
Also redundant, as well in addition to boot also.
See my detailed explanations to DavidRF, elsethread.
--
Eric Sosman
eso...@ieee-dot-org.invalid
> On Aug 28, 12:06 pm, David RF <davran...@gmail.com> wrote:
>> Hi, anybody knows a better way to (right-left) trim a string?
>
>> /* Trim (right-left) and returns a new allocated string or NULL */
>> char *sstrip(const char *s);
>> char *sstrip(const char *s)
>
> I'd be tempted to have a destination parameter here, so that the
> caller can avoid the nuisance of dealing with allocated strings (by
> using a fixed length buffer).
In which case you'd be well advised to pass in a buffer size too. The
result string should always be at least no longer than the input
string, so telling the function how much space is available gives it
the opportunity to complain if that space is insufficient.
<snip>
:^)
> ... and this is still wrong, for all the same old reasons.
> Also redundant, as well in addition to boot also.
I have a habit of checking for explicitly checking for NUL character. It's
wrong in the sense of the `xisspace()' macro being defined as taking a
signed value. I already corrected that non-sense:
http://groups.google.com/group/comp.lang.c/msg/d9d69bc065ee78bf
> See my detailed explanations to DavidRF, elsethread.
The ones that deal with negative values being passed to `isspace()'?
> You could try doing it in place; something like this:
>
> typed directly in newsreader, try and forgive any typos ;^o
[...]
Cool!!
Is there a way to forbid the use of isspace() in *.c keeping xisspace
()?
> On 29 ago, 04:11, "Chris M. Thomasson" <n...@spam.invalid> wrote:
<snip>
>> That should be:
>>
>> #define xisspace(c) isspace((unsigned char)(c))
>>
>> ARGHG!%$#!@
>>
>> ;^o
>
>
> Is there a way to forbid the use of isspace() in *.c keeping
> xisspace ()?
If there were, and if you availed yourself of that interdict, how
could xisspace possibly work? It's a macro. Wherever xisspace(x) is
seen in the code, the preprocessor will replace it with
isspace((unsigned char)(x)), which would fall foul of the interdict.
The best you can do, I think, is to forbid it not via your
implementation but via your project coding standards. You can then
search for unwrapped isspace calls in the source (grep is your friend
here), and raise them as project coding standard violations at code
review time.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within
Yes, possibly. This is a special case where the destination *must* be
at least as large as the input string, otherwise it can't be
guaranteed to work, unless the caller has some knowledge of the
expected amount of white space to be trimmed.
Putting in a buffer size would require an error return scheme and
requires the caller to check for the error. All in all, you might as
well stick with the allocation method!
--
Bart C.
Yes, is a stupid question
A different approach: */
#include <string.h>
#include <stdlib.h>
void rev(char *str, size_t len)
{
char *end;
if (!len) len = strlen(str);
if (len < 2) return;
for (end=str+len-1; end > str; end--, str++) {
int tmp;
tmp= *str;
*str = *end;
*end = tmp;
}
}
char * trim(const char *str, size_t len)
{
char *new;
size_t cnt;
cnt = strspn(str, " \t\n\r\f\v" );
str += cnt;
if (!len) len = strlen(str);
else len -= cnt;
new = malloc (len +1);
/* we should check malloc's return value here */
if (len) memcpy(new, str, len);
new[len] = 0;
/* if (!len) we could return early here */
rev(new, len);
cnt = strspn(new, " \t\n\r\f\v" );
len -= cnt;
memcpy(new, str, len);
new[len] = 0;
/* if (cnt) we could realloc() here */
return new;
}
#include <stdio.h>
int main(void)
{
char *src = "\v Hello,\tWorld !\f\n", *dst;
dst = trim(src, 0);
printf("[%s] -> [%s]\n", src, dst);
return 0;
}
/*
It does some more scanning and copying, but has the advantage is that
both leading and trailing white are scanned using strspn(),
HTH,
AvK
| Hi, anybody knows a better way to (right-left) trim a string?
Can you define what you mean by this? I've learned through the years to
never trust implementation code as a description of a problem.
For nul terminated strings, the standard in C (though you can freely do it
in other ways, as I have), to get a substring from the middle of a string
for which I can modify the string in place, I would advance a pointer to
the beginning of the substring, and store a nul character in the position
just past the substring. If modification is not possible, then allocate a
new string if no predetermined space for it, and copy the subtring and add
the termination at the end of the copy.
--
-----------------------------------------------------------------------------
| Phil Howard KA9WGN | http://linuxhomepage.com/ http://ham.org/ |
| (first name) at ipal.net | http://phil.ipal.org/ http://ka9wgn.ham.org/ |
-----------------------------------------------------------------------------
IMHO it's not a good idea to malloc in a function like this. The user
should supply the destination buffer (which he can malloc if he wants).
Things like this are usually used for parsing text files, may be
called millions of times. Typically the trimmed string is thrown away
almost immediately. The huge overhead from a million malloc/free pairs
serves no purpose in such a scenario.
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
> Cool!!
:^)
Here is a little simplification in the adjustment phase:
_____________________________________________________________
if (start != buffer)
{
memmove(buffer, start, cur - start);
if (! end)
{
buffer[cur - start] = '\0';
}
}
if (end)
{
buffer[end - start] = '\0';
}
_____________________________________________________________
One other improvement/simplification could be to skip the call to
`memmove()' altogether and just return a pointer to the `start' location:
_____________________________________________________________
char*
trim_string(char* const buffer)
{
char* cur = buffer;
while (*cur && xisspace(*cur))
{
++cur;
}
if (*cur)
{
char* end = NULL;
char* start = cur;
++cur;
while (*cur)
{
if (xisspace(*cur))
{
if (! end)
{
end = cur;
}
}
else if (end)
{
end = NULL;
}
++cur;
}
if (end)
{
buffer[end - buffer] = '\0';
}
return start;
}
return buffer;
}
_____________________________________________________________
This would limit the number of mutations to the `buffer' down to a single
store of a terminating NUL character.
> On 28 ago, 15:56, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:
> > =A0 =A0 =A02c) If you feed a <ctype.h> function a value other than
> > those mentioned in (2a) and (2b), the function's behavior is
> > undefined, and there's no telling what it might do.
>
> I must cast all params passed to ctype or is better to made my own
> safe functions?
That depends on where you get it from. If you have a char, cast it to
unsigned char. If, OTOH, you have an int that you just got from
getchar() or something related, you can (and should) pass it directly to
the <ctype.h> functions.
Richard
How can you trim (left and right trim) a (const char *) if you don't
allocate a new string?
glib do this (without malloc):
gchar*
g_strchug (gchar *string)
{
guchar *start;
g_return_val_if_fail (string != NULL, NULL);
for (start = (guchar*) string; *start && g_ascii_isspace (*start);
start++)
;
g_memmove (string, start, strlen ((gchar *) start) + 1);
return string;
}
gchar*
g_strchomp (gchar *string)
{
gsize len;
g_return_val_if_fail (string != NULL, NULL);
len = strlen (string);
while (len--)
{
if (g_ascii_isspace ((guchar) string[len]))
string[len] = '\0';
else
break;
}
return string;
}
/* and finally trim */
#define g_strstrip( string ) g_strchomp (g_strchug (string))
Not tested but functions fail when a const char* (read only string) is
passed because of the use of memmove and string[len] = '\0';
Please, excuse my poor english
Put the trimmed string into memory provided by the caller of the
function, rather than by the trimming function itself. This might be
dynamically allocated memory, but it doesn't have to be.
> Put the trimmed string into memory provided by the caller of the
> function, rather than by the trimming function itself. This might be
> dynamically allocated memory, but it doesn't have to be.
Yes!!
char *trim(const char *orig, char *dest)
Thanks to all posters of this thread
One disadvantage of this is that the caller has to ensure that
dest points to (the first element of) an array big enough to hold
the result. In this case, making the destination array the same
size as the source array is (more than) sufficient.
(BTW, for symmetry, I'd probably call the parameters src and dest
rather than orig and dest.)
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
You could try something like this:
__________________________________________________________________
#include <string.h>
#include <assert.h>
#include <ctype.h>
#define xisspace(c) isspace((unsigned char)(c))
char*
trim_string(char* const buffer,
char** const end_buffer)
{
char* cur = buffer;
while (*cur && xisspace(*cur))
{
++cur;
}
if (*cur)
{
char* end = NULL;
char* start = cur;
++cur;
while (*cur)
{
if (xisspace(*cur))
{
if (! end)
{
end = cur;
}
}
else if (end)
{
end = NULL;
}
++cur;
}
if (end_buffer)
{
if (end)
{
*end_buffer = buffer + (end - buffer);
}
else
{
*end_buffer = cur;
}
}
return start;
}
else if (end_buffer)
{
*end_buffer = buffer;
}
return buffer;
}
#include <stdio.h>
void
print_trim_string(char* buffer)
{
char* end;
char const* start = trim_string(buffer, &end);
char tmp = *end;
*end = '\0';
printf("(%lu)->%s<-\n\n",
(unsigned long int)(end - start),
start);
*end = tmp;
}
int main(void)
{
char name1[] = " Hello World! ";
char name2[] = "123 - 456 - 768 ";
char name3[] = " a b c d";
char name4[] = "a b c d";
char name5[] = "Hello";
char name6[] = " ";
char name7[] = "";
trim_string(name1, NULL);
trim_string(name2, NULL);
trim_string(name3, NULL);
trim_string(name4, NULL);
trim_string(name5, NULL);
trim_string(name6, NULL);
trim_string(name7, NULL);
print_trim_string(name1);
print_trim_string(name2);
print_trim_string(name3);
print_trim_string(name4);
print_trim_string(name5);
print_trim_string(name6);
print_trim_string(name7);
return 0;
}
__________________________________________________________________
In this version `trim_string()' does not mutate the caller provided
`buffer'. Instead, it simply returns information on exactly where the
trimmed string starts and ends. The caller can do whatever she/he wants with
this information. As you can see, `print_trim_string()' temporally swaps the
`end' character with a NUL, prints the trimmed string along with it's length
and restores the character it previously swapped out.
This also allows you to easily create another dynamically created buffer if
you wish:
__________________________________________________________________
#include <stdio.h>
#include <stdlib.h>
char*
create_trim_string(char const* buffer)
{
char* const end;
char const* start = trim_string((char*)buffer, (char**)&end);
char* new_buffer = malloc(end - start + 1);
if (new_buffer)
{
memcpy(new_buffer, start, end - start);
new_buffer[end - start] = '\0';
}
return new_buffer;
}
int main(void)
{
char const name1[] = " Hello World! ";
char* buffer = create_trim_string(name1);
puts(buffer);
free(buffer);
return 0;
}
__________________________________________________________________
Any thoughts?
> This also allows you to easily create another dynamically created buffer
> if you wish:
> __________________________________________________________________
> #include <stdio.h>
> #include <stdlib.h>
>
>
> char*
> create_trim_string(char const* buffer)
> {
> char* const end;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
That should be `char const* end;' if course!
;^/
Or even return the size of the newly allocated string to perhaps allow the
caller to avoid a call to `strlen()', or whatever:
__________________________________________________________________
#include <stdio.h>
#include <stdlib.h>
char*
create_trim_string(char const* buffer, size_t* size)
{
char const* end;
char const* start = trim_string((char*)buffer, (char**)&end);
char* new_buffer = malloc((end - start) + 1);
if (new_buffer)
{
memcpy(new_buffer, start, end - start);
new_buffer[end - start] = '\0';
}
if (size) *size = end - start;
return new_buffer;
}
int main(void)
{
size_t size;
char const name1[] = " Hello World! ";
char* buffer = create_trim_string(name1, &size);
printf("(%lu)->%s<-\n", (unsigned long int)size, buffer);
free(buffer);
return 0;
}
__________________________________________________________________
> /* Trim (right-left) and returns a new allocated string or NULL */
> char *sstrip(const char *s);
this is a declaration of a function. It acts as a prototype
for the function.
> char *sstrip(const char *s)
> {
this is a definition of the function. It is also acts as
a prototype for the function. You don't need both of them.
--
oh, that's too simple to test...
<G>
> Damn! As a voting and newswatching merkin (is that an oxymoron?)
No, merely a rarity.
Richard
As a fellow Merkun, and with some relevance to the matter
of character sets larger than Our Own, I repeat this trifle:
A person who speaks several languages is "multilingual."
A person who speaks two languages is "bilingual."
A person who speaks one language is "American."
(The word "badly" may be inserted in the last sentence, if your
taste so dictates.)
--
Eric Sosman
eso...@ieee-dot-org.invalid
I'm an American who has learned Spanish, German, Russian, a little bit
of Korean, and Mandarin. However, in more than three decades of
programming in this country, I have to admit that I've never needed to
write C code that had to interpret characters outside of the C basic
character set. I've written any number of filters that would pass such
characters from one place to another without interpretation, but that's
a much simpler case to deal with.
<snip>
> A person who speaks several languages is "multilingual."
>
> A person who speaks two languages is "bilingual."
>
> A person who speaks one language is "American."
In the interests of international amity, I would like to mention that
there is an American who lives not too far from me, who speaks fluent
Portuguese and pretty good English.
She's from Brazil.
<snip>
One of my American workmates is also a multi-lingual, and, yes, he's from
the United States. He speaks Spanish and English very well, and some
spatterings of French and Italian too. The education system in the United
States of Mexico can be complimented.
Phil
--
Any true emperor never needs to wear clothes. -- Devany on r.a.s.f1