read () de stdin no ignora la nueva línea

5 minutos de lectura

avatar de usuario
s_itbhu

Estoy usando la siguiente declaración condicional para leer desde la entrada estándar.

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

Al ingresar datos desde la entrada estándar, generalmente el usuario presiona enter cuando termina. Pero read() considera ‘\n’ como entrada también en cuyo caso n = 1 y el condicional no se evalúa como falso. ¿Hay alguna manera de hacer que la evaluación condicional sea falsa cuando el usuario presiona enter (sin ingresar nada) en la entrada estándar además de verificar el contenido de buf. ¿Hay alguna otra función además de read() que podría usar para este propósito??

De hecho, ¿cuál puede ser una forma de que la lectura determine el final de la entrada cuando la entrada proviene de la entrada estándar (stdin)?

  • ¿Que estás tratando de hacer? ¿Leer cada carácter uno a la vez?

    – GManNickG

    6 de agosto de 2009 a las 7:04

  • No, como puede ver en el condicional, estoy leyendo de la entrada estándar en un búfer (y tal vez diga que solo lo escribo en la salida estándar). Quiero detenerme cuando el usuario no ingresa nada y solo presiona enter.

    – s_itbhu

    6 de agosto de 2009 a las 7:20

  • Ah, ya veo. Lo leí mal.

    – GManNickG

    6 de agosto de 2009 a las 7:23

  • Explique por qué está buscando una forma de determinar una línea en blanco sin examinar el búfer. Realmente no veo la razón de ello. Siempre puede escribir su propia función que examina el búfer, pero devuelve 0 al final del archivo, -1 en caso de error, y N’ en una línea en blanco. Si lee su búfer carácter por carácter, entonces puede usar la función estándar para este propósito lista para usar; pero entonces eso es equivalente a examinar tu búfer ;-).

    – Inshallah

    6 de agosto de 2009 a las 7:30

  • Básicamente, quería saber si era posible terminar al final de la línea desde la entrada estándar sin examinar el búfer. Como si leyera de un archivo, cuando ocurre EOF, la llamada de lectura finaliza automáticamente. En ese caso, no es necesario comprobar el contenido del búfer.

    – s_itbhu

    7 de agosto de 2009 a las 4:33

Usted pregunta:

Al ingresar datos desde la entrada estándar, generalmente el usuario presiona enter cuando termina. Pero read() también considera ‘\n’ como entrada, en cuyo caso n = 1 y el condicional no se evalúa como falso.

El primer punto es ciertamente cierto. La tecla Intro es equivalente a la tecla de nueva línea, por lo que cuando el usuario presiona Intro, el teclado genera un carácter de nueva línea y el read() Por lo tanto, la función devuelve ese carácter. Es crucial que lo haga.

Por lo tanto, su condición es incorrecta: una línea vacía incluirá la nueva línea y, por lo tanto, el recuento de bytes será uno. De hecho, solo hay una manera de obtener la read() llame para devolver 0 cuando la entrada estándar es el teclado, y eso es para escribir el carácter ‘EOF’, generalmente control-D en Unix, control-Z en DOS. En Unix, el controlador de terminal interpreta ese carácter como “enviar los datos de entrada anteriores al programa incluso si aún no hay una nueva línea”. Y si el usuario no ha escrito nada más en la línea, entonces el retorno de read() será cero. Si la entrada proviene de un archivo, luego de leer los últimos datos, las lecturas posteriores devolverán 0 bytes.

Si la entrada proviene de una tubería, luego de leer todos los datos en la tubería, el read() la llamada se bloqueará hasta que se cierre el último descriptor de archivo que puede escribir en la canalización; si ese descriptor de archivo está en el proceso actual, entonces el read() colgará para siempre, aunque el proceso colgado nunca podrá write() al descriptor del archivo, suponiendo un proceso de un solo subproceso, por supuesto.

  • Es fundamental que explique por qué el valor de retorno de 0 de read()/recv() es distinto de una línea vacía. Si obtiene 0 de read()/recv(), significa que está al final de todas las entradas (es decir, está cerrado, no se pueden agregar nuevas entradas).

    – Será

    6 de agosto de 2009 a las 8:01

  • NB: hay dispositivos en los que obtener read() devolver cero no significa que no se puedan agregar más entradas. Mostrando mi antigüedad: los dispositivos de cinta magnética eran uno de esos. Actualmente, los terminales son otro. Con opciones esotéricas en open() (como O_NONBLOCK) puede obtener ese comportamiento en otros dispositivos. Pero una línea vacía es, por definición, una línea que contiene solo un carácter de nueva línea: el marcador de final de línea (también conocido como carácter de nueva línea) es parte de los datos. Si no quieres eso en tu programa, tienes que eliminarlo. Solamente gets() elimina la nueva línea por ti, pero deberías nunca usarlo en el código de producción.

    –Jonathan Leffler

    6 de agosto de 2009 a las 11:13

avatar de usuario
cuarenta y dos

Sólo tipo >1 en vez de !=0

los únicos falsos positivos son respuestas de un solo carácter seguidas de una interrupción (EOF)

Tienes que comprobar el búfer tú mismo. p.ej

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

}

o use, por ejemplo, fgets, y simplemente elimine el \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 
}

avatar de usuario
qrdl

es mejor que uses fgets() para su tarea (captar la entrada del usuario), pero incluso fgets() almacena el carácter de nueva línea en el búfer.

Sin embargo, si hay una nueva línea, puede estar seguro de que es el último carácter de la cadena, por lo que es fácil eliminarlo.

avatar de usuario
Michael Foukarakis

Estoy bastante seguro de que no hay forma de hacerlo sin examinar el contenido del búfer. Incluso readline() hace precisamente eso. ¿Por qué te opones a eso, de todos modos?

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad