[英]C - Replace tabs with spaces, multiple spaces with 1 space, multiple newlines with 1 newline
[英]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函數存在錯誤,因為s
為NULL
結果。 錯誤提示:
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循環的問題。
解決方案我的朋友給了我一些小建議/經驗,使代碼簡單易懂。 我有一個集群功能,可以同時完成很多事情。 因此,我感到困惑。 他引導了我,並告訴我讓我將整個功能濃縮成小塊。
步驟1:定位您的指針
int step1_getPosition(char const *string) { int i; i = 0; while(my_iswhitespace(string[i])) { i++; continue; } return (i); }
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); }
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); }
char *step4_removeExtraNulls(char *str) { char *newstring; newstring = my_strdup(str); if(newstring == NULL) return (NULL); free(str); return (newstring); }
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 = s
, s
變量處於不確定狀態。
請考慮以下代碼:
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.