从 fgets() 输入中删除尾随换行符

发布于 2024-08-30 09:40:43 字数 341 浏览 5 评论 0 原文

我试图从用户那里获取一些数据并将其发送到 gcc 中的另一个函数。代码是这样的。

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

但是,我发现它最后有一个换行符 \n 。因此,如果我输入 John,它最终会发送 John\n。如何删除该 \n 并发送正确的字符串。

I am trying to get some data from the user and send it to another function in gcc. The code is something like this.

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

However, I find that it has a newline \n character in the end. So if I enter John it ends up sending John\n. How do I remove that \n and send a proper string.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

巾帼英雄 2024-09-06 09:40:43

也许最简单的解决方案使用我最喜欢的鲜为人知的函数之一, strcspn()

buffer[strcspn(buffer, "\n")] = 0;

如果您希望它也处理 '\r'(例如,如果流是二进制的):

buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...

该函数计算字符数,直到遇到 '\r''\n'(换句话说,它找到第一个 '\r'< /code> 或 '\n')。如果没有命中任何内容,它将停在 '\0' 处(返回字符串的长度)。

请注意,即使没有换行符,此方法也能正常工作,因为 strcspn'\0' 处停止。在这种情况下,整行只需将 '\0' 替换为 '\0'

Perhaps the simplest solution uses one of my favorite little-known functions, strcspn():

buffer[strcspn(buffer, "\n")] = 0;

If you want it to also handle '\r' (say, if the stream is binary):

buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...

The function counts the number of characters until it hits a '\r' or a '\n' (in other words, it finds the first '\r' or '\n'). If it doesn't hit anything, it stops at the '\0' (returning the length of the string).

Note that this works fine even if there is no newline, because strcspn stops at a '\0'. In that case, the entire line is simply replacing '\0' with '\0'.

小苏打饼 2024-09-06 09:40:43

优雅的方式:

Name[strcspn(Name, "\n")] = 0;

稍微丑陋的方式:

char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
    *pos = '\0';
else
    /* input too long for buffer, flag error */

稍微奇怪的方式:

strtok(Name, "\n");

请注意,如果用户输入空字符串(即仅按 Enter 键),strtok 函数将无法按预期工作。它使 \n 字符保持不变。

当然还有其他的。

The elegant way:

Name[strcspn(Name, "\n")] = 0;

The slightly ugly way:

char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
    *pos = '\0';
else
    /* input too long for buffer, flag error */

The slightly strange way:

strtok(Name, "\n");

Note that the strtok function doesn't work as expected if the user enters an empty string (i.e. presses only Enter). It leaves the \n character intact.

There are others as well, of course.

情场扛把子 2024-09-06 09:40:43
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
已下线请稍等 2024-09-06 09:40:43

下面是从 fgets() 保存的字符串中删除潜在的 '\n' 的快速方法。
它使用 strlen(),并进行 2 个测试。

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }
  // `len` now represents the length of the string, shortened or not.

现在根据需要使用 bufferlen

此方法的另一个好处是为后续代码提供了 len 值。它可以轻松地比 strchr(Name, '\n') 更快。 参考 YMMV,但这两种方法都有效。


原始fgets()中的buffer在某些情况下不会包含在"\n"中:
A) 该行对于 buffer 来说太长,因此只有 '\n' 之前的 char 保存在 buffer 中。未读字符保留在流中。
B) 文件中的最后一行没有以 '\n' 结尾。

如果输入在某处嵌入了空字符 '\0',则 strlen() 报告的长度将不包括 '\n'地点。


其他一些答案的问题:

  1. strtok(buffer, "\n");buffer 时无法删除 '\n'“\n”。来自此答案 - 在此答案后进行修改以警告此限制。

  2. fgets() 读取的第一个 char'\0' 时,以下操作在极少数情况下会失败。当输入以嵌入的 '\0' 开头时,就会发生这种情况。然后 buffer[len -1] 变成 buffer[SIZE_MAX] 访问内存肯定超出了 buffer 的合法范围。黑客可能会在愚蠢地读取 UTF16 文本文件时尝试或发现一些东西。这是编写此答案时答案的状态。后来,一位非操作员对其进行了编辑,以包含类似此答案检查 "" 的代码。

     size_t len = strlen(buffer);
     if (buffer[len - 1] == '\n') { // 当 len == 0 时失败
       缓冲区[len -1] = '\0';
     }
    
  3. sprintf(buffer,"%s",buffer); 是未定义的行为:参考。此外,它不保存任何前导、分隔或尾随空格。现在已删除

  4. [稍后编辑答案] 1个衬垫没有问题buffer[strcspn( buffer, "\n")] = 0;strlen() 方法相比,性能除外。考虑到代码正在执行 I/O(CPU 时间的黑洞),修剪的性能通常不是问题。如果以下代码需要字符串的长度或高度关注性能,请使用此 strlen() 方法。否则,strcspn() 是一个不错的选择。

Below is a fast approach to remove a potential '\n' from a string saved by fgets().
It uses strlen(), with 2 tests.

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }
  // `len` now represents the length of the string, shortened or not.

Now use buffer and len as needed.

This method has the side benefit of a len value for subsequent code. It can be easily faster than strchr(Name, '\n'). Ref YMMV, but both methods work.


buffer, from the original fgets() will not contain in "\n" under some circumstances:
A) The line was too long for buffer so only char preceding the '\n' is saved in buffer. The unread characters remain in the stream.
B) The last line in the file did not end with a '\n'.

If input has embedded null characters '\0' in it somewhere, the length reported by strlen() will not include the '\n' location.


Some other answers' issues:

  1. strtok(buffer, "\n"); fails to remove the '\n' when buffer is "\n". From this answer - amended after this answer to warn of this limitation.

  2. The following fails on rare occasions when the first char read by fgets() is '\0'. This happens when input begins with an embedded '\0'. Then buffer[len -1] becomes buffer[SIZE_MAX] accessing memory certainly outside the legitimate range of buffer. Something a hacker may try or found in foolishly reading UTF16 text files. This was the state of an answer when this answer was written. Later a non-OP edited it to include code like this answer's check for "".

     size_t len = strlen(buffer);
     if (buffer[len - 1] == '\n') {  // FAILS when len == 0
       buffer[len -1] = '\0';
     }
    
  3. sprintf(buffer,"%s",buffer); is undefined behavior: Ref. Further, it does not save any leading, separating or trailing whitespace. Now deleted.

  4. [Edit due to good later answer] There are no problems with the 1 liner buffer[strcspn(buffer, "\n")] = 0; other than performance as compared to the strlen() approach. Performance in trimming is usually not an issue given code is doing I/O - a black hole of CPU time. Should following code need the string's length or is highly performance conscious, use this strlen() approach. Else the strcspn() is a fine alternative.

金兰素衣 2024-09-06 09:40:43

如果每行都有 '\n',则直接从 fgets 输出中删除 '\n'

line[strlen(line) - 1] = '\0';

否则:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}

Direct to remove the '\n' from the fgets output if every line has '\n'

line[strlen(line) - 1] = '\0';

Otherwise:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}
2024-09-06 09:40:43

对于单个 '\n' 修剪,

void remove_new_line(char* string)
{
    size_t length = strlen(string);
    if((length > 0) && (string[length-1] == '\n'))
    {
        string[length-1] ='\0';
    }
}

对于多个 '\n' 修剪,

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\0';
  }
}

For single '\n' trimming,

void remove_new_line(char* string)
{
    size_t length = strlen(string);
    if((length > 0) && (string[length-1] == '\n'))
    {
        string[length-1] ='\0';
    }
}

for multiple '\n' trimming,

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\0';
  }
}
亚希 2024-09-06 09:40:43

我的新手方式;-) 请告诉我这是否正确。它似乎适用于我的所有案例:

#define IPT_SIZE 5

int findNULL(char* arr)
{
    for (int i = 0; i < strlen(arr); i++)
    {
        if (*(arr+i) == '\n')
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
    int counter = 0;

    //prompt user for the input:
    printf("input string no longer than %i characters: ", IPT_SIZE);
    do
    {
        fgets(input, 1000, stdin);
        *(input + findNULL(input)) = '\0';
        if (strlen(input) > IPT_SIZE)
        {
            printf("error! the given string is too large. try again...\n");
            counter++;
        }
        //if the counter exceeds 3, exit the program (custom function):
        errorMsgExit(counter, 3); 
    }
    while (strlen(input) > IPT_SIZE);

//rest of the program follows

free(input)
return 0;
}

My Newbie way ;-) Please let me know if that's correct. It seems to be working for all my cases:

#define IPT_SIZE 5

