2009-03-18 13 views
20

skrócie:Przycinanie ciąg w C

Jestem po równowartości .NET na String.Trim w C przy użyciu win32 i standardowy C api (kompilacja z MSVC2008 więc mam dostęp do wszystkich rzeczy C++ jeśli potrzebne, ale Po prostu próbuję przyciąć char*).

Biorąc pod uwagę, że istnieje strchr, strtok, i wszelkiego rodzaju innych funkcji łańcuchowych, na pewno nie powinno być wykończenia funkcja, lub taki, który może być dostosowana ...

Dzięki

Odpowiedz

21

Nie ma funkcji standardowej biblioteki, aby to zrobić, ale nie jest to zbyt trudne do samodzielnego wykonania. Jest existing question na SO o tym, że otrzymał odpowiedź z kodem źródłowym.

+3

Dzięki za to. Uważam, że jest opóźnione, że nie ma funkcji bibliotecznej (jeśli wszyscy wykonują swoje własne zadania, wszyscy będą źle zarządzać unicode itp. Na różne sposoby), ale myślę, że to jest to, co jest ... –

+0

Obsługa ciągów C jest niezręczna, bardziej z Unicode. C++ łata go za pomocą std :: string, ale tworzenie ciągów naturalnych wymaga przeprojektowania. C, pomimo wszystkich swoich zalet, wcale nie jest idealnym językiem. –

+1

Heh. C został wynaleziony w '72. Unicode nie pojawił się aż do lat 90. Przez większość historii C nie było nic oprócz ASCII i str [x] = '\ 0'; zrobiłoby to dobrze. –

10

można użyć standardowa funkcja isspace() w ctype.h, aby to osiągnąć. Po prostu porównaj początkowe i końcowe znaki twojej tablicy znaków, aż oba końce przestaną mieć spacje.

"przestrzeni" obejmują:

'' (0x20) przestrzeni (SPC)

'\ T' (0x09) zakładka poziomego (TAB)

'\ n (0x0A) linia (LF)

'\ V' (0x0B) w oknie pionowym (VT)

'\ f' (0x0C) paszy (FF)

„\ r” (0x0d) powrotu karetki (CR)

chociaż nie jest funkcją, która zrobi całą pracę za ciebie, będziesz musiał toczyć własne rozwiązanie porównać z każdej strony daną tablicę znaków, dopóki nie pozostaną spacje.

Edit:

Skoro masz dostęp do C++, doładowania ma a trim implementation czeka na twoje życie o wiele łatwiejsze.

+0

nie widzę, co jest złego w tym, ale ok, mam wielkie ramiona i dużo reputacji spare :) –

+0

Nie wierzę, że coś jest z tym nie tak. Więc +1 :) – Stephan202

-6

Najprostszą rzeczą do zrobienia jest prosta pętla. Zakładam, że chcesz, aby przycięty sznurek wrócił na miejsce.

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 */ 
} 

Pozbywa się również pustych przestrzeni, jeśli String.Trim nie potrzebuje wtedy więcej logiki.

+0

Trudno "modyfikować na miejscu", jeśli zdeformujesz nowy bufor, a następnie ponownie go skopiujesz! –

+0

został zmodyfikowany w miejscu interfejsu. –

+0

tak, powodzenia w sprzedaży tego w następnej rozmowie :) –

4

Zaskoczony, aby zobaczyć takie wdrożenia. Zwykle trymuję tak:

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; 
} 

Jest szybki i niezawodny - służy mi wiele lat.

+2

Och, myślę, że to może spowodować opróżnienie bufora, rozważ to: char buffer [] = ""; wykończenie (bufor); Potem przynajmniej czytasz bufor [-1], a jeśli jest to losowo biała spacja, możesz nawet zapisać stronę swojego bufora. – quinmars

+0

Niezły! Dodałem dodatkową kontrolę. Sprawdzi także mój kod produkcyjny :) – qrdl

12

To sprawiło, że chciałem napisać własne - nie podobały mi się te, które zostały dostarczone. Wydaje mi się, że powinny być 3 funkcje.

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

wypróbowałem inne implementacje wymienione w tym wątku .. działało dobrze przez jakiś czas, aż nagle dostałem błąd w seg ... spędziłem dużo czasu próbując debugować i odkryłem, że to został pośrednio spowodowany przez kod przycinania ... wypróbowałem twoją wersję, a usterki seg zniknęły :) Dzięki! (chociaż nadal nie rozumiem, dlaczego wystąpiły błędy seg) – Sadhir

+1

edytuj: osoba przeglądająca mój kod sugeruje, że sprawdzam NULL wartości wejściowe .. może to jest coś, co możesz chcieć dodać – Sadhir

+0

'ltrim' zwraca wskaźnik, który nie jest odpowiedni za przejście do "wolnego". Jeśli go używasz (lub, oczywiście, "przycinanie"), upewnij się, że trzymasz się oryginalnego wskaźnika - w szczególności nie próbuj czegoś takiego jak 's = trim (s);' bez wcześniejszego zapisania 's' gdzie indziej. – 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. To jest wstrętne. Wygląda na to, że usunie również wewnętrzne przestrzenie? "foo bar" powinien przycinać do "foo bar", a nie "foobar". –

+0

Nawet jeśli operator również poprosił o przycięcie w środku, ten kod jest bardzo zbędny. Okropny! – pqsk

0

Jak o tym ...Wymaga tylko jednej iteracji na ciągu znaków (nie używa strlen, który iteruje po ciągu znaków). Gdy funkcja zwraca, otrzymasz wskaźnik do początku przyciętego łańcucha, który jest zakończony znakiem NUL. Ciąg jest przycinany spacji od lewej (aż do znalezienia pierwszego znaku). Ciąg jest również przycinany ze wszystkich końcowych spacji po ostatnim znaku spacji.

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

Modyfikuje to ciąg znaków wejściowych. Chociaż wydaje się, że wydajność byłaby świetna, nie użyłbym tego, chyba że absolutnie musiałbym, ponieważ modyfikowanie łańcucha w miejscu może być nieoczekiwane, ponieważ zwraca wskaźnik początkowy w środku istniejącego łańcucha. Dzwoniący powinien wiedzieć, aby nie usuwać oryginalnego ciągu, dopóki "przycięty" nie będzie już potrzebny –

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)); 
} 

wyjściowa:

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

Lubię, gdy wartość zwracana zawsze równa argument. W ten sposób, jeśli tablica znaków została przydzielona z malloc(), może znów być 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

Oto moja realizacja, zachowuje się jak wbudowanych funkcji łańcuchowych w libc (to znaczy, że spodziewa się, że c-strunowy, modyfikuje go i zwraca go do rozmówcy).

Przycina główne przestrzenie & przesuwa pozostałe znaki w lewo, gdy analizuje ciąg od lewej do prawej. Następnie zaznacza nowy koniec łańcucha i rozpoczyna parsowanie go w tył, zastępując spacje końcowe znakami '\ 0, dopóki nie znajdzie znaku spacji lub początku ciągu znaków. Uważam, że są to minimalne możliwe iteracje dla tego konkretnego zadania.

// ---------------------------------------------------------------------------- 
// 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

Nie jest to najlepszy sposób, ale działa

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; 
}