2009-12-23 35 views
5

Ya tengo un código para leer un archivo de texto usando fscanf(), y ahora lo necesito modificado para que los campos que anteriormente estaban libres de espacio en blanco tengan que permitir el espacio en blanco. El archivo de texto es, básicamente, en forma de:¿Puede fscanf() leer espacios en blanco?

título: DATOS
título: DATOS
etc ...

el cual es básicamente analiza sintácticamente usando fgets(inputLine, 512, inputFile); sscanf(inputLine, "%*s %s", &data);, la lectura de los campos de datos y ignorando los títulos, pero ahora algunos de los campos de datos deben permitir espacios. Todavía tengo que ignorar el título y el espacio en blanco inmediatamente después, pero luego leo en el resto de la línea, incluido el espacio en blanco.

¿Hay alguna forma de hacerlo con la función sscanf()?

Si no es así, ¿cuál es el cambio más pequeño que puedo hacer en el código para manejar correctamente el espacio en blanco?

ACTUALIZACIÓN: Edité la pregunta para reemplazar fscanf() con fgets() + sscanf(), que es lo que mi código está realmente usando. Realmente no pensé que fuera relevante cuando escribí la pregunta por qué lo simplifiqué a fscanf().

+0

Si solía analizarlo con 'scanf', entonces también podría analizar previamente algo como' title: DATA title: DATA' (es decir, todo en una línea). Si desea permitir espacios en blanco en valores, ¿cuál será el terminador? Si newline, parece que su código original era un poco flojo ... –

+0

Además, ¿cómo decide el tamaño del búfer 'str' y cómo se asegura de que no se desborde? –

+0

sí, cuando los DATOS pueden tener espacios en blanco, se usará la nueva línea como el terminador –

Respuesta

11

Si no puede utilizar fgets() utilizar el especificador %[ conversión (con la "opción de exclusión"):

char buf[100]; 
fscanf(stdin, "%*s %99[^\n]", buf); 
printf("value read: [%s]\n", buf); 

Pero fgets() es mucho mejor.


Editar: versión con fgets() + sscanf()

char buf[100], title[100]; 
fgets(buf, sizeof buf, stdin); /* expect string like "title: TITLE WITH SPACES" */ 
sscanf(buf, "%*s %99[^\n]", title); 
+3

Para este caso particular, ¿cómo es 'fgets'" mucho mejor "? –

+1

Bueno ... los requisitos siguen cambiando (primero no había espacio en la cadena). No es mejor para este caso en particular, pero es mejor usar 'fgets()' ahora, en antecipación para el próximo cambio de requisitos :) – pmg

+0

Actualicé la pregunta para mostrar que realmente uso fgets() para leer la línea, luego sscanf() para analizarlo, pero ¿hay una manera mejor de analizar la línea después de fgets()? –

3

Le sugiero que deje de usar fscanf() y comience a usar fgets() (que lee toda una línea) y luego analice la línea que se ha leído.

Esto le permitirá una libertad considerablemente mayor en lo que respecta al análisis de entradas con formato incorrecto.

+0

Actualicé la pregunta para mostrar que realmente uso fgets(), pero no entiendo exactamente qué ayudará. Todavía tengo que analizar la línea una vez que la haya leído. –

+1

Una vez que tenga toda la cadena, camínela usted mismo en lugar de usar sscanf. –

+0

Sí, hazlo con punteros o incluso mejor usa expresiones regulares. Si usaste C++, hubiera sugerido un impulso; No conozco ninguna buena biblioteca C, pero debe haber alguna. Escuché que POSIX los apoya. –

2

Lo más sencillo sería emitir una

fscanf("%*s"); 

para descartar la primera parte y luego simplemente llamar a los fgets:

fgets(str, stringSize, filePtr); 
3

Si usted insiste en el uso de scanf, y suponiendo que desea salto de línea como terminador, se puede hacer esto:

scanf("%*s %[^\n]", str); 

Tenga en cuenta, sin embargo, que lo anterior, utilizado exactamente como está escrito, es una mala idea porque th No hay nada que precaverse contra str sobrevolando (como scanf no conoce su tamaño). Por supuesto, puede establecer un tamaño máximo predefinido y especificarlo, pero luego su programa puede no funcionar correctamente en alguna entrada válida.

Si el tamaño de la línea, definido por el formato de entrada, no está limitado, su única opción práctica es usar fgetc para leer datos char por char, reasignando periódicamente el búfer sobre la marcha. Si lo hace, modifíquelo para dejar caer todos los caracteres de lectura hasta que el primer espacio en blanco sea bastante trivial.

2

Un %s especificador en fscanf omite cualquier espacio en blanco en la entrada, luego lee una cadena de caracteres que no son de espacio en blanco hasta y sin incluir el siguiente carácter de espacio en blanco.

Si desea leer una nueva línea, puede usar %[^\n] como especificador. Además, un '' en la cadena de formato omitirá espacios en blanco en la entrada. Así que si usa

fscanf("%*s %[^\n]", &str); 

leerá la primera cosa en la línea hasta el primer espacio en blanco ("Título:" en su caso), y tirarlo a la basura, entonces leerá caracteres de espacio en blanco y tirar a la basura, luego leerá todos los caracteres hasta una nueva línea en str, que suena como lo que quiere.

tener cuidado de que no se desborde str - es posible que desee utilizar

fscanf("%*s %100[^\n]", &str) 

para limitar la longitud máxima de la cadena que va a leer (100 caracteres, sin contar la LUN que termina aquí).

+0

Sé que este es un corto ejemplo, pero ¿tienes que usar la dirección de str? Yo pensaría que esto también funcionaría. 'fscanf ("% * s% [^ \ n] ", str);' – cokedude

1

Estás corriendo contra los límites de lo que es bueno para la familia *scanf. Con cambios bastante mínimos, podría intentar usar los módulos de exploración de cadenas de Dave Hanson's C Interfaces and Implementations. Esto es una actualización del lenguaje de programación Icon, un lenguaje de procesamiento de cadenas extremadamente simple y poderoso en el cual Hanson y otros trabajaron en Arizona. La salida de sscanf no será demasiado severa, y es más simple, más fácil de trabajar y más poderosa que las expresiones regulares. El único inconveniente es que el código es un poco difícil de seguir sin el libro — pero si se hace mucha programación en C, vale la pena tener el libro.

Cuestiones relacionadas