C中的修剪功能

时间:2019-07-30 06:52:38

标签: c

我正在用C语言编写自己的trim()。有一个包含所有字符串值的结构,该结构是从来自文件的数据中填充的,该文件包含单词开头和前后的空格。

char *trim(char *string)
{
    int stPos,endPos;
    int len=strlen(string);
    for(stPos=0;stPos<len && string[stPos]==' ';++stPos);
    for(endPos=len-1;endPos>=0 && string[endPos]==' ';--endPos);
    char *trimmedStr = (char*)malloc(len*sizeof(char));
    strncpy(trimmedStr,string+stPos,endPos+1);
    return trimmedStr;
}

int main()
{
    char string1[]="         a sdf ie    ";
    char *string =trim(string1);
    printf("%s",string);    
    return 0;
}

上面的代码工作正常,但我不想声明存储修剪后的单词的新变量。由于该结构包含大约100个变量。

有没有什么办法可以像下面这样,我不需要任何第二个变量来打印修剪后的字符串。

printf("%s",trim(string1)); 

我相信上面的打印内容可能会造成指针悬空的情况。

此外,还有什么方法可以不必对原始字符串收费,例如,如果我打印trim(string),它将打印修剪过的字符串,而当我仅打印字符串时,它将打印原始字符串

6 个答案:

答案 0 :(得分:1)

elcuco更快。但是已经完成,所以我们开始:

char *trim(char *string)
{
    char *ptr = NULL;
    while (*string == ' ') string++;  // chomp away space at the start
    ptr = string + strlen(string) - 1; // jump to the last char (-1 because '\0')
    while (*ptr == ' '){ *ptr = '\0' ; ptr--; } ; // overwrite with end of string
    return string;  // return pointer to the modified start 
}

如果您不想更改原始字符串,我会写一个特殊的印刷品:

void trim_print(char *string)
{
   char *ptr = NULL;
   while (*string == ' ') string++;  // chomp away space at the start
   ptr = string + strlen(string) - 1; // jump to the last char (-1 because '\0')
   while (*ptr == ' '){ ptr--; } ; // find end of string
   while (string <= ptr) { putchar(*string++); } // you get the picture 
}

类似的东西。

答案 1 :(得分:0)

您可以使用原始字符串来执行此操作。为了修整前缀,我只是前进了指针,对于后缀,我实际上添加了\0。如果要保持原始状态不变,则必须移动内存(这使它成为我提供的O(n)的O(n ^ 2)时间复杂度解决方案)。

#include <stdio.h>

char *trim(char *string)
{
    // trim prefix
    while ((*string) == ' ' ) {
         string ++;
    }

    // find end of original string
    char *c = string;
    while (*c) {
         c ++;
    }
    c--;

    // trim suffix
    while ((*c) == ' ' ) {
        *c = '\0';
        c--;
    }
    return string;
}

int main()
{
    char string1[] = "       abcdefg abcdf   ";
    char *string = trim(string1);
    printf("String is [%s]\n",string);
    return 0;
}

(重新考虑...是真的O(n ^ 2)吗?还是O(2n)等于更高的O(n)...?我想取决于实现方式)

答案 2 :(得分:0)

您可以通过在相同的输入字符串中提供输出来修改函数

--master local[*]

答案 3 :(得分:0)

  

...有什么办法我也不必向原始字符串收费,例如如果我修剪(string),它将打印修剪过的字符串,而当我仅打印字符串时,它将打印原始字符串字符串avinashse 8 mins ago

是的,尽管变得愚蠢。

您可以修改原始字符串。

trim(string);
printf("trimmed: %s\n", string);

好处是,如果要保留原始字符串,可以选择复制字符串。

char *original = strdup(string);
trim(string);
printf("trimmed: %s\n", string);

如果您不想修改原始字符串,则意味着您需要为修改后的字符串分配内存。然后必须释放该内存。这意味着有一个新变量来保存指针,以便您可以释放它。

char *trimmed = trim(original);
printf("trimmed: %s\n", trimmed);
free(trimmed);

您可以通过将函数指针传递到trim中并让trim为您管理所有内存来解决此问题。

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

