将文本中的每个单词替换为右移'k'次

时间:2015-12-12 18:35:52

标签: c string function pointers replace

我试图创建一个函数来替换文本中的每个单词,并将单词向右移动'k'次。 代码看起来像这样:

void operation_3(char *string, int k){
    int len = 0, i;
    int string_len = strlen(string);
    char *word;
    char s[12] = " .,?!\"'";
    char *dup;
    dup = strdup(string);
    word = strtok(dup, s);
    while (word != NULL) {
            len = strlen(word);
            char *new_word = (char *)malloc(len * sizeof(char));
            for (i = 0; i < k; i++) {
                    new_word = shift_to_right(word);
            }
            string = replace_word(string, word, new_word);
            word = strtok(NULL, s);
    }
 }

shift_to_right是:

char *shift_to_right(char *string){
    char temp;
    int len = strlen(string) - 1;
    int i;
    for (i = len - 1; i >= 0; i--) {
            temp = string[i+1];
            string[i+1] = string[i];
            string[i] = temp;

    }
    return string;
}

replace_word是:

char *replace_word(char *string, char *word, char *new_word) {
    int len = strlen(string) + 1;
    char *temp = malloc(len * sizeof(char));
    int temp_len = 0;
    char *found;
    while (found = strstr(string, word)) {
            if (strlen(found) != strlen(word) || isDelimitator(*(found - 1)) == 1) {
                    break;
            }
            memcpy(temp + temp_len, string, found - string);

            temp_len = temp_len + found - string;

            string = found + strlen(word)

            len = len - strlen(word) + strlen(new_word);
            temp = realloc(temp, len * sizeof(char));

            memcpy(temp + temp_len, new_word, strlen(new_word));

            temp_len = temp_len + strlen(new_word);
    }

    strcpy(temp + temp_len, string);

return temp;
 }

和isDelimitator是:

int isDelimitator(char c) {
    if(c == ' ' || c == '.' || c == ',' || c == '?' || c == '!' ||
       c == '"' || c == '\0' || c == '\'') {
            return 0;
    }
    else return 1;
 }

我测试了shift_to_right,replace_word和isDelimitator并且工作正常。但是最终的函数operation_3没有按预期工作。例如,对于输入:“嗨,我是约翰”,对于k = 1,输出为:“嗨,我是约翰”。基本上,operation_3不会修改字符串。有任何建议,更正吗?

2 个答案:

答案 0 :(得分:2)

我认为有一些事情可能是错误的原因。

1)operation_3中,您执行此操作:new_word = shift_to_right(word);并且,在char *shift_to_right(char *string)的定义中,您修改string本身并返回指向它的指针。因此,如果您调用了shift_to_right(word)word = "Hi",那么在执行shift_to_right之后,wordnew_word现在都指向相同的字符串"iH" ,所以在replace_word中,当你传递两个单词并检查子串word时,你总是会得到NULL,因为,没有子串"iH"

一种可能的解决方案,在shift_to_right中添加一个声明,

char *new_string = strdup(string);

而不是交换string中的字符,现在在new_string中交换字符并从函数中返回new_string

您的代码应如下所示::

char *shift_to_right(char *string){
    char temp;
    int len = strlen(string) - 1;
    char *new_string = strdup(string);
    int i;
    for (i = len - 1; i >= 0; i--) {
        temp = new_string[i+1];
        new_string[i+1] = new_string[i];
        new_string[i] = temp; 
    }
    return new_string;
}

2)在函数replace_word中,我们暂时考虑上述错误并未发生,replace_word使用参数:: {{ 1}}。 因此,当您执行replace_word(string, "Hi", "iH");时,它会为您提供指向found = strstr(string, word)开始的第一个字母的指针。因此,在这种情况下,如果您的字符串为Hi,那么您将获得指向第一个"Hi I am John"的指针,当您执行H时,您将获得strlen(found)(长度为{1}}字符串从指针开始离开)作为输出,12将始终更少(除非strlen(word)指向字符串中的最后一个字),因此在大多数情况下,您的found条件变为如果没有任何交换,你就可以从循环中断开。

此外,正如您自己在评论中指出的那样if将返回strstr,如果您想要一个子串Johns,唯一的解决办法就是运行一个循环,检查John之后的string是否存在分隔符,如果没有分隔符,则不是您需要的子字符串。

John看起来像这样::

replace_word

我认为这个void replace_word(char *string, char *word, char *new_word) { char *found = strstr(string, word); int len = strlen(word); while(found) { char temp = *(found + len); if(isDelimeter(temp) == 0) { break; } else { found = strstr(found + len + 1); } } if(found != NULL) { for(int i = 0; i < len; i++) { *(found + i) = new_word[i]; // *(found + i) is accessing the i^th, character in string from the pointer found } } } 可以正常工作,您可以直接修改replace_word,并且不需要实际生成string字符串并将其返回。这减少了分配新内存和保存指针的需要。

我希望这可以提供帮助!

EDIT :: 由于我们在代码中使用temp,因此动态分配字符串大小的内存以及strdup字符的额外块,我们将明确地释放它,所以根据我在退出函数之前在\0中释放已分配的内存将是一个好主意,因为replace_word在它之后是没用的。

此外,我在你的代码::

中看到了一个声明

1)new_word

在你开始转换单词之前,我希望你明白你不需要这样做。 char *new_word = (char *)malloc(len * sizeof(char));只是一个指针,因为我们现在在new_word中为它分配了内存,所以我们不需要这样做。甚至在此之前,考虑到您编写的代码,没有理由为strdup分配内存,因为您返回的数组的地址已经在堆栈中,并且将保留在堆栈中直到结束程序的执行。

答案 1 :(得分:1)

此代码比您拥有的代码简单,它会打印输入字符串中的所有单词分隔符。而不是寻找特定的标点字符,而是检查字母数字。

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

int main(void)
{
    char instr[] = "Hi! I am 'John' ;)";
    int lennin = strlen(instr);
    int shifts, i, len, index, start, next;

    printf("Working with  %s\n", instr);

    for(shifts=0; shifts<5; shifts++) {                         // various examples
        printf("Shifts = %d    ", shifts);
        start = 0;
        while(start < lennin) {
            while (start < lennin && !isalnum(instr[start])) {  // find next alphanum
                printf("%c", instr[start]);                     // output non-alphanum
                start++;
            }
            next = start + 1;
            while (isalnum(instr[next]))                        // find next non-alphanum
                next++;
            len = next - start;
            for(i=0; i<len; i++) {                              // shift the substring
                index = i - shifts;
                while(index < 0) index += len;                  // get index in range
                printf("%c", instr[start + (index % len)]);     // ditto
            }
            start = next;                                       // next substring
        }
        printf("\n");
    }
    return 0;
}

节目输出:

Working with  Hi! I am 'John' ;)
Shifts = 0    Hi! I am 'John' ;)
Shifts = 1    iH! I ma 'nJoh' ;)
Shifts = 2    Hi! I am 'hnJo' ;)
Shifts = 3    iH! I ma 'ohnJ' ;)
Shifts = 4    Hi! I am 'John' ;)