2009-03-18 57 views
20

ngắn gọn:Trim một chuỗi trong C

tôi sau tương đương với NET của String.Trim trong C bằng cách sử dụng win32 và C api chuẩn (biên soạn với MSVC2008 vì vậy tôi có quyền truy cập vào tất cả các công cụ C++, nếu cần thiết, nhưng Tôi chỉ đang cố gắng cắt một char*).

Cho rằng có strchr, strtok, và tất cả các cách thức của chức năng chuỗi khác, chắc chắn cần phải có một chức năng cắt, hoặc một trong đó có thể được thêm thắt ...

Cảm ơn

Trả lời

21

Không có chức năng thư viện chuẩn để thực hiện việc này, nhưng không quá khó để cuộn của riêng bạn. Có một số existing question trên SO về việc thực hiện điều này đã được trả lời bằng mã nguồn.

+3

Cảm ơn vì điều đó. Tôi tìm thấy nó chậm phát triển rằng không có chức năng thư viện (nếu tất cả mọi người cuộn riêng của họ sau đó họ đang tất cả sẽ mishandle unicode, vv theo nhiều cách khác nhau), nhưng tôi đoán nó là những gì nó là ... –

+0

Xử lý chuỗi C là khó xử, nhiều hơn thế với Unicode. C++ vá nó với chuỗi std :: nhưng việc tạo chuỗi tự nhiên yêu cầu thiết kế lại. C, mặc dù tất cả các nhân đức của nó, là xa là một ngôn ngữ hoàn hảo. –

+1

Heh. C được phát minh năm '72. Unicode đã không đi kèm cho đến những năm 90. Đối với hầu hết lịch sử của C không có gì ngoài ASCII, và str [x] = '\ 0'; sẽ làm tốt công việc. –

10

Bạn có thể sử dụng tiêu chuẩn isspace() chức năng trong ctype.h để đạt được điều này. Chỉ cần so sánh các ký tự đầu và cuối của mảng ký tự của bạn cho đến khi cả hai đầu không còn dấu cách.

"không gian" bao gồm:

'' (0x20) không gian (SPC)

'\ t' (0x09) tab ngang (TAB)

'\ n' (0x0a) xuống dòng (LF)

'\ v' (0x0b) tab dọc (VT)

'\ f' (0x0c) ăn (FF)

'\ r' (0x0d) vận chuyển trở lại (CR)

mặc dù không có chức năng mà sẽ làm tất cả các công việc cho bạn, bạn sẽ phải cuộn giải pháp của riêng bạn để so sánh mỗi bên của cho mảng ký tự liên tục cho đến khi không còn khoảng trắng.

Edit:

Vì bạn có quyền truy cập vào C++, Boost có a trim implementation chờ đợi cho bạn để làm cho cuộc sống của bạn dễ dàng hơn nhiều.

+0

Tôi không thấy có gì sai với điều này nhưng ok, tôi đã có vai lớn và rất nhiều danh tiếng để rảnh rỗi :) –

+0

Tôi không tin rằng có bất cứ điều gì sai trái với điều này. Vì vậy, +1 :) – Stephan202

-6

Điều dễ nhất cần làm là một vòng lặp đơn giản. Tôi sẽ giả định rằng bạn muốn xâu chuỗi được trả lại tại chỗ.

char * 
strTrim(char * s){ 
    int ix, jx; 
    int len ; 
    char * buf 
    len = strlen(s); /* possibly should use strnlen */ 
    buf = (char *) malloc(strlen(s)+1); 

    for(ix=0, jx=0; ix < len; ix++){ 
     if(!isspace(s[ix])) 
      buf[jx++] = s[ix]; 

    buf[jx] = '\0'; 
    strncpy(s, buf, jx); /* always looks as far as the null, but who cares? */ 
    free(buf);   /* no good leak goes unpunished */ 
    return s;    /* modifies s in place *and* returns it for swank */ 
} 

Điều này cũng loại bỏ khoảng trống được nhúng, nếu String.Trim không cần logic nhiều hơn một chút.

+0

Nó hầu như không "sửa đổi tại chỗ" nếu bạn malloc một bộ đệm mới và sau đó sao chép nó trở lại! –

+0

nó được sửa đổi tại chỗ như xa như giao diện có liên quan. –

+0

vâng, chúc may mắn bán cái đó trong cuộc phỏng vấn tiếp theo của bạn :) –

