سؤال

أحاول الحصول على بعض البيانات من المستخدم وإرسالها إلى وظيفة أخرى في 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 وأرسل سلسلة مناسبة.

هل كانت مفيدة؟

المحلول

الطريق القبيح قليلا:

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

الطريقة الغريبة قليلاً:

strtok(Name, "\n");

نلاحظ أن strtok لا تعمل الوظيفة كما هو متوقع إذا دخل المستخدم إلى سلسلة فارغة (أي يضغط فقط إدخال). يترك \n شخصية سليمة.

هناك آخرون كذلك ، بالطبع.

نصائح أخرى

ربما يستخدم الحل الأبسط إحدى وظائفي المفضلة غير المعروفة ، strcspn():

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

إذا كنت تريد أن تتعامل معها أيضًا '\r' (قل ، إذا كان الدفق ثنائيًا):

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

تعتبر الوظيفة عدد الأحرف حتى تصل إلى أ '\r' أو أ '\n' (بمعنى آخر ، يجد الأول '\r' أو '\n'). إذا لم تصل إلى أي شيء ، فسيتوقف عند '\0' (إرجاع طول السلسلة).

لاحظ أن هذا يعمل بشكل جيد حتى لو لم يكن هناك سطر جديد ، لأنه strcspn يتوقف عند أ '\0'. في هذه الحالة ، يتم استبدال الخط بأكمله ببساطة '\0' مع '\0'.

size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';

فيما يلي نهج سريع لإزالة الإمكانات '\n' من سلسلة محفوظة بواسطة fgets().
يستخدم 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';
  }

استخدم الآن buffer و len كما هو مطلوب.

هذه الطريقة لها فائدة جانبية من len قيمة الرمز اللاحق. يمكن أن يكون أسرع بسهولة من strchr(Name, '\n'). المرجع YMMV ، ولكن كلتا الطريقتين تعمل.


buffer, ، من الأصل fgets() لن يحتوي في "\n" في ظل بعض الظروف:
أ) كان الخط طويل جدا ل buffer لذلك فقط char قبل '\n' يتم حفظه buffer. تظل الشخصيات غير المقروءة في الدفق.
ب) لم ينتهي السطر الأخير في الملف بـ '\n'.

إذا كان المدخلات قد تم تضمين أحرف فارغة '\0' فيه في مكان ما ، الطول الذي أبلغ عنه strlen() لن تشمل '\n' موقعك.


بعض الإجابات الأخرى 'قضايا:

  1. strtok(buffer, "\n"); فشل في إزالة '\n' متى buffer هو "\n". من هذا إجابه - معدّل بعد هذه الإجابة لتحذير هذا القيد.

  2. فشل التالي في مناسبات نادرة عندما يكون الأول char اقرأ بواسطة fgets() هو '\0'. يحدث هذا عندما يبدأ الإدخال بتضمين '\0'. ثم buffer[len -1] يصبح buffer[SIZE_MAX] الوصول إلى الذاكرة بالتأكيد خارج النطاق الشرعي لـ buffer. شيء قد يحاول أو يجده القراصنة في قراءة ملفات UTF16 بحماقة. كانت هذه حالة إجابه عندما تمت كتابة هذه الإجابة. في وقت لاحق ، قام غير OP بتحريره لتضمين رمز مثل Check of This Found "".

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
  3. sprintf(buffer,"%s",buffer); هو سلوك غير محدد: المرجع. علاوة على ذلك ، فإنه لا ينقذ أي مسافة بيضاء رائدة أو مفصولة أو زائدة. حاليا تم الحذف.

  4. تحرير بسبب الخير لاحقًا إجابه] لا توجد مشاكل مع 1 بطانة buffer[strcspn(buffer, "\n")] = 0; بخلاف الأداء مقارنة مع strlen() يقترب. عادةً ما يكون الأداء في التشذيب ليس بمثابة رمز معين يقوم بإدخال/إخراج - ثقب أسود من وقت وحدة المعالجة المركزية. في حالة حاجة المدونة التالية إلى طول السلسلة أو يكون واعيًا للغاية للأداء ، استخدم هذا strlen() يقترب. آخر strcspn() هو بديل جيد.

مباشرة لإزالة ' 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';
}

لفرد ' n' trmming ،

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

تيم čas بطانة مدهشة بالنسبة للسلاسل التي تم الحصول عليها عن طريق مكالمة إلى FGTS ، لأنك تعلم أنها تحتوي على سطر جديد واحد في النهاية.

إذا كنت في سياق مختلف وترغب في التعامل مع السلاسل التي قد تحتوي على أكثر من سطر جديد ، فقد تبحث عن STRRSPN. إنه ليس Posix ، مما يعني أنك لن تجدها على جميع الوحدات. كتبت واحدة لاحتياجاتي الخاصة.

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

بالنسبة لأولئك الذين يبحثون عن مكافئ perl chomp في C ، أعتقد أن هذا هو (Chomp يزيل فقط خط Newline Trailing).

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

إذا كنت تستخدم 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 لا ينبغي إهمالها رغم ذلك.

طريقتي المبتدئ ؛-) يرجى إعلامي إذا كان هذا صحيحًا. يبدو أنه يعمل من أجل جميع حالاتي:

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

الوظيفة أدناه هي جزء من مكتبة معالجة السلسلة التي أحتفظ بها على 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

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

بما أنك ستستخدم عروض أسعار واحدة وليس عروض أسعار مزدوجة. هنا رابط حول عروض أسعار مزدوجة واحدة مقابل إذا كنت تريد معرفة المزيد

جرب هذه:

        int remove_cr_lf(char *str)
        {
          int len =0;


          len = strlen(str);

          for(int i=0;i<5;i++)
          {
            if (len>0)
            if (str[len-1] == '\n')
            {
              str[len-1] = 0;
              len--;
            }

            if (len>0)
            if (str[len-1] == '\r')
            {
              str[len-1] = 0;
              len--;
            }
          }

          return 0;
        }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top