iT邦幫忙

0

如何用c語言替換英文文章中特定的字

  • 分享至 

  • xImage

不好意思,我在編寫以下程式碼時遇到一些問題,希望有人可以幫忙
我希望程式碼可以讀入一行字串和一 篇文章,
第一行:(字被取代) (字要加入)
例如
第一行:hey hi
文章:hey, They’re just the nice, Hey….
輸出:hi
Thi
另外如果在第一行加上-i ,大小階不同但相同字也會被取代
例如
第一行:hey hi -I
文章:hey, They’re just the nice, Hey….
輸出:hi
Thi
It
如果第一行讀入少於 2個或多於3個字串,或第三個字串不是-i要輸出
輸出:Invalid case

我的做法是分用fget讀取兩行字串
然後分別把單詞除掉符號和空白后,存到陣列(到這?為止應該是正確的)
用strstr查看該詞語中有沒有要找的字
如果有,就把該單詞拆開三分”前””要被取代的字””後”
把目標字取代後,把三個部分都放在同一陣列,後printf出

但是不知為什麼程式碼沒有輸出任可東西
我確定兩行字串中的字詞有正確被分開存到我指定的陣列中,但沒有辨法去找到要找的字
以下是我的程式碼麻煩了

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define arrlen 100
#define string_len 4096
// str1_temp 和str2_temp 用來放各自的token
char str1_temp[3][101] = {'\0'}, str1[250] = {'\0'}, str2[4096] = {'\0'}, str2_temp[4096][101] = {'\0'}, temp_of_capital[101] = {'\0'};
char getword_temp[101], result[4096][101] = {'\0'}, old[101], new[101]; //給getword 用
int str1_temp_len = 0, str2_temp_len = 0;
const char delim[] = " !?_\n\t\r:,./[]{}";
void replace(char *p, int pos, char *temp, int new_len, int num, int old_len);
char *getword(char *article, char *word);

