簡體   English   中英

在C中刪除帶有字符串修剪的空格,換行符和制表符

[英]Removing a space, newline, and tabs with string trimming in C

我試圖從互聯網上收集信息,以了解其工作原理和功能。 基本上,每次讀取字符串時,我都需要檢查一個空格,換行符和制表符。 因此,我做了一個處理這種情況的函數:

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

static int  isspace(char c)
{
    return (c == '\t' || c == '\n' || c == ' ');
}

然后,我使用下面的函數在ANOTHER函數中實現它

char *my_strtrim(char const *string)
{
    char *i;
    char *s;
    int ready;

    i = s;
    s = (char *)string;
    ready = 0;
    while(*i)
    {
        ++i;
        if(isspace(*i))
        {
            if(!ready)
            {
                continue ;
            }
            ready = 0;
        }
        ready = 1;
        *(s++) = *i;
    }

    *s = 0;
    return ((char *)string);
}

對於我的主要工作,我只是做了一個隨機測試用例,其中涉及空格,制表符和換行符:

int main()
{
    char str[] = "                      hello world\n !";
    printf("%s",my_strtrim(str));
}

存在輸出錯誤,因為i = s因此my_strtrim函數存在錯誤,因為sNULL結果。 錯誤提示:

my_strtrim.c: error: variable 's' is uninitialized when used here [-Werror,-Wuninitialized]
        i = s;
            ^
my_strtrim.c: note: initialize the variable 's' to silence this warning
        char *s;
               ^
                = NULL

解決了我所說的內容(使s = NULL )后,我得到了分段錯誤。 這個問題變得令人困惑,因為它可以很好地用作for循環,但不能用作while循環。 我被要求做一個while循環的問題。

解決方案我的朋友給了我一些小建議/經驗,使代碼簡單易懂。 我有一個集群功能,可以同時完成很多事情。 因此,我感到困惑。 他引導了我,並告訴我讓我將整個功能濃縮成小塊。

步驟0:初始化變量並聲明

自我說明

步驟1:定位您的指針

 int step1_getPosition(char const *string) { int i; i = 0; while(my_iswhitespace(string[i])) { i++; continue; } return (i); } 

步驟2:復制您的STRING

 char *step2_copyString(char const *string, int pos) { char *tmp; int i; i = 0; tmp = my_strnew(my_strlen(string)); if(tmp == NULL) return (NULL); while (string[pos] != '\\0') tmp[i++] = string[pos++]; return (tmp); } 

第3步:刪除白色空間

 char *step3_removeWhite(char *str) { int i; i = my_strlen(str); while (str[i] == '\\0' || my_iswhitespace(str[i])) { str[i] = '\\0'; i--; } return (str); } 

步驟4:刪除多余的空字節('\\ 0')

 char *step4_removeExtraNulls(char *str) { char *newstring; newstring = my_strdup(str); if(newstring == NULL) return (NULL); free(str); return (newstring); } 

第5步:調用其他功能創建主要功能

 char *my_strtrim(char const *string) { char *trim; int i; i = step1_getPosition(string); trim = step2_copyString(string, i); if (trim == NULL) return (NULL); step3_removeWhite(trim); trim = step4_removeExtraNulls(trim); if (trim == NULL) return (NULL); return (trim); } 

我得到的輸出是: hello world ! 這是正確的

“修剪”前導空格字符的最簡單方法是跳過它們,根本不修改字符串。

這依賴於以下事實:C語言中的“字符串”可以表示為指向以null終止的字符序列的指針。

以您的字符串為例

char str[] = "                      hello world\n !";

如果我們讓數組str衰減到指向其第一個元素的指針,則它指向第一個空間。 如果我們有一個指向'h'的指針怎么辦? 那將是同樣有效的“字符串”。

要獲得該指針,我們只需在字符串上循環,只要當前字符是一個空格(當然不是終止符)即可。

將其付諸實踐,我們得到

char *my_strtrim(char const *string)
{
    for (/* empty */; *string && my_isspace(*string); ++string)
    {
        // Empty
    }

    return string;
}

在上面的函數的循環后,將指針string將指向無論對終止子(如果字符串只是所有空間),或於字符串中的第一個非空格字符。

如果我們像這樣使用

printf("%s\n", my_strtrim(str));

然后它將打印

hello world
 !

[嵌入的換行符是因為您在字符串中包含它。]

請注意,這不會修剪尾隨空格。 為此,參數string不能是指向常量字符的指針。

發生問題是因為當您分配i = ss變量處於不確定狀態。

請考慮以下代碼:

char *my_strtrim(char const *string)
{
    char *i;
    char *s;
    int ready;

    s = (char *)string;
    i = s;
    ready = 0;
    while(*i)
    {
        ++i;
        if(isspace(*i))
        {
            if(!ready)
            {
                continue ;
            }
            ready = 0;
        }
        ready = 1;
        *(s++) = *i;
    }

    *s = 0;
    return ((char *)string);
}

Zeid,繼續評論。 效率目標之一應該是限制您在字符串上進行的通過次數(最好是一次)。 您還應該考慮傳遞一個最終數組來保存修剪后的字符串,因為在許多情況下需要保留原始字符串,或者正如某些程序員所正確指出的那樣,您不能修改並將參數指定為const或駐留在其中的一個參數。在只讀內存中 (例如字符串常量 )。

您可以在調用方中為此目的使用VLA。 將其放在一起並添加一個附加參數以保存下面的結果'r' ,您可以執行以下操作。

它只是刪除所有前導空格,然后進行備份,刪除所有尾隨空格,並檢查最終字符是否不是alnum字符(因為大多數句子都以某種標點符號結尾)。 然后,它檢查標點符號和字符串中的最后一個alchar字符之間是否還有其他空格,通過向前拖尾字符以覆蓋找到的任何中間空格來刪除任何中間空格(這將消除world之間多余的'\\n ''!'

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

/** remove leading and trailing whitespace, original is preserved.
 *  this funciton can be used with or without assigning return.
 *  any intervening whitespace between end punctuation and first
 *  alpha-num character is also removed.
 */
char *strtrimws (char *r, const char *s)
{
    char *p = r;                            /* pointer to result         */
    *r = 0;                                 /* initialize as empty str   */
    if (!s) return NULL;                    /* validaate source str      */
    if (!*s) return r;                      /* empty str - nothing to do */
    while (isspace (*s))  s++;              /* skip leading whitespace   */
    while (*s) *p++ = *s++;                 /* fill r with s to end      */
    *p = 0;                                 /* nul-terminate r           */
    while (p > r && isspace (*--p)) *p = 0; /* overwrite spaces from end */
    while (p > r && !isalnum (*--p)) {      /* continue until 1st alnum  */
        if (isspace (*p)) {                 /* if spaces found           */
            char *rp = p, *wp = p;          /* set read & write pointers */
            while (*rp++) *wp++ = *rp;      /* shuffle end chars forward */
            *wp = 0;                        /* nul-terminate at new end  */
        }
    }
    return r;
}

int main (void) {

    char str[] = "                      hello world\n !",
        result[sizeof str];
    printf ("%s\n", strtrimws (result, str));
    return 0;
}

使用/輸出示例

$ ./bin/trimws
hello world!

仔細檢查一下,如果您還有其他問題,請與我聯系。 如果沒有,請祝您編程愉快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM