Friday, April 19, 2013

How to remove characters from a c++ string

Formatting strings in C++

Sometimes you may want to filter a string and remove some characters that appear on that string.
the algorithm library is good for doing just things like that.
In this example I create a string called text with the initial value specified in the quotes.
std::string text("ex-ample-/");
the char array filterChars is used to specify the characters we wish to remove.
 char filterChars[] = "-/";
std::remove iterates over the text string from the first character (including) to the last characters (not including) and removes the character specified in filterChars. We also want to remove the last character if it is in our filter and we will see what to do in order to achieve that later. The result of std::remove is in iterator to the element that follows the last element not removed.
 for (unsigned int i = 0; i < strlen(filterChars); ++i)
 {
  std::remove(text.begin(), text.end(), filterChars[i]);
 }
The result is that "ex-ample-/" turns to "example/-/" This is because remove traverses from the beginning to the end only taking characters that is not in the filter. and it keeps the last '/' character. To solve the problem of std::remove not working on the last character we give the result iterator to the erase function. The erase function will erase all characters in the range between remove result and the actual end of our string, in our case it is the last two characters "-/".
 for (unsigned int i = 0; i < strlen(filterChars); ++i)
 {
  text.erase(std::remove(text.begin(), text.end(), filterChars[i]), text.end());
 }


The needed libraries for this code are:

#include <algorithm>
#include <string>

The result of running this code is:

text now contains "example"

Thursday, April 18, 2013

Run your C program using configuration files


Main idea

Instead of using command parameters for your application you can setup a config file or even multiple config files. This is the kind of code that is most useful in console application. It allows to test or run your software in various ways. In this manner you can configure strings, numbers and enable/disable flags to your application using a file you can edit in any text editor. You can change the way your application behaves without recompiling it and it can be very helpful for testing purposes. It is a very easy code to understand, and add configuration variables into.

The config file

For example use the following text in a file called configuration_1.cfg The separator character in this example is the equal sign, but it can also be colon, tab or space.
# This is a comment
# Configuration file number 1
MyFlag=Enabled
MyString=config file is useful
MyNumber=43

The coding part

First we should define the maximum length of lines we want to work with. I also like to to work with booleans as ints with values of 1 for true and 0 for false. so i will define the following.
#define MAX_LINE_LENGTH         256
#define TRUE  1
#define FALSE 0
A global configuration structure of type config_st can be used to store the parameters after they are parsed from the file. extend your application by adding additional variables that it needs to this structure.
typedef struct config_s
{
 char configFileName[60];
 int b_Flag;
 int myNumber;
 char myString[MAX_LINE_LENGTH];
}config_st;

To use this structure as a global variables add the following to your c file.

config_st g_config;

parsing the config file

The parseConfigFile function iterates over the config file line by line reading the parameters into a global config state. On each line the first word is read into the param variable and the text after the separator character is read into the value variable. the if-else if logic that comes after that handles each variable according to it's type.
void parseConfigFile()
{
 // parsing configuration file
 char next_line[MAX_LINE_LENGTH];
 char* value, *param; 
 int line = 0;
 FILE * fd = fopen(g_config.configFileName, "r");
 if (!fd) {
  //could not open the file
  return;
 }
 while (fgets(next_line, MAX_LINE_LENGTH, fd)) {
  line++;
  if ((next_line[0] == '#') || (next_line[0] == '\n')) {
   // skip
  } else {
   //read from the line into param until the first separator
   param = strtok(next_line," :=\t");
   // continue tokenizing next_line until end of line is reached
   value = strtok(NULL,"\n");
   if ( (param == NULL) || (value == NULL) ) {
    continue;
   }
   else if ( strcmp(param, "MyFlag") == 0 ) {
    setTrueIfEnabled(value, &g_config.b_Flag);
   }
   else if ( strcmp(param, "MyString") == 0 ) {
    strcpy(g_config.myString, value);
   }
   else if( strcmp(param, "MyNumber") == 0 ) {
    g_config.myNumber = atoi(value);
   }
  }
 }
 //close the file
 fclose(fd);
}

Helper functions

the setTrueIfEnabled helper function is used to set boolean flags
void setTrueIfEnabled(const char * key,int * result)
{
 if (strcmp(key, "Enabled") == 0)
  *result = TRUE;
 else
  *result = FALSE;
}

Required headers

Add the needed include files to your program.

#include <string.h>
#include <stdlib.h>

Main program example

Here is a simple main example that uses the config file parser, I hard code the file name here but it can be a command parameter if you use several configuration files.
int main(int argc, char **argv)
{
 sprintf(g_config.configFileName ,"%s", "configuration_1.cfg");
 parseConfigFile();
 printf("myNumber is %d\n",g_config.myNumber);
 printf("myString is %s\n",g_config.myString);
 printf("MyFlag is %d\n",g_config.b_Flag);
 return 0;
}

Program output

myNumber is 43
myString is config file is useful
MyFlag is 1