4

Ngạc nhiên khi thấy những triển khai như vậy. Tôi thường cắt như sau:

char *trim(char *s) { 
    char *ptr; 
    if (!s) 
     return NULL; // handle NULL string 
    if (!*s) 
     return s;  // handle empty string 
    for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr); 
    ptr[1] = '\0'; 
    return s; 
} 

Nó rất nhanh và đáng tin cậy - phục vụ tôi nhiều năm.

+2

Oh, tôi nghĩ rằng có thể gây ra một bộ đệm underrun, xem xét điều này: char buffer [] = ""; trim (buffer); Sau đó, bạn ít nhất là đọc bộ đệm [-1], và nếu nó là ngẫu nhiên một không gian màu trắng, bạn thậm chí sẽ viết ra bên của bộ đệm của bạn. – quinmars

+0

Đẹp nhất! Tôi đã thêm kiểm tra thêm cho điều này. Sẽ kiểm tra mã sản xuất của tôi cũng :) – qrdl

12

Điều này khiến tôi muốn viết của riêng mình - Tôi không thích những cái đã được cung cấp. Dường như với tôi nên có 3 chức năng.

char *ltrim(char *s) 
{ 
    while(isspace(*s)) s++; 
    return s; 
} 

char *rtrim(char *s) 
{ 
    char* back = s + strlen(s); 
    while(isspace(*--back)); 
    *(back+1) = '\0'; 
    return s; 
} 

char *trim(char *s) 
{ 
    return rtrim(ltrim(s)); 
} 
+0

tôi đã thử các triển khai khác được đề cập trong thread này .. nó làm việc tốt trong một thời gian cho đến khi tôi đột nhiên có một lỗi seg .. tôi đã dành rất nhiều thời gian cố gắng để gỡ lỗi và phát hiện ra rằng nó đã gián tiếp gây ra bởi các mã trang trí ... tôi đã thử phiên bản của bạn và lỗi seg biến mất :) Cảm ơn! (mặc dù tôi vẫn không hiểu tại sao các lỗi seg xảy ra) – Sadhir

+1

chỉnh sửa: người xem xét mã của tôi đề nghị tôi kiểm tra giá trị đầu vào NULL .. có thể đó là cái gì bạn có thể muốn thêm – Sadhir

+0

'ltrim' trả về một con trỏ không phù hợp để chuyển sang 'miễn phí'. Nếu bạn sử dụng nó (hoặc, tất nhiên, 'trim'), hãy chắc chắn rằng bạn giữ con trỏ ban đầu - đặc biệt là không thử một cái gì đó như' s = trim (s); 'mà không có' s' được lưu trữ ở nơi khác đầu tiên. – cHao

-4
void inPlaceStrTrim(char* str) { 
    int k = 0; 
    int i = 0; 
    for (i=0; str[i] != '\0';) { 
     if (isspace(str[i])) { 
      // we have got a space... 
      k = i; 
      for (int j=i; j<strlen(str)-1; j++) { 
       str[j] = str[j+1]; 
      } 
      str[strlen(str)-1] = '\0'; 
      i = k; // start the loop again where we ended.. 
     } else { 
      i++; 
     } 
    } 
} 
+0

Ouch. Thật khó chịu. Có vẻ như nó cũng sẽ loại bỏ không gian bên trong? "foo bar" nên cắt thành "foo bar", không phải "foobar" –

+0

Thậm chí nếu op được yêu cầu cắt bên trong, mã này rất thừa. Kinh khủng! – pqsk

0

Làm thế nào về vấn đề này ...Nó chỉ yêu cầu một lần lặp qua chuỗi (không sử dụng strlen, mà lặp qua chuỗi). Khi hàm trả về bạn nhận được một con trỏ tới đầu của chuỗi được cắt xén mà không được kết thúc. Chuỗi được cắt không gian từ bên trái (cho đến khi tìm thấy ký tự đầu tiên). Chuỗi cũng được cắt xén của tất cả dấu cách sau ký tự không gian cuối cùng.

