Estoy leyendo un archivo usando fscanf
. Quiero ignorar los caracteres no alfabéticos como comas, \,: y puntos.
Este es mi código:
FILE *fp; fp = fopen(fl,"r"); char c[50]; while(fscanf(fp, "%s" ,c)!= EOF){ linkLst(c); } fclose(fp);
¿Cómo leo el archivo palabra por palabra ignorando los caracteres no alfabéticos?
{parte del archivo como sigue
CON RESPUESTAS:
1) ¿Qué lenguaje escrito es el más complicado del mundo? (Sugerencia: utiliza cuatro conjuntos de caracteres). (¿Es esta pregunta demasiado fácil?) >> Japonés
2) ¿Qué idioma tiene un vocabulario principalmente de origen árabe (alrededor del 70%, me han dicho), pero utiliza el alfabeto romano? (¡Me gustaría saber dónde encontraste la respuesta!) >> Maltés
3) ¿Qué lenguaje no romance usa una tilde (~) sobre la letra N? >> estonio}
Tendrá que crear una copia de la cadena que lea, filtrando los caracteres no alfanuméricos.
Después de que el scanf
haga esto
char str[50]; int index = 0; int index2 = 0; while(c[index] != '\0') { if (isalpha((unsigned char)c[index])) str[index2++] = c[index]; else{ str[index2] = '\0'; if (index2 != 0) linkLst(str); index2 = 0; } index++; } str[index2] = '\0'; if (index2 != 0) linkLst(str);
Me limitaré a leer el contenido “palabra por palabra” en lugar de preocuparme por la lista enlazada.
scanf
familia de funciones scanf
le brinda la posibilidad de realizar un análisis trivial, no hay necesidad de hacerlo carácter por carácter, ya que la funcionalidad suficiente está disponible en scanf. Si desea analizar las cadenas char por char, simplemente use fgets
y realice el análisis que necesita.
Me quedo con scanf ya que eso es lo que estás usando:
Comenzando con un archivo simple ( foo.txt ) que contiene:
¿Hola como estás?
y tratando de escanearlo:
/* NOTE: this code does NOT do what you want */ #include int main() { char foo[128]; FILE *fp; fp = fopen("foo.txt", "r"); do { sscanf(input, "%[A-Za-z0-9]", foo); fprintf(stderr, "foo: %s\n", foo); } while(1); return 0; }
Obtendrá un hello
impresión en bucle infinito porque scanf está atascado y no puede mungear el espacio después de “hola”.
Así que vamos a añadir un munger:
#include int main() { char foo[128]; char mung[128]; char rv = 0; FILE *fp; fp = fopen("foo.txt", "r"); do { rv = fscanf(fp, "%[A-Za-z0-9]%[^A-Za-z0-9]", foo, mung); if(rv == EOF) break; fprintf(stderr, "foo: %s\n", foo); }while(1); }
Así que munger mungea todo lo que no está en el conjunto de caracteres foo que estamos buscando (al poner un ^
dentro de [] el primer carácter hace que scanf niegue el contenido).
Esto imprimirá:
foo: hello foo: there foo: how foo: are foo: you
Ahora, si estamos siendo listos, podemos omitir la asignación de la variable mung:
#include int main() { char foo[128]; char rv = 0; FILE *fp; fp = fopen("foo.txt", "r"); do { rv = fscanf(fp, "%[A-Za-z0-9]%*[^A-Za-z0-9]", foo); if(rv == EOF) break; fprintf(stderr, "foo: %s\n", foo); }while(1); }
Obviamente en mis ejemplos asumí que foo tiene menos de 128 bytes. Sin embargo, no sabemos que, bueno scanf (después del estándar POSIX de 2001) le permite asignar dinámicamente la memoria para las cadenas de caracteres que debe free
más adelante, así que:
#include #include int main() { char *foo; char rv = 0; FILE *fp; fp = fopen("foo.txt", "r"); do { /* notice the & before foo, because fscanf will modify the pointer * variable itself and assign it a new pointer after allocating * the space for the string */ rv = fscanf(fp, "%m[A-Za-z0-9]%*[^A-Za-z0-9]", &foo); if(rv == EOF) break; fprintf(stderr, "foo: %s\n", foo); /* store the foo pointer somewhere for use and free it later, * if you are sticking it in a linked list, then you should * free it whenever you free the corrosponding node. * * I am just going to free it here after printing it out */ free(foo); }while(1); }
Como señala BLUEPIXY, esto no comería ningún carácter que comience con caracteres no coincidentes. Así que algo como
)) oops helo
se atascará en un bucle (null)
Lo que significa que necesitamos hacer una operación separada para que se coman las cosas:
#include #include int main() { char *foo; char rv = 0; FILE *fp; fp = fopen("foo.txt", "r"); do { /* notice the & before foo, because fscanf will modify the pointer * variable itself and assign it a new pointer after allocating * the space for the string */ rv = fscanf(fp, "%m[A-Za-z0-9]", &foo); if(rv == EOF) break; /* foo would be null if scanf didn't read anything */ if (foo) { fprintf(stderr, "foo: %s\n", foo); /* store the foo pointer somewhere for use and free it later, * if you are sticking it in a linked list, then you should * free it whenever you free the corrosponding node. * * I am just going to free it here after printing it out */ free(foo); } rv = fscanf(fp, %*[^A-Za-z0-9]"); if (rv == EOF) break; }while(1); }
(vea la página de scanf (3)) para detalles
Filtra cada personaje con la función isalpha
.
while (fscanf(fp, "%s", c) != EOF) { char* ptr = c; while (*ptr) { if (isalpha(*ptr)) { linkLst(*ptr); } ptr++; } }
Y corrija la función linkLst
para aceptar carácter por carácter en lugar de puntero de carácter.
Si linkLst
es obligatorio para char *
como parámetro, puede hacerlo así:
while (fscanf(fp, "%s", c) != EOF) { char* ptr = c; char tmp[2] = {0, 0}; while (*ptr) { if (isalpha(*ptr)) { tmp[0] = *ptr; linkLst(tmp); } ptr++; } }
Incluya el encabezado #include
que incluye una función isalpha(char c)
que devuelve true
si c
es un carácter alfabético.
if ( isalpha(c)) { // do what you wanna do } else { // ignore }
De lo contrario, puede utilizar la tabla ASCII . Usa los caracteres como si fueran int
y compáralos. Por ejemplo, para verificar si un char
es alfabético y capital, harías:
if ( c < 66 && c > 90) { // do what you wanna do } else { // ignore }
Si c
es una pestaña, haz un bucle así:
for (int i = 0; i < sizeof(c); i++) // Then use c[i] to access to char inside it { if (c[i] < 66 && c[i] > 90) // or if (isalpha(c[i]) { // do what you wanna do } else { // ignore } }
También podrías escribir:
if (c[i] < 'A' && c[i] > 'Z')
Porque gracias a la tabla ASCII, 'A' == 66
y 'Z' == 90