Печать печати на двух строках без указания новой строки? [Дубликат]

Лучшая опция ... просто разделите все незнаковые символы на входе (кроме знаков «x» и «впереди» +), заботясь о том, что британская тенденция писать числа в нестандартной форме +44 (0) ..., когда попросил использовать международный префикс (в этом конкретном случае вы должны полностью отбросить (0)).

Затем вы получите такие значения, как:

 12345678901
 12345678901x1234
 345678901x1234
 12344678901
 12345678901
 12345678901
 12345678901
 +4112345678
 +441234567890

Тогда, когда вы показываете, переформатируете в свои сердца. например,

  1 (234) 567-8901
  1 (234) 567-8901 x1234
168
задан Jonathan Leffler 14 March 2015 в 07:23
поделиться

12 ответов

Немного уродливый способ:

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

Немного странный способ:

strtok(Name, "\n");

Обратите внимание, что функция strtok не работает должным образом, если пользователь входит пустую строку (т.е. нажмите только Enter). Он оставляет неизменным \n.

Конечно, есть и другие.

113
ответ дан Malcolm McLean 21 August 2018 в 16:22
поделиться
  • 1
    Осторожно с помощью strtok ... – frankc 22 April 2010 в 21:42
  • 2
    Любая библиотека времени выполнения C, которая является осведомленной о потоке (то есть, большая часть любой, которая нацелена на многопоточную платформу), strtok() будет потокобезопасной (она будет использовать локальное хранилище потоков для состояния «inter-call»). Тем не менее, как правило, лучше использовать нестандартный (но достаточно общий) вариант strtok_r(). – Michael Burr 22 April 2010 в 22:36
  • 3
    См. Мой ответ для полностью потокобезопасного и повторного варианта, аналогичного вашему strtok подходу (и он работает с пустыми вводами). На самом деле хорошим способом реализации strtok является использование strcspn и strspn. – Tim Čas 11 February 2015 в 20:09
  • 4
    Очень важно обрабатывать дело else, если вы находитесь в среде, где существует риск чрезмерно длинных строк. Беззвучный усеченный вход может привести к очень опасным ошибкам. – Malcolm McLean 8 January 2017 в 19:52
  • 5
    Если вам нравятся однострочные и используются glibc, попробуйте *strchrnul(Name, '\n') = '\0';. – twobit 17 August 2017 в 08:55

Прямо удалить «\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';
}
5
ответ дан Amitabha 21 August 2018 в 16:22
поделиться
  • 1
    Обратите внимание, что более безопасно использовать strnlen вместо strlen. – Mike Mertsock 30 June 2013 в 02:37
  • 2
    Комментарий к первому ответу в связанных с вопросом состояниях. Обратите внимание, что strlen (), strcmp () и strdup () являются безопасными. Альтернативы 'n' дают вам дополнительную функциональность. & Quot; – Étienne 20 November 2013 в 01:12
  • 3
    @esker нет, это не так. вставка n не волшебным образом повышает безопасность, в этом случае это фактически сделает код более опасным. Аналогично strncpy, ужасно опасная функция. Сообщение, с которым вы связались, является плохим советом. – M.M 28 October 2015 в 21:55
  • 4
    Это терпит неудачу для пустой строки (""). Также strlen() возвращает size_t не int. – alk 17 June 2017 в 09:55
  • 5
    это небезопасно для пустой строки, она будет писать с индексом -1. Не используйте это. – Jean-François Fabre 14 June 2018 в 19:38

Попробуйте следующее:

        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;
        }
0
ответ дан Balazs Kiss 21 August 2018 в 16:22
поделиться

Ниже приведен быстрый подход к удалению потенциала '\n' из строки, сохраненной в fgets(). Он использует strlen() с двумя тестами.

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'). Ref YMMV, но оба метода работают.


buffer, из оригинала fgets() не будет содержать в "\n" при некоторых обстоятельствах: A) Линия был слишком длинным для buffer, поэтому только char, предшествующий '\n', сохраняется в buffer. В потоке остаются непрочитанные символы. B) Последняя строка в файле не заканчивалась символом '\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 отредактировал его, чтобы включить код, подобный проверке этого ответа на "".
    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
  3. sprintf(buffer,"%s",buffer); - неопределенное поведение: Ref . Кроме того, он не сохраняет никаких ведущих, разделяющих или завершающих пробелов. Теперь удален .
  4. [Редактировать из-за хорошего ответа ] Нет проблем с 1 лайнером buffer[strcspn(buffer, "\n")] = 0;, отличным от производительности, по сравнению с strlen(). Производительность при обрезке обычно не является проблемой, поскольку код вводит I / O - черную дыру процессорного времени. Если следующий код нуждается в длине строки или имеет высокую производительность, используйте этот подход strlen(). Иначе strcspn() является прекрасной альтернативой.
15
ответ дан chux 21 August 2018 в 16:22
поделиться
char name[1024];
unsigned int len;

printf("Enter your name: ");
fflush(stdout);
if (fgets(name, sizeof(name), stdin) == NULL) {
    fprintf(stderr, "error reading name\n");
    exit(1);
}
len = strlen(name);
if (name[len - 1] == '\n')
    name[len - 1] = '\0';
0
ответ дан draebek 21 August 2018 в 16:22
поделиться
  • 1
    Это терпит неудачу для пустой строки (""). Также strlen() возвращает size_t не int. – alk 17 June 2017 в 09:56

Нижеприведенная функция является частью библиотеки обработки строк, которую я поддерживаю в 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

0
ответ дан Fehmi Noyan ISI 21 August 2018 в 16:22
поделиться
  • 1
    Вы должны удалить * в *src++; и сделать bad, token и d const char *. Также почему не использовать strchr вместо zChrSearch? *src не может быть '\0' в вашей функции zStrrmv. – chqrlie 17 August 2016 в 14:43
  • 2
    Спасибо @chqrlie! обновил код, чтобы отразить ваши предложения ..... zstring начал как забавный проект с целью создания библиотеки обработки строк без использования каких-либо стандартных функций библиотеки, поэтому я не использовал strchr – Fehmi Noyan ISI 21 October 2016 в 08:30
  • 3
  • 4
    – Jonathan Leffler 14 October 2018 в 07:53
 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

Вы должны попробовать. Этот код в основном проходит через строку до тех пор, пока не найдет «\n». Когда он будет найден, '\n' будет заменен на нулевой символ terminator '\ 0'

Обратите внимание, что вы сравниваете символы, а не строки в этой строке, тогда нет необходимости использовать strcmp ():

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

, поскольку вы будете использовать одинарные кавычки, а не двойные кавычки. Здесь ссылка о одиночных или двойных кавычках, если вы хотите узнать больше

1
ответ дан Matheus Martins Jerônimo 21 August 2018 в 16:22
поделиться

Для одиночного '\n' trmming,

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

для множественной обрезки '\n',

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

}
1
ответ дан Naveen Kumar 21 August 2018 в 16:22
поделиться
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
77
ответ дан P.P. 21 August 2018 в 16:22
поделиться
  • 1
    Вероятно, будет исключение, если строка пуста, не так ли? Как индекс за пределами диапазона. – Edward Olamisan 31 May 2013 в 04:26
  • 2
    @EdwardOlamisan, строка никогда не будет пуста. – James Morris 15 July 2013 в 00:27
  • 3
    @James Morris В необычных случаях fgets(buf, size, ....) - & gt; strlen(buf) == 0. 1) fgets() читается как первый char a '\0'. 2) size == 1 3) fgets() возвращает NULL, тогда содержимое buf может быть любым. (Код OP действительно проверяет значение NULL, хотя) Предложите: size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0'; – chux 2 July 2014 в 15:00
  • 4
    Что делать, если строка пуста? ln будет -1, за исключением того факта, что size_t не имеет знака, поэтому записывается в случайную память. Я думаю, вы хотите использовать ssize_t и проверить ln is & gt; 0. – abligh 16 March 2015 в 23:38
  • 5
    @ legends2k: поиск значения времени компиляции (особенно нулевого значения, как в strlen) может быть реализован гораздо эффективнее, чем простой поиск char-by-char. По этой причине я считаю это решение лучше, чем на основе strchr или strcspn. – AnT 29 March 2016 в 18:28

