Cの文字列から先頭と末尾の空白をトリミングする、きれいでできれば標準的な方法はありますか? 私は自分でロールバックしますが、これは同様に一般的な解決策を持つ一般的な問題だと思います.
39 に答える
文字列を変更できる場合:
// Note: This function returns a pointer to a substring of the original string.
// If the given string was allocated dynamically, the caller must not overwrite
// that pointer with the returned value, since the original pointer must be
// deallocated using the same allocator with which it was allocated. The return
// value must NOT be deallocated using free() etc.
char *trimwhitespace(char *str)
{
char *end;
// Trim leading space
while(isspace((unsigned char)*str)) str++;
if(*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
// Write new null terminator character
end[1] = '\0';
return str;
}
文字列を変更できない場合は、基本的に同じ方法を使用できます。
// Stores the trimmed input string into the given output buffer, which must be
// large enough to store the result. If it is too small, the output is
// truncated.
size_t trimwhitespace(char *out, size_t len, const char *str)
{
if(len == 0)
return 0;
const char *end;
size_t out_size;
// Trim leading space
while(isspace((unsigned char)*str)) str++;
if(*str == 0) // All spaces?
{
*out = 0;
return 1;
}
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
end++;
// Set output size to minimum of trimmed string length and buffer size minus 1
out_size = (end - str) < len-1 ? (end - str) : len-1;
// Copy trimmed string and add null terminator
memcpy(out, str, out_size);
out[out_size] = 0;
return out_size;
}
これは、文字列をバッファの最初の位置にシフトするものです。文字列を動的に割り当てた場合でも、trim()が返すのと同じポインタで文字列を解放できるように、この動作が必要になる場合があります。
char *trim(char *str)
{
size_t len = 0;
char *frontp = str;
char *endp = NULL;
if( str == NULL ) { return NULL; }
if( str[0] == '\0' ) { return str; }
len = strlen(str);
endp = str + len;
/* Move the front and back pointers to address the first non-whitespace
* characters from each end.
*/
while( isspace((unsigned char) *frontp) ) { ++frontp; }
if( endp != frontp )
{
while( isspace((unsigned char) *(--endp)) && endp != frontp ) {}
}
if( frontp != str && endp == frontp )
*str = '\0';
else if( str + len - 1 != endp )
*(endp + 1) = '\0';
/* Shift the string so that it starts at str so that if it's dynamically
* allocated, we can still free it on the returned pointer. Note the reuse
* of endp to mean the front of the string buffer now.
*/
endp = str;
if( frontp != str )
{
while( *frontp ) { *endp++ = *frontp++; }
*endp = '\0';
}
return str;
}
正しさをテストします。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* Paste function from above here. */
int main()
{
/* The test prints the following:
[nothing to trim] -> [nothing to trim]
[ trim the front] -> [trim the front]
[trim the back ] -> [trim the back]
[ trim front and back ] -> [trim front and back]
[ trim one char front and back ] -> [trim one char front and back]
[ trim one char front] -> [trim one char front]
[trim one char back ] -> [trim one char back]
[ ] -> []
[ ] -> []
[a] -> [a]
[] -> []
*/
char *sample_strings[] =
{
"nothing to trim",
" trim the front",
"trim the back ",
" trim front and back ",
" trim one char front and back ",
" trim one char front",
"trim one char back ",
" ",
" ",
"a",
"",
NULL
};
char test_buffer[64];
char comparison_buffer[64];
size_t index, compare_pos;
for( index = 0; sample_strings[index] != NULL; ++index )
{
// Fill buffer with known value to verify we do not write past the end of the string.
memset( test_buffer, 0xCC, sizeof(test_buffer) );
strcpy( test_buffer, sample_strings[index] );
memcpy( comparison_buffer, test_buffer, sizeof(comparison_buffer));
printf("[%s] -> [%s]\n", sample_strings[index],
trim(test_buffer));
for( compare_pos = strlen(comparison_buffer);
compare_pos < sizeof(comparison_buffer);
++compare_pos )
{
if( test_buffer[compare_pos] != comparison_buffer[compare_pos] )
{
printf("Unexpected change to buffer @ index %u: %02x (expected %02x)\n",
compare_pos, (unsigned char) test_buffer[compare_pos], (unsigned char) comparison_buffer[compare_pos]);
}
}
}
return 0;
}
ソースファイルはtrim.cでした。「cc-Walltrim.c-otrim」でコンパイルされます。
私の解決策。文字列は変更可能でなければなりません。スペース以外の部分を最初に移動することで、後で free() する必要がある場合に備えて古いポインターを使用し続けることができるという、他のいくつかのソリューションよりも優れた利点です。
void trim(char * s) {
char * p = s;
int l = strlen(p);
while(isspace(p[l - 1])) p[--l] = 0;
while(* p && isspace(* p)) ++p, --l;
memmove(s, p, l + 1);
}
このバージョンでは、その場で編集するのではなく、strndup() を使用して文字列のコピーを作成します。strndup() には _GNU_SOURCE が必要なので、malloc() と strncpy() を使用して独自の strndup() を作成する必要があるかもしれません。
char * trim(char * s) {
int l = strlen(s);
while(isspace(s[l - 1])) --l;
while(* s && isspace(* s)) ++s, --l;
return strndup(s, l);
}
これは、左、右、両方、すべて、その場で個別にトリミングし、指定された文字のセット(またはデフォルトでは空白)をトリミングするための私のCミニライブラリです。
strlib.h の内容:
#ifndef STRLIB_H_
#define STRLIB_H_ 1
enum strtrim_mode_t {
STRLIB_MODE_ALL = 0,
STRLIB_MODE_RIGHT = 0x01,
STRLIB_MODE_LEFT = 0x02,
STRLIB_MODE_BOTH = 0x03
};
char *strcpytrim(char *d, // destination
char *s, // source
int mode,
char *delim
);
char *strtriml(char *d, char *s);
char *strtrimr(char *d, char *s);
char *strtrim(char *d, char *s);
char *strkill(char *d, char *s);
char *triml(char *s);
char *trimr(char *s);
char *trim(char *s);
char *kill(char *s);
#endif
strlib.c の内容:
#include <strlib.h>
char *strcpytrim(char *d, // destination
char *s, // source
int mode,
char *delim
) {
char *o = d; // save orig
char *e = 0; // end space ptr.
char dtab[256] = {0};
if (!s || !d) return 0;
if (!delim) delim = " \t\n\f";
while (*delim)
dtab[*delim++] = 1;
while ( (*d = *s++) != 0 ) {
if (!dtab[0xFF & (unsigned int)*d]) { // Not a match char
e = 0; // Reset end pointer
} else {
if (!e) e = d; // Found first match.
if ( mode == STRLIB_MODE_ALL || ((mode != STRLIB_MODE_RIGHT) && (d == o)) )
continue;
}
d++;
}
if (mode != STRLIB_MODE_LEFT && e) { // for everything but trim_left, delete trailing matches.
*e = 0;
}
return o;
}
// perhaps these could be inlined in strlib.h
char *strtriml(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_LEFT, 0); }
char *strtrimr(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_RIGHT, 0); }
char *strtrim(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_BOTH, 0); }
char *strkill(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_ALL, 0); }
char *triml(char *s) { return strcpytrim(s, s, STRLIB_MODE_LEFT, 0); }
char *trimr(char *s) { return strcpytrim(s, s, STRLIB_MODE_RIGHT, 0); }
char *trim(char *s) { return strcpytrim(s, s, STRLIB_MODE_BOTH, 0); }
char *kill(char *s) { return strcpytrim(s, s, STRLIB_MODE_ALL, 0); }
1 つのメインルーチンがすべてを行います。src == dstの場合はその場でトリミングし、それ以外の場合はstrcpy
ルーチンのように機能します。文字列delimで指定された一連の文字をトリムします、または null の場合は空白。左、右、両方、およびすべて (tr と同様) をトリムします。これは大したことではなく、文字列を 1 回だけ反復処理します。一部の人々は、右のトリムが左から始まることに文句を言うかもしれませんが、とにかく左から始まる strlen は必要ありません。(何らかの方法で、適切なトリムのために文字列の最後に到達する必要があるため、作業を進めた方がよい場合があります。) パイプライン処理やキャッシュ サイズなどについて議論する必要があるかもしれません。 . ソリューションは左から右に機能し、1 回だけ繰り返されるため、ストリームでも機能するように拡張できます。制限: Unicode文字列では機能しません。
これが、シンプルでありながら正しいインプレーストリム機能の試みです。
void trim(char *str)
{
int i;
int begin = 0;
int end = strlen(str) - 1;
while (isspace((unsigned char) str[begin]))
begin++;
while ((end >= begin) && isspace((unsigned char) str[end]))
end--;
// Shift all characters back to the start of the string array.
for (i = begin; i <= end; i++)
str[i - begin] = str[i];
str[i - begin] = '\0'; // Null terminate string.
}
トリムパーティーに遅刻
特徴:
1. 他の多くの回答と同様に、冒頭をすばやくトリムします。
2. 最後まで行った後、ループごとに 1 つのテストだけで右側をトリミングします。@jfm3 と同様ですが、すべて空白の文字列に対して機能します) 3.が符号付き の
場合の未定義の動作を回避するには、 にキャストします。 char
char
*s
unsigned char
文字処理 「すべての場合、引数は であり
int
、その値は として表現できるunsigned char
か、マクロの値と等しくなければなりませんEOF
。引数が他の値を持つ場合、動作は未定義です。」C11 §7.4 1
#include <ctype.h>
// Return a pointer to the trimmed string
char *string_trim_inplace(char *s) {
while (isspace((unsigned char) *s)) s++;
if (*s) {
char *p = s;
while (*p) p++;
while (isspace((unsigned char) *(--p)));
p[1] = '\0';
}
// If desired, shift the trimmed string
return s;
}
@chqrlieは、上記はトリミングされた文字列をシフトしないとコメントしました。そうするために....
// Return a pointer to the (shifted) trimmed string
char *string_trim_inplace(char *s) {
char *original = s;
size_t len = 0;
while (isspace((unsigned char) *s)) {
s++;
}
if (*s) {
char *p = s;
while (*p) p++;
while (isspace((unsigned char) *(--p)));
p[1] = '\0';
// len = (size_t) (p - s); // older errant code
len = (size_t) (p - s + 1); // Thanks to @theriver
}
return (s == original) ? s : memmove(original, s, len + 1);
}
@adam-rosenfields のインプレース変更ルーチンに似たソリューションですが、不必要に strlen() に頼ることはありません。@jkramer と同様に、文字列はバッファー内で左揃えになるため、同じポインターを解放できます。memmove を使用しないため、大きな文字列には最適ではありません。@jfm3 が言及している ++/-- 演算子が含まれています。 FCTXベースの単体テストが含まれています。
#include <ctype.h>
void trim(char * const a)
{
char *p = a, *q = a;
while (isspace(*q)) ++q;
while (*q) *p++ = *q++;
*p = '\0';
while (p > a && isspace(*--p)) *p = '\0';
}
/* See http://fctx.wildbearsoftware.com/ */
#include "fct.h"
FCT_BGN()
{
FCT_QTEST_BGN(trim)
{
{ char s[] = ""; trim(s); fct_chk_eq_str("", s); } // Trivial
{ char s[] = " "; trim(s); fct_chk_eq_str("", s); } // Trivial
{ char s[] = "\t"; trim(s); fct_chk_eq_str("", s); } // Trivial
{ char s[] = "a"; trim(s); fct_chk_eq_str("a", s); } // NOP
{ char s[] = "abc"; trim(s); fct_chk_eq_str("abc", s); } // NOP
{ char s[] = " a"; trim(s); fct_chk_eq_str("a", s); } // Leading
{ char s[] = " a c"; trim(s); fct_chk_eq_str("a c", s); } // Leading
{ char s[] = "a "; trim(s); fct_chk_eq_str("a", s); } // Trailing
{ char s[] = "a c "; trim(s); fct_chk_eq_str("a c", s); } // Trailing
{ char s[] = " a "; trim(s); fct_chk_eq_str("a", s); } // Both
{ char s[] = " a c "; trim(s); fct_chk_eq_str("a c", s); } // Both
// Villemoes pointed out an edge case that corrupted memory. Thank you.
// http://stackoverflow.com/questions/122616/#comment23332594_4505533
{
char s[] = "a "; // Buffer with whitespace before s + 2
trim(s + 2); // Trim " " containing only whitespace
fct_chk_eq_str("", s + 2); // Ensure correct result from the trim
fct_chk_eq_str("a ", s); // Ensure preceding buffer not mutated
}
// doukremt suggested I investigate this test case but
// did not indicate the specific behavior that was objectionable.
// http://stackoverflow.com/posts/comments/33571430
{
char s[] = " foobar"; // Shifted across whitespace
trim(s); // Trim
fct_chk_eq_str("foobar", s); // Leading string is correct
// Here is what the algorithm produces:
char r[16] = { 'f', 'o', 'o', 'b', 'a', 'r', '\0', ' ',
' ', 'f', 'o', 'o', 'b', 'a', 'r', '\0'};
fct_chk_eq_int(0, memcmp(s, r, sizeof(s)));
}
}
FCT_QTEST_END();
}
FCT_END();
もう 1 つ、1 行で実際の作業を行います。
#include <stdio.h>
int main()
{
const char *target = " haha ";
char buf[256];
sscanf(target, "%s", buf); // Trimming on both sides occurs here
printf("<%s>\n", buf);
}
これらの回答のほとんどは、次の1つ以上を行ったため、気に入らなかった...
- 元のポインターの文字列内に別のポインターが返されました (同じものへの 2 つの異なるポインターをジャグリングするのはちょっと面倒です)。
- 文字列全体を事前反復するstrlen()のようなものを無償で使用しました。
- 移植性のない OS 固有の lib 関数を使用しました。
- バックスキャン。
- TAB / CR / LF が保持されるように、 isspace()の代わりに' 'との比較を使用しました。
- 大きな静的バッファによるメモリの浪費。
- sscanf/sprintfなどの高コスト関数による無駄なサイクル。
これが私のバージョンです:
void fnStrTrimInPlace(char *szWrite) {
const char *szWriteOrig = szWrite;
char *szLastSpace = szWrite, *szRead = szWrite;
int bNotSpace;
// SHIFT STRING, STARTING AT FIRST NON-SPACE CHAR, LEFTMOST
while( *szRead != '\0' ) {
bNotSpace = !isspace((unsigned char)(*szRead));
if( (szWrite != szWriteOrig) || bNotSpace ) {
*szWrite = *szRead;
szWrite++;
// TRACK POINTER TO LAST NON-SPACE
if( bNotSpace )
szLastSpace = szWrite;
}
szRead++;
}
// TERMINATE AFTER LAST NON-SPACE (OR BEGINNING IF THERE WAS NO NON-SPACE)
*szLastSpace = '\0';
}
あなたが何を「無痛」と考えているのか私にはわかりません。
C弦はかなり痛いです。最初の非空白文字の位置を自明に見つけることができます。
while (isspace(* p)) p++;
次の 2 つの同様の些細な動きで、最後の非空白文字の位置を見つけることができます。
while (* q) q++; { q--; を行います。} while (isspace(* q));
( *
and++
演算子を同時に使用する手間を省きました。)
問題は、これをどうするかです。String
手元にあるデータ型は、簡単に考えることができる堅牢で大きな抽象化ではありませんが、ストレージ バイトの配列にすぎません。堅牢なデータ型がないため、PHperytonby のchomp
関数と同じことを行う関数を作成することは不可能です。C のそのような関数は何を返しますか?
たとえば、文字列ライブラリを使用します。
Ustr *s1 = USTR1(\7, " 12345 ");
ustr_sc_trim_cstr(&s1, " ");
assert(ustr_cmp_cstr_eq(s1, "12345"));
...あなたが言うように、これは「一般的な」問題です。はい、#include などを含める必要があります。これは libc には含まれていませんが、ランダム ポインターと size_t を格納する独自のハック ジョブを発明しないでください。バッファオーバーフロー。
を使用している場合は、 g_strstripglib
を使用できます
ゲームには少し遅れましたが、ルーチンを争いに投入します。それらはおそらく最も絶対的に効率的ではありませんが、私はそれらが正しく、単純であると信じています (rtrim()
複雑さの限界を押し上げています):
#include <ctype.h>
#include <string.h>
/*
Public domain implementations of in-place string trim functions
Michael Burr
michael.burr@nth-element.com
2010
*/
char* ltrim(char* s)
{
char* newstart = s;
while (isspace( *newstart)) {
++newstart;
}
// newstart points to first non-whitespace char (which might be '\0')
memmove( s, newstart, strlen( newstart) + 1); // don't forget to move the '\0' terminator
return s;
}
char* rtrim( char* s)
{
char* end = s + strlen( s);
// find the last non-whitespace character
while ((end != s) && isspace( *(end-1))) {
--end;
}
// at this point either (end == s) and s is either empty or all whitespace
// so it needs to be made empty, or
// end points just past the last non-whitespace character (it might point
// at the '\0' terminator, in which case there's no problem writing
// another there).
*end = '\0';
return s;
}
char* trim( char* s)
{
return rtrim( ltrim( s));
}
この成長を維持するために、変更可能な文字列を使用したもう 1 つのオプションがあります。
void trimString(char *string)
{
size_t i = 0, j = strlen(string);
while (j > 0 && isspace((unsigned char)string[j - 1])) string[--j] = '\0';
while (isspace((unsigned char)string[i])) i++;
if (i > 0) memmove(string, string + i, j - i + 1);
}
#include <ctype.h>
#include <string.h>
char *trim_space(char *in)
{
char *out = NULL;
int len;
if (in) {
len = strlen(in);
while(len && isspace(in[len - 1])) --len;
while(len && *in && isspace(*in)) ++in, --len;
if (len) {
out = strndup(in, len);
}
}
return out;
}
isspace
すべての空白を削除するのに役立ちます。
- 最初のループを実行して最後のバイトから空白文字をチェックし、長さ変数を減らします
- 2 番目のループを実行して最初のバイトから空白文字をチェックし、長さ変数を減らして char ポインターをインクリメントします。
- 最後に、長さ変数が 0 より大きい場合は、
strndup
スペースを除外して新しい文字列バッファーを作成するために使用します。
これまでに投稿されたコードは最適ではないように思われるため、コードのみを含めています(そして、コメントする担当者がまだいません)。
void inplace_trim(char* s)
{
int start, end = strlen(s);
for (start = 0; isspace(s[start]); ++start) {}
if (s[start]) {
while (end > 0 && isspace(s[end-1]))
--end;
memmove(s, &s[start], end - start);
}
s[end - start] = '\0';
}
char* copy_trim(const char* s)
{
int start, end;
for (start = 0; isspace(s[start]); ++start) {}
for (end = strlen(s); end > 0 && isspace(s[end-1]); --end) {}
return strndup(s + start, end - start);
}
strndup()
GNU拡張です。あなたがそれまたは同等のものを持っていない場合は、あなた自身を転がしてください。例えば:
r = strdup(s + start);
r[end-start] = '\0';
個人的には、自分で転がします。strtokを使用することはできますが、(特に先頭の文字を削除する場合は)どのメモリが何であるかがわかるように注意する必要があります。
末尾のスペースを取り除くのは簡単で、かなり安全です。最後のスペースの上に0を入れて、最後から数えていくことができるからです。主要なスペースを取り除くことは、物事を動かすことを意味します。(おそらく賢明な)その場でそれを行いたい場合は、先頭のスペースがなくなるまで、すべてを1文字戻し続けることができます。または、より効率的にするために、最初の非スペース文字のインデックスを見つけて、すべてをその番号だけ戻すことができます。または、最初の非スペース文字へのポインターを使用することもできます(ただし、strtokの場合と同じように注意する必要があります)。
#include "stdafx.h"
#include "malloc.h"
#include "string.h"
int main(int argc, char* argv[])
{
char *ptr = (char*)malloc(sizeof(char)*30);
strcpy(ptr," Hel lo wo rl d G eo rocks!!! by shahil sucks b i g tim e");
int i = 0, j = 0;
while(ptr[j]!='\0')
{
if(ptr[j] == ' ' )
{
j++;
ptr[i] = ptr[j];
}
else
{
i++;
j++;
ptr[i] = ptr[j];
}
}
printf("\noutput-%s\n",ptr);
return 0;
}
これらの関数は元のバッファーを変更するため、動的に割り当てられた場合、元のポインターを解放できます。
#include <string.h>
void rstrip(char *string)
{
int l;
if (!string)
return;
l = strlen(string) - 1;
while (isspace(string[l]) && l >= 0)
string[l--] = 0;
}
void lstrip(char *string)
{
int i, l;
if (!string)
return;
l = strlen(string);
while (isspace(string[(i = 0)]))
while(i++ < l)
string[i-1] = string[i];
}
void strip(char *string)
{
lstrip(string);
rstrip(string);
}
これまでの回答のほとんどは、次のいずれかを行います。
- 文字列の最後でバックトラックする (つまり、文字列の最後を見つけてから、スペース以外の文字が見つかるまで逆方向にシークする)
- 最初に呼び出し
strlen()
、文字列全体を 2 番目に通過させます。
このバージョンは 1 つのパスのみを作成し、バックトラックしません。したがって、数百の末尾のスペースが一般的である場合に限りますが (SQL クエリの出力を処理する場合は珍しいことではありません)、他の方法よりもパフォーマンスが向上する可能性があります。
static char const WHITESPACE[] = " \t\n\r";
static void get_trim_bounds(char const *s,
char const **firstWord,
char const **trailingSpace)
{
char const *lastWord;
*firstWord = lastWord = s + strspn(s, WHITESPACE);
do
{
*trailingSpace = lastWord + strcspn(lastWord, WHITESPACE);
lastWord = *trailingSpace + strspn(*trailingSpace, WHITESPACE);
}
while (*lastWord != '\0');
}
char *copy_trim(char const *s)
{
char const *firstWord, *trailingSpace;
char *result;
size_t newLength;
get_trim_bounds(s, &firstWord, &trailingSpace);
newLength = trailingSpace - firstWord;
result = malloc(newLength + 1);
memcpy(result, firstWord, newLength);
result[newLength] = '\0';
return result;
}
void inplace_trim(char *s)
{
char const *firstWord, *trailingSpace;
size_t newLength;
get_trim_bounds(s, &firstWord, &trailingSpace);
newLength = trailingSpace - firstWord;
memmove(s, firstWord, newLength);
s[newLength] = '\0';
}
これは私が考えることができる最短の実装です:
static const char *WhiteSpace=" \n\r\t";
char* trim(char *t)
{
char *e=t+(t!=NULL?strlen(t):0); // *e initially points to end of string
if (t==NULL) return;
do --e; while (strchr(WhiteSpace, *e) && e>=t); // Find last char that is not \r\n\t
*(++e)=0; // Null-terminate
e=t+strspn (t,WhiteSpace); // Find first char that is not \t
return e>t?memmove(t,e,strlen(e)+1):t; // memmove string contents and terminator
}
ヘッダー Shlwapi.h で定義されている StrTrim 関数の使用についてどう思いますか? 自分で定義するのではなく、簡単です。
詳細については、http:
//msdn.microsoft.com/en-us/library/windows/desktop/bb773454 (v=vs.85).aspx を参照してください。
あなたが持っている場合、
char ausCaptain[]="GeorgeBailey ";
StrTrim(ausCaptain," ");
これはそうでausCaptain
は"GeorgeBailey"
ありません"GeorgeBailey "
。
void trim(char* const str)
{
char* begin = str;
char* end = str;
while (isspace(*begin))
{
++begin;
}
char* s = begin;
while (*s != '\0')
{
if (!isspace(*s++))
{
end = s;
}
}
*end = '\0';
const int dist = end - begin;
if (begin > str && dist > 0)
{
memmove(str, begin, dist + 1);
}
}
文字列をその場で変更するため、引き続き削除できます。
ファンシー パンツ ライブラリ関数を使用しません (memmove ファンシーと考えない限り)。
文字列のオーバーラップを処理します。
前後をトリミングします(真ん中ではありません、申し訳ありません)。
文字列が大きい場合は高速です (memmove はアセンブリで記述されることが多い)。
必要な場合にのみ文字を移動します (文字列には先頭のスペースがほとんどなく、多くの場合、末尾のスペースがないため、ほとんどのユースケースでこれが当てはまります)
これをテストしたいのですが、遅れています。バグを見つけて楽しんでください... :-)
ここにあなたが望むことをする関数があります。文字列がすべて空白である縮退したケースを処理する必要があります。出力バッファーとバッファーの長さを渡す必要があります。つまり、割り当てたバッファーを渡す必要があります。
void str_trim(char *output, const char *text, int32 max_len)
{
int32 i, j, length;
length = strlen(text);
if (max_len < 0) {
max_len = length + 1;
}
for (i=0; i<length; i++) {
if ( (text[i] != ' ') && (text[i] != '\t') && (text[i] != '\n') && (text[i] != '\r')) {
break;
}
}
if (i == length) {
// handle lines that are all whitespace
output[0] = 0;
return;
}
for (j=length-1; j>=0; j--) {
if ( (text[j] != ' ') && (text[j] != '\t') && (text[j] != '\n') && (text[j] != '\r')) {
break;
}
}
length = j + 1 - i;
strncpy(output, text + i, length);
output[length] = 0;
}
ループ内の if ステートメントは、おそらくisspace(text[i])またはisspace(text[j])に置き換えて、行を少し読みやすくすることができます。テストしたくない文字がいくつかあったため、このように設定したと思いますが、今ではすべての空白をカバーしているようです:-)
Linuxカーネルコードの質問に関して私が開示したことは次のとおりです。
/**
* skip_spaces - Removes leading whitespace from @s.
* @s: The string to be stripped.
*
* Returns a pointer to the first non-whitespace character in @s.
*/
char *skip_spaces(const char *str)
{
while (isspace(*str))
++str;
return (char *)str;
}
/**
* strim - Removes leading and trailing whitespace from @s.
* @s: The string to be stripped.
*
* Note that the first trailing whitespace is replaced with a %NUL-terminator
* in the given string @s. Returns a pointer to the first non-whitespace
* character in @s.
*/
char *strim(char *s)
{
size_t size;
char *end;
size = strlen(s);
if (!size)
return s;
end = s + size - 1;
while (end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
return skip_spaces(s);
}
起源のためにバグがないはずです;-)
私のワンピースはKISSの原則に近いと思います:
/**
* trim spaces
**/
char * trim_inplace(char * s, int len)
{
// trim leading
while (len && isspace(s[0]))
{
s++; len--;
}
// trim trailing
while (len && isspace(s[len - 1]))
{
s[len - 1] = 0; len--;
}
return s;
}
C++ STL スタイル
std::string Trimed(const std::string& s)
{
std::string::const_iterator begin = std::find_if(s.begin(),
s.end(),
[](char ch) { return !std::isspace(ch); });
std::string::const_iterator end = std::find_if(s.rbegin(),
s.rend(),
[](char ch) { return !std::isspace(ch); }).base();
return std::string(begin, end);
}
void trim(char* string) {
int lenght = strlen(string);
int i=0;
while(string[0] ==' ') {
for(i=0; i<lenght; i++) {
string[i] = string[i+1];
}
lenght--;
}
for(i=lenght-1; i>0; i--) {
if(string[i] == ' ') {
string[i] = '\0';
} else {
break;
}
}
}
#include<stdio.h>
#include<ctype.h>
main()
{
char sent[10]={' ',' ',' ','s','t','a','r','s',' ',' '};
int i,j=0;
char rec[10];
for(i=0;i<=10;i++)
{
if(!isspace(sent[i]))
{
rec[j]=sent[i];
j++;
}
}
printf("\n%s\n",rec);
}