Removing special characters from fscanf string in C

c, scanf

Solution

You can give `x` to a function like this. First simple version for sake of understanding:

// header needed for isalpha()
#include <ctype.h>

void condense_alpha_str(char *str) {
  int source = 0; // index of copy source
  int dest = 0; // index of copy destination

  // loop until original end of str reached
  while (str[source] != '\0') {
    if (isalpha(str[source])) {
      // keep only chars matching isalpha()
      str[dest] = str[source];
      ++dest;
    }
    ++source; // advance source always, wether char was copied or not
  }
  str[dest] = '\0'; // add new terminating 0 byte, in case string got shorter
}

It will go through the string in-place, copying chars which match `isalpha()` test, skipping and thus removing those which do not. To understand the code, it's important to realize that C strings are just `char` arrays, with byte value 0 marking end of the string. Another important detail is, that in C arrays and pointers are in many (not all!) ways same thing, so pointer can be indexed just like array. Also, this simple version will re-write every byte in the string, even when string doesn't actually change.

Then a more full-featured version, which uses filter function passed as parameter, and will only do memory writes if str changes, and returns pointer to `str` like most library string functions do:

char *condense_str(char *str, int (*filter)(int)) {

  int source = 0; // index of character to copy

  // optimization: skip initial matching chars
  while (filter(str[source])) {
    ++source; 
  }
  // source is now index if first non-matching char or end-of-string

  // optimization: only do condense loop if not at end of str yet
  if (str[source]) { // '\0' is same as false in C

    // start condensing the string from first non-matching char
    int dest = source; // index of copy destination
    do {
      if (filter(str[source])) {
        // keep only chars matching given filter function
        str[dest] = str[source];
        ++dest;
      }
      ++source; // advance source always, wether char was copied or not
    } while (str[source]);
    str[dest] = '\0'; // add terminating 0 byte to match condenced string

  }

  // follow convention of strcpy, strcat etc, and return the string
  return str;
}

Example filter function:

int isNotAlpha(char ch) {
    return !isalpha(ch);
}

Example calls:

char sample[] = "1234abc";
condense_str(sample, isalpha); // use a library function from ctype.h
// note: return value ignored, it's just convenience not needed here
// sample is now "abc"
condense_str(sample, isNotAlpha); // use custom function
// sample is now "", empty

// fscanf code from question, with buffer overrun prevention
char x[100];
while (fscanf(inputFile, "%99s", x) == 1) {
  condense_str(x, isalpha); // x modified in-place
  ...
}

reference:

Read int isalpha ( int c ); manual:

Checks whether c is an alphabetic letter. Return Value: A value different from zero (i.e., true) if indeed c is an alphabetic letter. Zero (i.e., false) otherwise

Problem

I'm currently using the following code to scan each word in a text file, put it into a variable then do some manipulations with it before moving onto the next word. This works fine, but I'm trying to remove all characters that don't fall under `A-Z / a-z.` e.g if `"he5llo"` was entered I want the output to be `"hello"`. If I can't modify `fscanf` to do it is there way of doing it to the variable once scanned? Thanks. ``` while (fscanf(inputFile, "%s", x) == 1) ```

Original source

Related problems