void trim(char *string, void(*func)(char *) )
{
    // Advance the pointer to the first non-space char
    while( *string == ' ' ) {
        string++;
    }

    // Shrink the length to the last non-space char.
    size_t len = strlen(string);
    while(string[len-1]==' ') {
        len--;
    }

    // Copy the string to stack memory
    char trimmedStr[len + 1];
    strncpy(trimmedStr,string, len);

    // strncpy does not add a null byte, add it ourselves.
    trimmedStr[len] = '\0';

    // pass the trimmed string into the user function.
    func(trimmedStr);
}

void print_string(char *str) {
    printf("'%s'\n", str);
}

int main()
{
    char string[]="         a sdf ie    ";
    trim(string, print_string);
    printf("original: '%s'\n", string);
    return 0;
}

Ta da!一个变量,原始变量保持不变,没有内存泄漏。

虽然函数指针有其用途,但这有点愚蠢。

是C。习惯于管理内存。 ¯\ _(ツ)_ /¯

答案 4 :(得分:0)

  

此外,有什么方法我不必收取原始字符串的费用   好吧,就像我打印trim(string)一样,它将打印出修剪过的字符串,   当我只打印字符串时,它将打印原始字符串

是的,但是您不能在trim函数中分配新的内存,因为您将不会保留返回内存。

您可以在trim函数中使用静态char缓冲区并对其进行操作。

@elcuco答案的更新版本。

#include <stdio.h>

char *trim(char *string)
{
    static char buff[some max length];

    // trim prefix
    while ((*string) == ' ' ) {
         string++;
    }

    // find end of original string

    int i = 0;
    while (*string) {
         buff[i++] = *string;
         string++;
    }

    // trim suffix
    while ((buff[i]) == ' ' ) {
        buff[i] = '\0';
        i--;
    }
    return buff;
}

int main()
{
    char string1[] = "       abcdefg abcdf   ";
    char *string = trim(string1);
    printf("String is [%s]\n",string);
    return 0;
}

有了这个,您不必担心持有对trim函数返回的引用。

  

注意:buff函数的新调用将覆盖先前的trim值。

答案 5 :(得分:0)

如果不想更改原件,则需要进行复制,或将足够大的第二个数组作为参数传递给函数以进行填充。否则,简单的就地修整就可以了-只要原始字符串是 mutable

对前导和尾随空白进行修整的一种简单方法是确定要删除的前导空白字符的数量。然后只需使用memmove将第一个非空白字符移回字符串的开头(不要忘记将 nul-character 移至字符串的右侧)

仅留下尾随空白。一种简单的方法是从字符串的结尾到开头循环,用 nul-character 覆盖尾随空格的每个字符,直到找到第一个表示字符串新结尾的非空格字符

一个简单的实现可能是:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define DELIM " \t\n"   /* whitespace constant delimiters for strspn */

/** trim leading and trailing whitespace from s, (s must be mutable) */
char *trim (char *s)
{
    size_t  beg = strspn (s, DELIM),    /* no of chars of leading whitespace */
            len = strlen (s);           /* length of s */

    if (beg == len) {   /* string is all whitespace */
        *s = 0;         /* make s the empty-string */
        return s;
    }

    memmove (s, s + beg, len - beg + 1);    /* shift string to beginning */
    for (int i = (int)(len - beg - 1); i >= 0; i--) {   /* loop from end */
        if (isspace(s[i]))  /* checking if char is whitespace */
            s[i] = 0;       /* overwrite with nul-character */
        else
            break;          /* otherwise - done */
    }
    return s;       /* Return s */
}

int main (void) {

    char string1[] = "         a    sdf   ie    ";

    printf ("original: '%s'\n", string1);
    printf ("trimmed : '%s'\n", trim(string1));    
}

注意:额外的中间空格已添加到您的初始字符串中,以显示多个中间空格保持不变,输出被单引号引起来以显示剩余的文本边界)

使用/输出示例

$ ./bin/strtrim
original: '         a    sdf   ie    '
trimmed : 'a    sdf   ie'

仔细检查一下,如果还有其他问题,请告诉我。