char* trim(char* input) { 
    char* start = input; 
    while (isSpace(*start)) { //trim left 
     start++; 
    } 

    char* ptr = start; 
    char* end = start; 
    while (*ptr++ != '\0') { //trim right 
     if (!isSpace(*ptr)) { //only move end pointer if char isn't a space 
      end = ptr; 
     } 
    } 

    *end = '\0'; //terminate the trimmed string with a null 
    return start; 
} 

bool isSpace(char c) { 
    switch (c) { 
     case ' ': 
     case '\n': 
     case '\t': 
     case '\f': 
     case '\r': 
      return true; 
      break; 
     default: 
      return false; 
      break; 
    } 
} 
+0

Điều này sửa đổi chuỗi đầu vào tại chỗ. Trong khi nó có vẻ như hiệu suất sẽ là tuyệt vời, tôi sẽ không sử dụng này trừ khi tôi hoàn toàn phải, như sửa đổi chuỗi tại chỗ có thể là bất ngờ, như sẽ trở lại một con trỏ bắt đầu vào giữa chuỗi hiện có. Người gọi sẽ phải biết không xóa chuỗi gốc cho đến khi chuỗi "được cắt" không còn cần thiết nữa –

0
/* iMode 0:ALL, 1:Left, 2:Right*/ 
char* Trim(char* szStr,const char ch, int iMode) 
{ 
    if (szStr == NULL) 
     return NULL; 
    char szTmp[1024*10] = { 0x00 }; 
    strcpy(szTmp, szStr); 
    int iLen = strlen(szTmp); 
    char* pStart = szTmp; 
    char* pEnd = szTmp+iLen; 
    int i; 
    for(i = 0;i < iLen;i++){ 
     if (szTmp[i] == ch && pStart == szTmp+i && iMode != 2) 
      ++pStart; 
     if (szTmp[iLen-i-1] == ch && pEnd == szTmp+iLen-i && iMode != 1) 
      *(--pEnd) = '\0'; 
    } 
    strcpy(szStr, pStart); 
    return szStr; 
} 
1
#include "stdafx.h" 
#include <string.h> 
#include <ctype.h> 

char* trim(char* input); 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    char sz1[]=" MQRFH "; 
    char sz2[]=" MQRFH"; 
    char sz3[]=" MQR FH"; 
    char sz4[]="MQRFH "; 
    char sz5[]="MQRFH"; 
    char sz6[]="M"; 
    char sz7[]="M "; 
    char sz8[]=" M"; 
    char sz9[]=""; 
    char sz10[]="  "; 

    printf("sz1:[%s] %d\n",trim(sz1), strlen(sz1)); 
    printf("sz2:[%s] %d\n",trim(sz2), strlen(sz2)); 
    printf("sz3:[%s] %d\n",trim(sz3), strlen(sz3)); 
    printf("sz4:[%s] %d\n",trim(sz4), strlen(sz4)); 
    printf("sz5:[%s] %d\n",trim(sz5), strlen(sz5)); 
    printf("sz6:[%s] %d\n",trim(sz6), strlen(sz6)); 
    printf("sz7:[%s] %d\n",trim(sz7), strlen(sz7)); 
    printf("sz8:[%s] %d\n",trim(sz8), strlen(sz8)); 
    printf("sz9:[%s] %d\n",trim(sz9), strlen(sz9)); 
    printf("sz10:[%s] %d\n",trim(sz10), strlen(sz10)); 

    return 0; 
} 

char *ltrim(char *s) 
{  
    while(isspace(*s)) s++;  
    return s; 
} 

char *rtrim(char *s) 
{  
    char* back; 
    int len = strlen(s); 

    if(len == 0) 
     return(s); 

    back = s + len;  
    while(isspace(*--back));  
    *(back+1) = '\0';  
    return s; 
} 

char *trim(char *s) 
{  
    return rtrim(ltrim(s)); 
} 

Output:

sz1:[MQRFH] 9 
sz2:[MQRFH] 6 
sz3:[MQR FH] 8 
sz4:[MQRFH] 7 
sz5:[MQRFH] 5 
sz6:[M] 1 
sz7:[M] 2 
sz8:[M] 2 
sz9:[] 0 
sz10:[] 8 
1
static inline void ut_trim(char * str) { 
    char * start = str; 
    char * end = start + strlen(str); 

    while (--end >= start) { /* trim right */ 
     if (!isspace(*end)) 
     break; 
    } 
    *(++end) = '\0'; 

    while (isspace(*start)) /* trim left */ 
     start++; 

    if (start != str)   /* there is a string */ 
     memmove(str, start, end - start + 1); 
} 
1