int findNULL(char* arr)
{
    for (int i = 0; i < strlen(arr); i++)
    {
        if (*(arr+i) == '\n')
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
    int counter = 0;

    //prompt user for the input:
    printf("input string no longer than %i characters: ", IPT_SIZE);
    do
    {
        fgets(input, 1000, stdin);
        *(input + findNULL(input)) = '\0';
        if (strlen(input) > IPT_SIZE)
        {
            printf("error! the given string is too large. try again...\n");
            counter++;
        }
        //if the counter exceeds 3, exit the program (custom function):
        errorMsgExit(counter, 3); 
    }
    while (strlen(input) > IPT_SIZE);

//rest of the program follows

free(input)
return 0;
}
娇纵 2024-09-06 09:40:43

以最明显的方式删除换行符的步骤:

  1. 使用 strlen() 确定 NAME 内字符串的长度,头 string.h< /代码>。请注意,strlen() 不计算终止 \0
size_t sl = strlen(NAME);

  1. 查看字符串是否以 \0 字符开头或仅包含一个 \0 字符(空字符串)。在这种情况下,sl 将是 0,因为正如我上面所说的 strlen() 不计算 \0并在第一次出现时停止:
if(sl == 0)
{
   // Skip the newline replacement process.
}

  1. 检查正确字符串的最后一个字符是否是换行符'\n'。如果是这种情况,请将 \n 替换为 \0。请注意,索引计数从 0 开始,因此我们需要执行 NAME[sl - 1]
if(NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

请注意,如果您仅在 fgets() 处按 Enter 键code> 字符串请求(字符串内容仅由换行符组成),此后 NAME 中的字符串将为空字符串。


  1. 我们可以使用逻辑运算符 && 将步骤 2. 和 3. 组合在一个 if 语句中:
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

  1. 完成的代码:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

如果您更喜欢函数为了通过一般处理 fgets 输出字符串来使用此技术,而无需每次都重新输入,这里是 fgets_newline_kill

void fgets_newline_kill(char a[])
{
    size_t sl = strlen(a);

    if(sl > 0 && a[sl - 1] == '\n')
    {
       a[sl - 1] = '\0';
    }
}

在您提供的示例中,它将是:

printf("Enter your Name: ");

if (fgets(Name, sizeof Name, stdin) == NULL) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}
else {
    fgets_newline_kill(NAME);
}

请注意,此方法确实如果输入字符串中嵌入了 \0 则不起作用。如果是这种情况,strlen() 将仅返回第一个 \0 之前的字符数。但这并不是一种常见的方法,因为大多数字符串读取函数通常会在第一个 \0 处停止,并获取字符串直到该空字符。

除了问题本身。尽量避免使代码不清楚的双重否定:if (!(fgets(Name, sizeof Name, stdin) != NULL) {}。您可以简单地执行if (fgets(Name) , sizeof 名称, stdin) == NULL) {}

The steps to remove the newline character in the perhaps most obvious way:

  1. Determine the length of the string inside NAME by using strlen(), header string.h. Note that strlen() does not count the terminating \0.
size_t sl = strlen(NAME);

  1. Look if the string begins with or only includes one \0 character (empty string). In this case sl would be 0 since strlen() as I said above doesn´t count the \0 and stops at the first occurrence of it:
if(sl == 0)
{
   // Skip the newline replacement process.
}

  1. Check if the last character of the proper string is a newline character '\n'. If this is the case, replace \n with a \0. Note that index counts start at 0 so we will need to do NAME[sl - 1]:
if(NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

Note if you only pressed Enter at the fgets() string request (the string content was only consisted of a newline character) the string in NAME will be an empty string thereafter.


  1. We can combine step 2. and 3. together in just one if-statement by using the logic operator &&:
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

  1. The finished code:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

If you rather like a function for use this technique by handling fgets output strings in general without retyping each and every time, here is fgets_newline_kill:

void fgets_newline_kill(char a[])
{
    size_t sl = strlen(a);

    if(sl > 0 && a[sl - 1] == '\n')
    {
       a[sl - 1] = '\0';
    }
}

In your provided example, it would be:

printf("Enter your Name: ");

if (fgets(Name, sizeof Name, stdin) == NULL) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}
else {
    fgets_newline_kill(NAME);
}

Note that this method does not work if the input string has embedded \0s in it. If that would be the case strlen() would only return the amount of characters until the first \0. But this isn´t quite a common approach, since the most string-reading functions usually stop at the first \0 and take the string until that null character.

Aside from the question on its own. Try to avoid double negations that make your code unclearer: if (!(fgets(Name, sizeof Name, stdin) != NULL) {}. You can simply do if (fgets(Name, sizeof Name, stdin) == NULL) {}.

燕归巢 2024-09-06 09:40:43

一般来说,与其修剪不需要的数据,不如从一开始就避免写入数据。如果您不希望缓冲区中出现换行符,请不要使用 fgets。请改用 getcfgetcscanf。也许是这样的:

#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
        char Name[256];
        char fmt[32];
        if( snprintf(fmt, sizeof fmt, "%%%zd[^\n]", sizeof Name - 1) >= (int)sizeof fmt ){
                fprintf(stderr, "Unable to write format\n");
                return EXIT_FAILURE;
        }
        if( scanf(fmt, Name) == 1 ) {
                printf("Name = %s\n", Name);
        }
        return 0;
}

请注意,这种特殊方法将使换行符保持未读状态,因此您可能需要使用像 "%255[^\n]%*c" 这样的格式字符串来丢弃它(例如, sprintf(fmt, "%%%zd[^\n]%%*c", sizeof Name - 1);),或者在 scanf 后面加上 getchar()代码>.

In general, rather than trimming data that you don't want, avoid writing it in the first place. If you don't want the newline in the buffer, don't use fgets. Instead, use getc or fgetc or scanf. Perhaps something like:

#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
        char Name[256];
        char fmt[32];
        if( snprintf(fmt, sizeof fmt, "%%%zd[^\n]", sizeof Name - 1) >= (int)sizeof fmt ){
                fprintf(stderr, "Unable to write format\n");
                return EXIT_FAILURE;
        }
        if( scanf(fmt, Name) == 1 ) {
                printf("Name = %s\n", Name);
        }
        return 0;
}