int main()
{
    // str1_temp_len 和str2_temp_len 代表各自的長度 num=number of token
    int str2_temp_x_leght = 0, old_len = 0, new_len = 0, par = 0, temp_len = 0, have_capital; //有要找的字的token的長度 par=0代表沒有parameter
    char str2_temp_x[101], parameter[101];
    const char delim[] = " !?_\n\t\r:,./[]{}@#$^*()+=_";

    int pos = 0, a = 0, b = 0, c = 0, total = 0;
    fprintf(stderr, "Enter pattern, replacement, and at most one parameter: ");
    fgets(str1, arrlen, stdin);

    fprintf(stderr, "Enter the article: ");
    fgets(str2, string_len, stdin);
    // printf("str1:%s\n",str1);
    // printf("str2:%s\n",str2);
    str1[strlen(str1) - 1] = '\0';
    str2[strlen(str2) - 1] = '\0';
    // read string1 string2 [parameter]
    char *token1;
    token1 = strtok(str1, delim);
    // printf("%s",token);
    str1_temp_len = 0;
    while (token1 != NULL)
    {
        // vv token ok
        //找old ,new,parameter
        strcpy(str1_temp[str1_temp_len], token1);

        str1_temp_len++; // find str1_temp leght
        // printf("str1 token:%s\n",token1);//vv token ok
        //續找token
        // printf("tokenstr1:%s %d",token1,str1_temp_len);
        token1 = strtok(NULL, delim);
        if (str1_temp_len < 2 && str1_temp_len > 3)
        {

            fprintf(stderr, "Invalid case");
            break;
        }
    }

    char *ptr;
    ptr = str2;
    str2_temp_len = 0;
    while (ptr = getword(ptr, getword_temp))
    {
        strcpy(str2_temp[str2_temp_len], getword_temp);

        str2_temp_len++;
    }

    strcpy(old, str1_temp[0]);
    strcpy(new, str1_temp[1]);
    strcpy(parameter, str1_temp[2]);
    // printf("%s %s %s",old,new,parameter);
    if (strcmp(parameter, "-i") != 0 && str1_temp_len == 3)
    { //有第三個字串但不是-i

        fprintf(stderr, "Invalid case");
    }
    else
    {
        par = 1;
    } // par=1代表有-i

    old_len = strlen(old);
    new_len = strlen(new);
    ///////////////////////////////////////////
    //在每個str2的token中找str1_temp[0]
    char *p;
    int num = 0;
    p = (char *)malloc(string_len * sizeof(char));

    for (int x = 0; x < str2_temp_len; x++)
    {
        p = 0;
        char temp[101] = {'\0'};
        strcpy(temp, str2_temp[x]); //把token放入temp
                                    //找有沒有相同的字
        p = strstr(temp, old);      //
                                    // printf("%s",p);
        ///////如果有"-i"
        if (par == 1)
        {
            temp_len = strlen(temp);

            //找該token有沒有大階
            have_capital = 0;
            for (int i = 0; i < temp_len; i++)
            {
                if (temp[i] >= 'a' && temp[i] <= 'z')
                {
                }
                else
                {
                    have_capital = 1;
                }
            }
            //該token有大階
            if (have_capital == 1)
            {
                strcpy(temp_of_capital, temp);
                int i = 0;
                //將大階變成小階
                while (temp_of_capital[i] == '\0')
                {
                    if (temp_of_capital[i] <= 'Z' && temp_of_capital[i] >= 'A')
                    {
                        temp_of_capital[i] += 32;
                    }
                }
                p = 0;
                p = strstr(temp_of_capital, old); //在temp_of_capital有相同字的位置
                replace(p, pos, temp, new_len, num, old_len);
            }
        }
        ///////////////////////////////////////////
        //如果有要找的字
        //應該是從這開始有問題
        if (p)
        {
            int total = 0; //
            pos = p - &temp[0];
            //找有old前的字完
            for (int i = 0; i < pos; i++)
            {
                result[num][total] = temp[i];
                total++;
            }
            //找有old的位置加入new
            for (int i = 0; i < new_len; i++)
            {
                result[num][total] = new[i];
                total++;
            }
            //加入new後
            for (int j = pos + old_len; temp[j] != '\0'; j++)
            {
                result[num][total] = temp[j]; //將temp的單字放入 result[num]
                total++;
            }
            result[num][total] = '\0';
            num++;
        }
        //初始化temp
        for (int i = 0; i < 101; i++)
        {
            temp[i] = '\0';
        }
    }
    for (int i = 0; i < num - 1; i++)
    {
        printf("%s", result[i]);
    }
    return 0;
}

char *getword(char *text, char *temp)
{
    char *ptr1 = text;
    char *ptr2 = temp;

    while (*ptr1 && !isalnum(*ptr1))
    {
        ptr1++;
    }
    while (*ptr1 && isalnum(*ptr1))
    {
        if (ptr2 - temp >= 128)
        {
            break;
        }
        *ptr2++ = *ptr1++;
    }

    *ptr2 = '\0';
    if (ptr2 - temp == 0)
    {
        return NULL;
    }
    return ptr1;
}
void replace(char *p, int pos, char *temp, int new_len, int num, int old_len)
{
    if (p)
    {
        int total = 0;
        num = 0; //
        pos = p - &temp[0];
        //找有old前的字完
        for (int i = 0; i < pos; i++)
        {
            result[num][total] = temp[i];
            total++;
        }
        //找有old的位置加入new
        for (int i = 0; i < new_len; i++)
        {
            result[num][total] = new[i];
            total++;
        }
        //加入new後
        for (int j = pos + old_len; temp[j] != '\0'; j++)
        {
            result[num][total] = temp[j]; //將temp的單字放入 result[num]
            total++;
        }
        result[num][total++] = '\0';
        num++;
        for (int i = 0; i < 101; i++)
        {
            temp[i] = '\0';
        }
    }
}
尼克 iT邦大師 1 級 ‧ 2022-03-10 08:50:03 檢舉
建議你把程式部份排版好!
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

