Kyle
Kyle

Reputation: 3042

String replace in C?

Write a program that takes nouns and forms their plurals on the basis of these rules: a. If noun ends in “y” remove the “y” and add “ies” b. If noun ends in “s” , “ch”, or “sh”, add “es” c. In all other cases, just add “s” Print each noun and its plural. Try the following data: chair
dairy boss circus fly dog church clue dish

This is what I've got so far but it just isn't quite functioning like it's supposed to:

#include<stdlib.h>
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#define SIZE    8

char *replace_str(char *str, char *orig, char *rep)
{
    static char buffer[4096];
    char *p;
    if(!(p = strstr(str, orig)))
        return str;
    strncpy(buffer, str, p-str);
    buffer[p-str] = '\0';
    sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
    return buffer;
}

int main(void)
{
    char plural[SIZE];
    printf("Enter a noun: ");
    scanf("%c",&plural);
    bool noreplace = false;

    puts(replace_str(plural, "s","es"));
    puts(replace_str(plural, "sh","es"));
    puts(replace_str(plural, "ch","es"));
    puts(replace_str(plural, "y", "ies"));
    if(noreplace) {
    puts(replace_str(plural, "","s"));
    }
    system("pause");
    return 0;
}

I haven't taken a C class in a while can anyone help me out? Thanks.

Upvotes: 1

Views: 13541

Answers (5)

paxdiablo
paxdiablo

Reputation: 881363

For a start, scanf("%c") gets a single character, not a string. You should use fgets for that, along the lines of:

fgets (buffer, SIZE, stdin);

// Remove newline if there.

size_t sz = strlen(buffer);
if (sz > 0 && buffer[sz-1] == '\n') buffer[sz-1] = '\0';

Once you've fixed that, we can turn to the function which pluralises the words along with a decent test harness. Make sure you keep your own main (with a fixed input method) since there's a couple of things in this harness which will probably make your educator suspect it's not your code. I'm just including it for our testing purposes here.

Start with something like:

#include <stdio.h>
#include <string.h>

char *pluralise(char *str) {
    static char buffer[4096];
    strcpy (buffer, str);
    return buffer;
}

int main(void) {
    char *test[] = {
        "chair", "dairy", "boss", "circus", "fly",
        "dog", "church", "clue", "dish"
    };

    for (size_t i = 0; i < sizeof(test)/sizeof(*test); i++)
        printf ("%-8s -> %s\n", test[i], pluralise(test[i]));

    return 0;
}

This basically just gives you back exactly what you passed in but it's a good start:

chair    -> chair
dairy    -> dairy
boss     -> boss
circus   -> circus
fly      -> fly
dog      -> dog
church   -> church
clue     -> clue
dish     -> dish

The next step is to understand how to detect a specific ending and how to copy and modify the string to suit. The string is an array of characters of the form:

  0   1   2   3   4   5
+---+---+---+---+---+---+
| c | h | a | i | r | $ |
+---+---+---+---+---+---+

where $ represents the null terminator \0. The numbers above give the offset from the start or the index that you can use to get a character from a particular position in that array. So str[3] will give you i.

Using that and the length of the string (strlen(str) will give you 5), you can check specific characters. You can also copy the characters to your target buffer and use a similar method to modify the end.

Like any good drug pusher, I'm going to give you the first hit for free :-)

char *pluralise(char *str) {
    static char buffer[4096];           // Risky, see below.

    size_t sz = strlen(str);            // Get length.
    if (sz >= 1 && str[sz-1] == 'y') {  // Ends with 'y'?
        strcpy(buffer, str);            // Yes, copy whole buffer,
        strcpy(&(buffer[sz-1]), "ies"); //   overwrite final bit,
        return buffer;                  //   and return it.
    }
    strcpy(buffer, str);                // If no rules matched,
    strcat(buffer, "s");                //   just add "s",
    return buffer;                      //   and return it.
}

Of particular interest there is the sequence:

strcpy(buffer, str);
strcpy(&(buffer[sz-1]), "ies");

The first line makes an exact copy of the string like:

  0   1   2   3   4   5
+---+---+---+---+---+---+
| d | a | i | r | y | $ |
+---+---+---+---+---+---+

The second line copies the "ies" string into the memory location of buffer[sz-1]. Since sz is 5, that would be offset 4, resulting in the following change:

  0   1   2   3   4   5
+---+---+---+---+---+---+
| d | a | i | r | y | $ |
+---+---+---+---+---+---+---+---+
                | i | e | s | $ |
                +---+---+---+---+

so that you end up with dairies.

From that, you should be able to use the same methods to detect the other string endings, and do similar copy/modify operations to correctly pluralise the strings.


Keep in mind that this is basic code meant to illustrate the concept, not necessarily hardened code that I would use in a production environment. For example, the declaration static char buffer[4096] has at least two problems that will occur under certain circumstances:

  • If your words are longer than about 4K in length, you'll get buffer overflow. However, even German, with its penchant for stringing basic words together in long sequences(a), doesn't have this problem :-) Still, it's something that should be catered for, if only to handle "invalid" input data.
  • Being static, the buffer will be shared amongst all threads calling this function if used in a multi-threaded environment. That's unlikely to end well as threads may corrupt the data of each other.

A relatively easy fix would be for the caller to also provide a buffer for the result, at least long enough to handle the largest possible expansion of a word to its plural form. But I've left that as a separate exercise since it's not really relevant to the question.


(a) Such as Donaudampfschiffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft :-)

Upvotes: 4

codaddict
codaddict

Reputation: 455000

You are reading a word as:

scanf("%c",&plural);

which is incorrect as it only reads one character.

Change it to:

scanf("%s",plural);

or even better use fgets as:

fgets (plural,SIZE, stdin);

But note that fgets might add a newline at the end of the string. If it does you need to remove it before you do the replacement as your replacement depends on the last character in the word.

Also your replacement part is incorrect. You are replacing any s with es (same with other replacements). You need to replace only the last s.

Upvotes: 2

Poonam
Poonam

Reputation: 4631

first of all u need to find last position of occurance and then call replace_str() function and secondly scanf("%s",&plural);or use fgets()

Upvotes: 0

sarnold
sarnold

Reputation: 104050

puts(replace_str(plural, "ch","es"));

Consider the input: church

strstr(3) will find the first ch, not the last ch. Ooops.

Furthermore, once you modify replace_str() to find the the last ch, you're still ripping it off and not putting it back on: chures. (Assuming your replace_str() functions as I think it does; that's some hairy code. :) So add the ch back on:

puts(replace_str(plural, "ch","ches"));

Upvotes: 0

sharpner
sharpner

Reputation: 3937

Maybe this might help you: str_replace

it's nicely done!

Upvotes: -2

Related Questions