Nano Hash - криптовалюты, майнинг, программирование

read() из стандартного ввода не игнорирует новую строку

Я использую следующий условный оператор для чтения из стандартного ввода.

if ((n = read(0,buf,sizeof(buf))) != 0)

При вводе данных из стандартного ввода пользователь, как правило, нажимает ввод, когда закончит. Но read() также рассматривает '\n' как ввод, и в этом случае n = 1 и условное выражение не оценивается как ложное. Есть ли способ сделать условную оценку ложной, когда пользователь нажимает ввод (ничего не вводя) на стандартном вводе, кроме проверки содержимого buf. Есть ли какая-либо другая функция, кроме read(), которую я мог бы использовать для этой цели??

В этом отношении, каким может быть способ для чтения определить конец ввода, когда ввод поступает из стандартного ввода (stdin)?

06.08.2009

  • Что ты пытаешься сделать? Читать каждый символ по одному? 06.08.2009
  • Нет, как вы можете видеть из условия, я читаю из стандартного ввода в буфер (и, может быть, просто записываю его обратно в стандартный вывод). Я хочу остановиться, когда пользователь ничего не вводит и просто нажимает ввод. 06.08.2009
  • А, теперь я вижу. Я неправильно прочитал. 06.08.2009
  • Пожалуйста, объясните, почему вы ищете способ определить пустую строку без изучения буфера. Я действительно не вижу в этом причины. Вы всегда можете написать свою собственную функцию, которая проверяет буфер, но возвращает 0 в конце файла, -1 в случае ошибки, и '\n' в пустой строке. Если вы читаете свой буфер посимвольно, то вы можете использовать стандартную функцию для этой цели из коробки; но тогда это эквивалентно проверке вашего буфера ;-). 06.08.2009
  • По сути, я хотел знать, можно ли завершиться в конце строки из стандартного ввода без изучения буфера. Как если бы я читал из файла, когда происходит EOF, вызов чтения автоматически завершается. В этом случае нет необходимости проверять содержимое буфера. 07.08.2009

Ответы:


1

Ты спрашиваешь:

При вводе данных из стандартного ввода пользователь, как правило, нажимает ввод, когда закончит. Но read() также рассматривает '\n' как ввод, и в этом случае n = 1, а условное выражение не оценивается как ложное.

Первый пункт, безусловно, верен. Клавиша ввода эквивалентна клавише новой строки, поэтому, когда пользователь нажимает клавишу ввода, клавиатура генерирует символ новой строки, и поэтому функция read() возвращает этот символ. Крайне важно, чтобы он это сделал.

Следовательно, ваше условие ошибочно - пустая строка будет включать новую строку, и поэтому количество байтов будет равно единице. Действительно, есть только один способ заставить вызов read() возвращать 0, когда стандартным вводом является клавиатура, и это набрать символ 'EOF' - обычно Control-D в Unix, control-Z в DOS. В Unix этот символ интерпретируется драйвером терминала как «отправить предыдущие входные данные в программу, даже если новой строки еще нет». И если пользователь больше ничего не набрал в строке, то возврат от read() будет равен нулю. Если ввод поступает из файла, то после чтения последних данных последующие чтения вернут 0 байтов.

Если ввод поступает из канала, то после того, как все данные в канале будут прочитаны, вызов read() будет заблокирован до тех пор, пока не будет закрыт последний файловый дескриптор, который может записывать в канал; если этот файловый дескриптор находится в текущем процессе, то read() будет зависать навсегда, даже если зависший процесс никогда не сможет write() к файловому дескриптору - конечно, при условии однопоточного процесса.

06.08.2009
  • Очень важно, чтобы вы объяснили, почему возвращаемое значение 0 из read()/recv() отличается от пустой строки. Если вы получаете 0 из read()/recv(), это означает, что вы находитесь в конце всех входных данных (т.е. они закрыты, новые входные данные не могут быть добавлены). 06.08.2009
  • NB: есть устройства, в которых получение read() возврата нуля не означает, что больше нельзя добавить ввод. Демонстрация моей древности - одним из таких устройств были магнитофоны. В настоящее время терминалы другие. С эзотерическими параметрами на open() (например, O_NONBLOCK) вы можете добиться такого же поведения на других устройствах. Но пустая строка по определению является строкой, содержащей только символ новой строки — маркер конца строки (также известный как символ новой строки) является частью данных. Если вы не хотите этого в своей программе, вы должны удалить его. Только gets() удалит для вас новую строку, но вы не должны никогда использовать ее в производственном коде. 06.08.2009

  • 2

    просто введите >1 вместо !=0

    единственные ложные срабатывания - это односимвольные ответы, за которыми следует прерывание (EOF)

    16.06.2011

    3

    Вы должны проверить буфер самостоятельно. например

    while((n = read(0,buf,sizeof(buf))) > 0) {
      if(buf[0] == '\n') // won't handle pressing 9 spaces and then enter
        continue;
      ... process input
    
    }
    

    или используйте, например. fgets и просто удалите \n

    while(fgets(buf,sizeof buf,stdin) != NULL) {
      char *ptr;
      size_t len;
    
      if((ptr = strchr(buf,'\n')) != NULL) //strip newline
        *ptr = 0; 
      len = strlen(buf);
      if(len == 0)
       continue;
      ... process input 
    }
    
    06.08.2009

    4

    Вам лучше использовать fgets() для своей задачи (перехват пользовательского ввода), но даже fgets() сохраняет символ новой строки в буфере.

    Однако, если есть новая строка, вы можете быть уверены, что это последний символ в строке, поэтому его легко удалить.

    06.08.2009
  • Вы не можете быть уверены, что последний символ в буфере является новой строкой, так как fgets() сохранит новую строку только в том случае, если она есть в файле. Не может быть, если последняя строка не включает его. 06.08.2009
  • @Inshalla Я имел в виду, что если новая строка находится в буфере, это наверняка последний символ. Я отредактирую свой пост, чтобы сделать его явным. 06.08.2009
  • Во-первых, здесь я работаю с файловыми дескрипторами, а не с файловыми указателями. fgets() принимает указатели на файлы. И что я хочу сделать, так это сделать условную оценку ложной, когда пользователь нажимает ввод. Здесь я также могу определить, был ли символ новой строки последним введенным символом или нет. 06.08.2009
  • Вы сказали, что читаете со стандартного ввода, поэтому не имеет значения, используете ли вы read(0, ..) или fread(..., stdin) или fgets(..., stdin). Мой пост был основан на информации, которую вы предоставили в своем вопросе. Если вы хотите остановиться на пустой строке, вы можете сделать это следующим образом: if ('\n' != *fgets(buf, sizeof(buf)-1, stdin)) 06.08.2009
  • @qrdl, который, конечно, также проверяет буфер, но может быть предпочтительнее других решений по эстетическим соображениям. 06.08.2009
  • @qrdl: ваше предложение проверить *fgets() не очень хорошая идея; если fgets() действительно обнаруживает EOF, он возвращает нулевой указатель и разыменование, которое приведет к сбою вашей программы (вероятно, формально это вызывает неопределенное поведение, и результат не является хорошим, независимо от этого). 23.08.2012

  • 5

    Я совершенно уверен, что это невозможно сделать без изучения содержимого буфера. Даже readline() делает именно это. Почему вы вообще против?

    06.08.2009
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..