2
海綿寶寶
iT邦大神 1 級 ‧ 2022-03-10 10:45:19

https://ithelp.ithome.com.tw/upload/images/20220310/20001787R8YPdqfmXv.png

告訴你一個好消息和一個壞消息
好消息是我找到為什麼沒有輸出任何東西的原因
以下這段程式碼
在「只輸入兩個字串時(會跑到 else),par 會等於 1」以致出錯

if (strcmp(parameter, "-i") != 0 && str1_temp_len == 3)
    { //有第三個字串但不是-i

        fprintf(stderr, "Invalid case");
    }
    else
    {
        par = 1;
    } // par=1代表有-i

壞消息是我只 debug 到這裡,剩下的實在懶得看了

尼克 iT邦大師 1 級 ‧ 2022-03-10 11:21:16 檢舉

海綿寶寶,你這圖是公版嗎?

我自己做的,免費公開使用
(不知道算不算公版 /images/emoticon/emoticon19.gif)

2
淺水員
iT邦大師 6 級 ‧ 2022-03-11 01:29:26

以下是照你原本程式碼去修的

37~54 行的 while 這樣即可
(這邊我沒看原本的寫法能不能正常跑)

while (token1 != NULL)
{
    //str1_temp 最多只能存 3 個詞,多的會被省略
    if (str1_temp_len < 3)
    {
        strcpy(str1_temp[str1_temp_len++], token1);
        token1 = strtok(NULL, delim);
    }
    else
    {
        fprintf(stderr, "Invalid case");
    }
}

70~78 行判斷參數那邊要修一下,不然只輸入 hey hi 也會當作有 -i

if (strcmp(parameter, "-i") == 0 && str1_temp_len == 3)
{
    par = 1;
}
else if(str1_temp_len != 2)
{
    fprintf(stderr, "Invalid case");
}

88~164 的 for 迴圈弄得太複雜
既然已經有自己寫 replace 函式
可以利用,避免太多重複的程式碼

for (int x = 0; x < str2_temp_len; x++)
{
    char temp[101] = {'\0'};
    char *pSearchStr;
    if (par == 1)
    {
        //複製 str2_temp[x] 到 temp,並把所有字母轉為小寫
        strcpy(temp, str2_temp[x]);
        temp_len = strlen(temp);
        for (int i = 0; i < temp_len; i++)
        {
            if ('A' <= temp[i] && temp[i] <= 'Z')
            {
                temp[i] += 32;
            }
        }
        //搜尋目標為 temp (轉小寫的 str2_temp[x])
        pSearchStr = temp;
    }
    else
    {
        //搜尋目標為 str2_temp[x]
        pSearchStr = str2_temp[x];
    }
    p = strstr(pSearchStr, old);
    strcpy(pSearchStr, str2_temp[x]);
    replace(p, pSearchStr, new_len, old_len, &num);
}

replace 函式
因為你要動到那個 num,所以要改成傳址
另外 pos 既然每次都會重新計算,那用區域變數就好,不需要當參數

void replace(char *p, char *temp, int new_len, int old_len, int *num)
{
    if (p != NULL)
    {
        int total = 0, pos;
        pos = p - temp;
        //找有old前的字完
        for (int i = 0; i < pos; i++)
        {
            result[*num][total] = temp[i];
            total++;
        }
        //找有old的位置加入new
        for (int i = 0; i < new_len; i++)
        {
            result[*num][total] = new[i];
            total++;
        }
        //加入new後
        for (int j = pos + old_len; temp[j] != '\0'; j++)
        {
            result[*num][total] = temp[j]; //將temp的單字放入 result[num]
            total++;
        }
        result[*num][total++] = '\0';
        (*num)++;
        for (int i = 0; i < 101; i++)
        {
            temp[i] = '\0';
        }
    }
}

我要發表回答

立即登入回答