Cómo ignorar los caracteres no alfabéticos en c cuando se lee el archivo

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:

mal ejemplo 1:

 /* 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); } 

Actualizar

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