Тим Čas один лайнер поражает строки, полученные вызовом 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;
}

Для тех, кто ищет эквивалент Perl chomp в C, я думаю, что это он (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;
}
0
ответ дан Philippe A. 21 August 2018 в 16:22
поделиться
  • 1
    ", потому что вы знаете, что они содержат одну новую строку в конце. & quot; - & GT; Он работает даже тогда, когда нет '\n' (или строка ""). – chux 18 November 2015 в 18:59
  • 2
    В ответ на ваш первый комментарий, мой ответ сохраняет это. Мне пришлось сбросить сброс в strrcspn, если нет \n. – Philippe A. 18 November 2015 в 19:14
  • 3
    Зачем использовать goto end; вместо return len;? – chqrlie 17 August 2016 в 14:48
  • 4
    @chqrlie Мне нужно было выйти из этой неэлегантной 2-уровневой петли, в которую я попал. Ущерб был нанесен. Почему бы не перейти? – Philippe A. 29 November 2016 в 21:48
  • 5
    У вас есть два типа goto s в вашем коде: бесполезный goto, который можно заменить выражением return и назад goto, который считается злым. Использование strchr помогает реализовать strrspn и strrcspn более простым способом: size_t strrspn(const char *s, const char *accept) { size_t len = strlen(s); while (len > 0 && strchr(accept, s[len - 1])) { len--; } return len; } и size_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; } – chqrlie 30 November 2016 в 00:04

Если использование 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 не следует пренебрегать.

0
ответ дан sjsam 21 August 2018 в 16:22
поделиться

Возможно, самое простое решение использует одну из моих любимых малоизвестных функций, 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'.

300
ответ дан Tim Čas 21 August 2018 в 16:22
поделиться
  • 1
    Это даже обрабатывает редкий buffer, чем начинается с '\0', что вызывает горе для подхода buffer[strlen(buffer) - 1] = '\0';. – chux 11 February 2015 в 20:39
  • 2
    @chux: Да, я хочу, чтобы больше людей знали о strcspn(). Одна из наиболее полезных функций в библиотеке, ИМО. Я решил написать и опубликовать кучу обычных C-хаков, подобных этому сегодня; реализация strtok_r с использованием strcspn и strspn была одной из первых: codepad.org/2lBkZk0w ( Предупреждение: Я не могу гарантировать, что это без ошибок , он был написан спешно и, вероятно, есть несколько). Я не знаю, где я еще опубликую их, но я намерен сделать это в духе знаменитых «бит-скрипучих хаков». – Tim Čas 11 February 2015 в 20:44
  • 3
    Посмотрел способы надежно trim fgets() . Этот strcspn(), по-видимому, является only правильным однострочным. strlen быстрее - хотя и не так просто. – chux 11 February 2015 в 21:04
  • 4
    @sidbushes: вопрос, как в заголовке, так и в контенте, запрашивает о завершающей новой строке из fgets() ввода . Который всегда является первой новой линией. – Tim Čas 9 April 2017 в 13:44
  • 5
    @sidbushes: Я понимаю, откуда вы пришли, но я не могу нести ответственность за результаты поиска Google для определенных условий. Поговорите с Google, а не со мной. – Tim Čas 8 May 2017 в 12:08
Другие вопросы по тегам:

Похожие вопросы: