Looking for Code Review: Abbreviate a given string using a dictionary of acceptable abbreviations.
Notes:
Only "whole words" should be abbreviated. That is, if the word "record" can be abbreviated to "rec", "records" SHOULD NOT be abbreviated to "recs".
- A "whole word" is a sequence of alphanumeric characters.
- If the abbreviated string will not fit in the destination buffer clamp the string.
- Bonus points for allowing the substitution to be case insensitive, but also case aware. It should handle three cases, the original word all lower case, all upper case, or the first letter only being capitalized. Mixed cases can be handled in any reasonable way.
For example, if the dictionary contains: "record"->"rec":
- "record" should be replaced with "rec"
- "Record" should be replaced with "Rec"
- "RECORD" should be replaced with "REC"
- "ReCord" can be replaced with "rec", "Rec" or "REC"
@param str
- source string to abbreviate (NULL terminated)@param str_abbr
- destination buffer to store abbreviated version of 'str'@param str_abbr_len
- length of 'str_abbr' buffer, including NULL terminator@param dictionary
- array of acceptable abbreviations@param dictionary_len
- number of items in dictionary
abbr.h
#include <stdlib.h>
typedef struct
{
const char * full;
const char * abbr;
} dictionary_t;
void abbreviate_string(const char * str, char * str_abbr, size_t str_abbr_len, dictionary_t * dictionary, size_t dictionary_len);
const char* CheckMatchinDictionary(char *result, dictionary_t* dictionary, size_t dictionary_len );
abbr.c
#include "abbr.h"
void abbreviate_string(const char * str, char * str_abbr, size_t str_abbr_len, dictionary_t * dictionary, size_t dictionary_len)
{
const char* inputString = str;
char ** wordArray = NULL;
int numOfWords = 0;
char* word = strtok (inputString," ,-.:;");
while (word != NULL)
{
wordArray = realloc (wordArray, sizeof (char*) * ++numOfWords);
//Check memory allocation
if(wordArray == NULL)
exit(-1);
wordArray[numOfWords - 1] = word;
word = strtok (NULL, " ,-.:;");
}
memset(str_abbr, 0, str_abbr_len - 1);
int i;
int stringLength = 0;
for(i=0; i < numOfWords; ++i )
{
const char* result = CheckMatchinDictionary(wordArray[i], dictionary, dictionary_len );
// Append to the str_abbr only if fits in the destination buffer
if( stringLength < str_abbr_len - 1)
{
if(result != NULL)
{
strcat(str_abbr, result);
stringLength += strlen(result);
}
else
{
strcat(str_abbr, wordArray[i]);
stringLength += strlen(wordArray[i]);
}
strcat(str_abbr, " ");
stringLength += 1;
}
else
{
if(result != NULL)
strncat(str_abbr, result, str_abbr_len - stringLength - 1);
else
strncat(str_abbr, wordArray[i], str_abbr_len - stringLength - 1 );
}
}
//printf("The abbreviated string is %s\n", str_abbr);
}
// Function to check the match from the dictionary
const char* CheckMatchinDictionary(char *input, dictionary_t* dictionary, size_t dictionary_len )
{
unsigned int index;
for(index=0; index < dictionary_len; ++index)
{
if(strcmp(dictionary[index].full, input) == 0)
return dictionary[index].abbr;
else if(strcasecmp(dictionary[index].full, input) == 0)
{
size_t length = strlen(dictionary[index].abbr);
char* substr = malloc(sizeof(char) * length);
strncpy(substr, input, length);
substr[length + 1] = '\0';
return substr;
}
}
return NULL;
}
main
#include <string.h>
#include <stdio.h>
#include "abbr.h"
int main(void)
{
/* Sample Dictionary */
dictionary_t dictionary[] =
{
{"record", "rec"},
{"maximum", "max"},
{"minimum", "min"},
{"number", "no"}
};
char str[100];
char str_abbr[100];
strcpy(str, "maximum record rate is:");
abbreviate_string(str, str_abbr, sizeof(str_abbr), dictionary, sizeof(dictionary) / sizeof(dictionary[0]));
printf("%s -> %s\n", str, str_abbr);
return 0;
}
abbr.h
from the review. \$\endgroup\$main.c
part. Suggest reviewing After you ask your question \$\endgroup\$