tôi thích nó khi giá trị trả về luôn bằng với đối số. Bằng cách này, nếu mảng chuỗi đã được phân bổ với malloc(), nó có thể an toàn lại là free().

/* Remove leading whitespaces */ 
char *ltrim(char *const s) 
{ 
     size_t len; 
     char *cur; 

     if(s && *s) { 
       len = strlen(s); 
       cur = s; 

       while(*cur && isspace(*cur)) 
         ++cur, --len; 

       if(s != cur) 
         memmove(s, cur, len + 1); 

     } 

     return s; 
} 

/* Remove trailing whitespaces */ 
char *rtrim(char *const s) 
{ 
     size_t len; 
     char *cur; 

     if(s && *s) { 
       len = strlen(s); 
       cur = s + len - 1; 

       while(cur != s && isspace(*cur)) 
         --cur, --len; 

       cur[isspace(*cur) ? 0 : 1] = '\0'; 
     } 

     return s; 
} 

/* Remove leading and trailing whitespaces */ 
char *trim(char *const s) 
{ 
     rtrim(s); // order matters 
     ltrim(s); 

     return s; 
} 
0

Dưới đây là thực hiện của tôi, hành xử như các chức năng chuỗi tích hợp sẵn trong libc (có nghĩa là, nó hy vọng một c-string, nó sẽ thay đổi nó và trả nó cho người gọi).

Nó cắt không gian hàng đầu & thay đổi các ký tự còn lại ở bên trái, vì nó phân tích chuỗi từ trái sang phải. Sau đó nó đánh dấu một đầu mới của chuỗi và bắt đầu phân tích cú pháp ngược lại, thay thế dấu cách bằng dấu '\ 0' cho đến khi nó tìm thấy ký tự không gian hoặc bắt đầu chuỗi. Tôi tin rằng đó là những lần lặp tối thiểu có thể cho công việc cụ thể này.

// ---------------------------------------------------------------------------- 
// trim leading & trailing spaces from string s (return modified string s) 
// alg: 
// - skip leading spaces, via cp1 
// - shift remaining *cp1's to the left, via cp2 
// - mark a new end of string 
// - replace trailing spaces with '\0', via cp2 
// - return the trimmed s 
// 
char *s_trim(char *s) 
{ 
    char *cp1;        // for parsing the whole s 
    char *cp2;        // for shifting & padding 

    // skip leading spaces, shift remaining chars 
    for (cp1=s; isspace(*cp1); cp1++)  // skip leading spaces, via cp1 
     ; 
    for (cp2=s; *cp1; cp1++, cp2++)   // shift left remaining chars, via cp2 
     *cp2 = *cp1; 
    *cp2-- = 0;        // mark new end of string for s 

    // replace trailing spaces with '\0' 
    while (cp2 > s && isspace(*cp2)) 
     *cp2-- = 0;       // pad with '\0's 

    return s; 
} 
3
/* Function to remove white spaces on both sides of a string i.e trim */ 

void trim (char *s) 
{ 
    int i; 

    while (isspace (*s)) s++; // skip left side white spaces 
    for (i = strlen (s) - 1; (isspace (s[i])); i--) ; // skip right side white spaces 
    s[i + 1] = '\0'; 
    printf ("%s\n", s); 
} 
1
void ltrim(char str[PATH_MAX]) 
{ 
     int i = 0, j = 0; 
     char buf[PATH_MAX]; 
     strcpy(buf, str); 
     for(;str[i] == ' ';i++); 

     for(;str[i] != '\0';i++,j++) 
       buf[j] = str[i]; 
     buf[j] = '\0'; 
     strcpy(str, buf); 
} 
0

Không phải là cách tốt nhất nhưng nó hoạt động

char* Trim(char* str) 
{ 
    int len = strlen(str); 
    char* buff = new char[len]; 
    int i = 0; 
    memset(buff,0,len*sizeof(char)); 
    do{ 
     if(isspace(*str)) continue; 
     buff[i] = *str; ++i; 
    } while(*(++str) != '\0'); 
    return buff; 
} 
Các vấn đề liên quan