Note that this particular approach will leave the newline unread, so you may want to use a format string like "%255[^\n]%*c" to discard it (eg, sprintf(fmt, "%%%zd[^\n]%%*c", sizeof Name - 1);), or perhaps follow the scanf with a getchar().

吖咩 2024-09-06 09:40:43

如果使用 POSIX getline() 是一个选项 - 不忽略它的安全问题,并且如果您希望使用大括号指针 - 您可以避免字符串函数,因为 getline 返回字符数。如下所示:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char *fname, *lname;
    size_t size = 32, nchar; // Max size of strings and number of characters read
    fname = malloc(size * sizeof *fname);
    lname = malloc(size * sizeof *lname);
    if (NULL == fname || NULL == lname)
    {
        printf("Error in memory allocation.");
        exit(1);
    }
    printf("Enter first name ");
    nchar = getline(&fname, &size, stdin);
    if (nchar == -1) // getline return -1 on failure to read a line.
    {
        printf("Line couldn't be read..");
        // This if block could be repeated for next getline too
        exit(1);
    }
    printf("Number of characters read :%zu\n", nchar);
    fname[nchar - 1] = '\0';
    printf("Enter last name ");
    nchar = getline(&lname, &size, stdin);
    printf("Number of characters read :%zu\n", nchar);
    lname[nchar - 1] = '\0';
    printf("Name entered %s %s\n", fname, lname);
    return 0;
}

注意[不过,不应忽视 getline安全问题]

If using POSIX getline() is an option - Not neglecting its security issues and if you wish to brace pointers - you can avoid string functions as the getline returns the number of characters. Something like below:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char *fname, *lname;
    size_t size = 32, nchar; // Max size of strings and number of characters read
    fname = malloc(size * sizeof *fname);
    lname = malloc(size * sizeof *lname);
    if (NULL == fname || NULL == lname)
    {
        printf("Error in memory allocation.");
        exit(1);
    }
    printf("Enter first name ");
    nchar = getline(&fname, &size, stdin);
    if (nchar == -1) // getline return -1 on failure to read a line.
    {
        printf("Line couldn't be read..");
        // This if block could be repeated for next getline too
        exit(1);
    }
    printf("Number of characters read :%zu\n", nchar);
    fname[nchar - 1] = '\0';
    printf("Enter last name ");
    nchar = getline(&lname, &size, stdin);
    printf("Number of characters read :%zu\n", nchar);
    lname[nchar - 1] = '\0';
    printf("Name entered %s %s\n", fname, lname);
    return 0;
}

Note: The [ security issues ] with getline shouldn't be neglected though.

只有影子陪我不离不弃 2024-09-06 09:40:43

扩展 @Jerry Coffin 和 @Tim Čas 的答案:

strchr 版本在设计上比 strcspn (和 strlen 版本)快得多可能是最快的)。

strcspn 的内部结构必须遍历 "\n" 字符串,如果合理实现,它只会执行一次并将字符串长度存储在某处。然后在搜索时,它还必须使用嵌套的 for 循环来遍历 "\n" 字符串。

忽略这些函数的库质量实现会考虑的字长等因素,简单的实现可能如下所示:

char* my_strchr (const char *s, int c)
{
  while(*s != '\0')
  {
    if(*s == c)
      return (char*)s;
    s++;
  }
  return NULL;
}

size_t my_strcspn (const char *s1, const char *s2)
{
  size_t s2_length = strlen(s2);
  size_t i;
  for(i=0; s1[i] != '\0'; i++)
  {
    for(size_t j=0; j<s2_length; j++)
    {
      if(s1[i] == s2[j])
      {
        return i;
      }
    }
  }
  return i;
}
  • 对于 strchr,每个字符有两个分支。一个搜索空终止符,另一个将当前字符与搜索到的字符进行比较。

  • 对于 strcspn,它要么必须像我的示例中那样预先计算 s2 大小,要么在查找​​ null 以及搜索时迭代它钥匙。后者本质上就是 strchr 所做的,因此内部循环可以用 strchr 替换。无论我们如何实现,都会有很多额外的分支。

    细心的语言律师也可能会发现 strcspn 标准库定义中缺少 restrict。这意味着编译器不允许假设 s1s2 是不同的字符串。这也会阻止一些优化。

strlen 版本将比这两个版本更快,因为 strlen 只需要检查 null 终止而无需其他任何操作。尽管正如 @chux - Reinstate Monica 的答案中提到的,但在某些情况下它不起作用,因此它比其他版本稍微脆弱一些。

问题的根源在于 fgets 函数的 API 不好 - 如果它在过去实现得更好,它会返回与实际读取的字符数相对应的大小,这将导致太棒了。或者,指向最后一个字符的指针,如 strchr 所示。相反,标准库通过返回指向传递的字符串中第一个字符的指针来浪费返回值,这有点有用。

To expand on the answers by @Jerry Coffin and @Tim Čas:

The strchr version is by design much faster than the strcspn (and strlen versions are likely the fastest of all).

The internals of strcspn has to iterate through the "\n" string and if reasonably implemented, it only does that once and stores down the string length somewhere. Then while searching, it also has to use a nested for loop going through the "\n" string.

Ignoring things like word size that a library-quality implementation of these functions would take in account, naive implementations may look like this:

char* my_strchr (const char *s, int c)
{
  while(*s != '\0')
  {
    if(*s == c)
      return (char*)s;
    s++;
  }
  return NULL;
}

size_t my_strcspn (const char *s1, const char *s2)
{
  size_t s2_length = strlen(s2);
  size_t i;
  for(i=0; s1[i] != '\0'; i++)
  {
    for(size_t j=0; j<s2_length; j++)
    {
      if(s1[i] == s2[j])
      {
        return i;
      }
    }
  }
  return i;
}
  • In case of strchr, there are two branches per character. One searching for the null terminator and other comparing the current character with the one searched for.

  • In case of strcspn, it either has to pre-calculate s2 size as in my example, or alternatively iterate through it while looking for null as well as the search key. The latter is essentially just what strchr does, so the inner loop could have been replaced with strchr. No matter how we implement it, there will be a lot of extra branching.

    An attentive language lawyer might also spot the absence of restrict in the strcspn standard library definition. Meaning that the compiler is not allowed to assume that s1 and s2 are different strings. This blocks some optimizations too.

The strlen version will be faster than both, since strlenonly needs to check for null termination and nothing else. Though as mentioned in the answer by @chux - Reinstate Monica, there are some situations where it won't work, so it is slightly more brittle than the other versions.

The root of the problem is the bad API of the fgets function - if it had been implemented better back in the days, it would have returned a size corresponding to the number of characters actually read, which would have been great. Or alternatively a pointer to the last character read like strchr. Instead the standard lib wasted the return value by returning a pointer to the first character in the string passed, which is mildly useful.

雨后咖啡店 2024-09-06 09:40:43

Tim 的一个衬垫对于通过调用 fgets 获得的字符串来说是令人惊奇的,因为您知道它们末尾包含一个换行符。

如果您处于不同的上下文中并且想要处理可能包含多个换行符的字符串,您可能需要寻找 strrspn。它不是 POSIX,这意味着您不会在所有 Unices 上找到它。我根据自己的需要写了一篇。

/* Returns the length of the segment leading to the last 
   characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
  const char *ch;
  size_t len = strlen(s);

more: 
  if (len > 0) {
    for (ch = accept ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        len--;
        goto more;
      }
    }
  }
  return len;
}

对于那些在 C 中寻找 Perl chomp 等效项的人来说,我认为这就是它(chomp 仅删除尾随换行符)。

line[strrspn(string, "\r\n")] = 0;

strrcspn 函数:

/* Returns the length of the segment leading to the last 
   character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
  const char *ch;
  size_t len = strlen(s);
  size_t origlen = len;

  while (len > 0) {
    for (ch = reject ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        return len;
      }
    }
    len--;
  }
  return origlen;
}

Tim Čas one liner is amazing for strings obtained by a call to fgets, because you know they contain a single newline at the end.

If you are in a different context and want to handle strings that may contain more than one newline, you might be looking for strrspn. It is not POSIX, meaning you will not find it on all Unices. I wrote one for my own needs.

/* Returns the length of the segment leading to the last 
   characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
  const char *ch;
  size_t len = strlen(s);

more: 
  if (len > 0) {
    for (ch = accept ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        len--;
        goto more;
      }
    }
  }
  return len;
}

For those looking for a Perl chomp equivalent in C, I think this is it (chomp only removes the trailing newline).

line[strrspn(string, "\r\n")] = 0;

The strrcspn function:

/* Returns the length of the segment leading to the last 
   character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
  const char *ch;
  size_t len = strlen(s);
  size_t origlen = len;

  while (len > 0) {
    for (ch = reject ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        return len;
      }
    }
    len--;
  }
  return origlen;
}
一抹微笑 2024-09-06 09:40:43

下面的函数是我在 Github 上维护的字符串处理库的一部分。它从字符串中删除不需要的字符,正是您想要的

int zstring_search_chr(const char *token,char s){
    if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;
    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
        return str;
}

示例用法可能是

Example Usage
      char s[]="this is a trial string to test the function.";
      char const *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

您可能想检查其他可用的函数,甚至为该项目做出贡献:)
https://github.com/fnoyanisi/zString

The function below is a part of string processing library I am maintaining on Github. It removes and unwanted characters from a string, exactly what you want

int zstring_search_chr(const char *token,char s){
    if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;
    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
        return str;
}

An example usage could be

Example Usage
      char s[]="this is a trial string to test the function.";
      char const *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

You may want to check other available functions, or even contribute to the project :)
https://github.com/fnoyanisi/zString

入怼 2024-09-06 09:40:43
 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

你应该尝试一下。该代码基本上循环遍历字符串,直到找到“\n”。当发现 '\n' 将被空字符终止符 '\0' 替换时

请注意,您正在比较此行中的字符而不是字符串,则无需使用 strcmp():

if(Name[i] == '\n') Name[i] = '\0';

因为您将使用单引号而不是双引号。 这里有关 single 的链接如果您想了解更多信息,请与双引号比较

 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

You should give it a try. This code basically loop through the string until it finds the '\n'. When it's found the '\n' will be replaced by the null character terminator '\0'

Note that you are comparing characters and not strings in this line, then there's no need to use strcmp():

if(Name[i] == '\n') Name[i] = '\0';

since you will be using single quotes and not double quotes. Here's a link about single vs double quotes if you want to know more

桃酥萝莉 2024-09-06 09:40:43

这是我的解决方案。很简单。

// Delete new line
// char preDelete[256]  include "\n" as newline after fgets

char deletedWords[256];
int iLeng = strlen(preDelete);
int iFinal = 0;
for (int i = 0; i < iLeng; i++) {
    if (preDelete[i] == '\n') {

    }
    else {
        deletedWords[iFinal]  = preDelete[i];
        iFinal++;
    }
    if (i == iLeng -1 ) {
        deletedWords[iFinal] = '\0';
    }
}

This is my solution. Very simple.

// Delete new line
// char preDelete[256]  include "\n" as newline after fgets

char deletedWords[256];
int iLeng = strlen(preDelete);
int iFinal = 0;
for (int i = 0; i < iLeng; i++) {
    if (preDelete[i] == '\n') {

    }
    else {
        deletedWords[iFinal]  = preDelete[i];
        iFinal++;
    }
    if (i == iLeng -1 ) {
        deletedWords[iFinal] = '\0';
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文