討論區快速選單
知識庫快速選單
下載Alexa Toolbar讓你上網更有趣 傑米的攝影旅遊筆記 最新Microsoft免費研討會行事曆
[ 回上頁 ] [ 討論區發言規則 ]
[C]讀檔、分割字串、再排序輸出(strtok使用請教)
更改我的閱讀文章字型大小
作者 : linuxk(k1) 人氣指數超過10000點
[ 貼文 121 | 人氣 28595 | 評價 40 | 評價/貼文 0.33 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/20 下午 04:18:48
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER 80 //螢幕輸出最大行數
#define MAX_TOTAL 6000 //設定全文總字數上限
#define MAX_LETTER 15 //設定一個字串最長的字元數目

/*輸入一文字資料檔
     1.將文章內容輸出至螢幕 (大小寫需與原文相同)
     2.統計文章內所包含相異字數,大小寫視為相同,並將結果輸出至螢幕
     (如:本文章共包含 a the of normal program...共n字)
     3.計算各字出現次數,並按下列兩種方式排序 (大小寫視為同一字)
     a.按字母順序排序 (如:apple 3
     book 2
     both 4)
     b.按出現次數排序 (如:both 4
     apple 3
     book 2)*/

void main()
{
FILE *aptr,*bptr; //指向檔案的指標
char line[MAX_BUFFER],*charline;
char total[MAX_TOTAL];
char *word[MAX_LETTER]; //單字指標
int count=1,a;

if((aptr=fopen("example.txt","r"))==NULL&&(bptr=fopen("example.txt","r"))==NULL)
{
printf("open file error!!\n");
}
else
{
printf("*********** 讀檔開始 *****************\n");
printf("檔案內容如下:\n");
while(fgets(line,MAX_BUFFER,aptr)!=NULL)
{
charline=line;

for(a=0;a<80;charline++,a++,(*word)++)
{
if(*charline==' ')
count++;
}
printf("%s\n",line);
}
while(fscanf(bptr,"%s",total)!=EOF) //讀入連續的全文做分割準備
{
*word = strtok(total, " ");
while(strtok(NULL, " ")!=NULL)
{
*word = strtok(NULL, " ");
}
for(*word;*word!=NULL;(*word)--) //從單字指標結尾結尾印出字串
printf("%s\n", *word); //輸出單字
}
printf("字串總數目:%d\n",count);
}

fclose(aptr);
fclose(bptr);
printf("*********** 讀檔結束 *****************\n");
}

目前我的程式第一、第二功能皆完成,最難的在於對單字分割然後處理這部份,原先我用strtok對aptr的內容作分割,但由於aptr的輸出本身是經過最大螢幕字元[80]分割處理輸出,所以切出來的字串某些是不正確分開的兩字串,所以後來我在以另一指檔案指標[bptr]處理,這部份有邏輯上的錯誤,我還不太熟strtok,不知道strtok切出來儲存的NULL跟一般我們所指的空字串NULL是否相同呢?為何取同樣名稱
另外題目還要求,單字本身後面接的逗點、句點必須去除[之後在做統計判斷],這個如何去把金以空格切出來的word內容在做處理呢?

麻煩大大指教了@@~~
作者 : 7654321(0)
[ 貼文 112 | 人氣 254 | 評價 500 | 評價/貼文 4.46 | 送出評價 1 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/21 上午 10:12:37
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER 80 //螢幕輸出最大行數
#define MAX_TOTAL 6000 //設定全文總字數上限
#define MAX_LETTER 15 //設定一個字串最長的字元數目

int currline;
char totalwordarray[MAX_TOTAL][MAX_LETTER];

void main()
{
    FILE *aptr; //指向檔案的指標
    char *token;
    char line[MAX_BUFFER], linebuf[MAX_BUFFER];
    char word[MAX_BUFFER];
    int len, totalword;
    int i, j;
    int cnt;

    aptr = fopen("example.txt","r");
    if(aptr == NULL)
    {
     printf("open file error!!\n");
     return;
    }

    printf("*********** 讀檔開始 *****************\n");
    printf("檔案內容如下:\n");
    currline = 0;
    totalword = 0;
    while(!feof(aptr))
    {
     fgets(line, MAX_BUFFER, aptr);
     if(feof(aptr)) break;

     currline++; /* 現在行數 */
     strcpy(linebuf, line);
     printf("第 %d 行: %s", currline, linebuf);

     token = strtok(linebuf, " ,.\n\t"); /* 取得 token */
     while(token)
     {
     strcpy(word, strupr(token));

     strcpy(&totalwordarray[totalword][0], word);
     totalword++; /* 總字數 */

     token = strtok(NULL, " ,.\n\t"); /* 取得 token */
     }
    }
    printf("總字數:%d\n", totalword);
    printf("*********** 讀檔結束 *****************\n");
    fclose(aptr);
    printf("按任意鍵繼續...\n");
    getch();

    printf("*********** 分析開始 *****************\n");
    printf("按字母順序排序:\n");
    for(i=0; i<totalword; i++)
    {
     for(j=i+1; j<totalword; j++)
     {
     if(strcmpi(totalwordarray[j], totalwordarray[i]) < 0)
     {
     strcpy(word, totalwordarray[j]);
     strcpy(totalwordarray[j], totalwordarray[i]);
     strcpy(totalwordarray[i], word);
     }
     }
    }
    cnt = 0;
    strcpy(word, totalwordarray[0]);
    for(i=0; i<totalword; i++)
    {
     if(strcmpi(word, totalwordarray[i]) == 0)
     {
     cnt++;
     }
     else
     {
     printf("%-20s : 出現 %d 次\n", word, cnt);
     cnt = 1;
     strcpy(word, totalwordarray[i]);
     }
    }
    printf("*********** 分析結束 *****************\n");
    printf("按任意鍵結束...\n");
    getch();
}

/*輸入一文字資料檔
     1.將文章內容輸出至螢幕 (大小寫需與原文相同)
     2.統計文章內所包含相異字數,大小寫視為相同,並將結果輸出至螢幕
     (如:本文章共包含 a the of normal program...共n字)
     3.計算各字出現次數,並按下列兩種方式排序 (大小寫視為同一字)
     a.按字母順序排序 (如:apple 3
     book 2
     both 4)
     b.按出現次數排序 (如:both 4
     apple 3
     book 2)*/


     第 3 項 的第 b 項 請自己想想再寫

作者 : linuxk(k1) 人氣指數超過10000點
[ 貼文 121 | 人氣 28595 | 評價 40 | 評價/貼文 0.33 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/26 上午 08:39:41
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_BUFFER 80 //螢幕輸出最大行數
#define MAX_TOTAL 6000 //設定全文總字數上限
#define MAX_LETTER 20 //設定一個字串最長的字元數目
int currline;
char totalwordarray[MAX_TOTAL][MAX_LETTER];

void sort_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)
{
int i,j;
char temp[MAX_LETTER];
for(i=0; i<wordlength; i++) //totalword代表總字數,跑外部迴圈
{
for(j=i+1; j<wordlength; j++) //內部迴圈
{
if(strcmpi(wordarray[j], wordarray[i]) < 0) //當totalwordarray[i]<totalwordarray[j]時,把字母序較高的往後排
{
strcpy(temp, wordarray[j]);
strcpy(wordarray[j], wordarray[i]);
strcpy(wordarray[i], temp);
}
}
}
}

void count1_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)
{
int count = 0,i;
char temp[MAX_LETTER];

strcpy(temp, totalwordarray[0]);
for(i=0; i<wordlength; i++)
{
if(strcmpi(temp, totalwordarray[i]) == 0)
{
count++;
}
else
{
printf("%-20s : 出現 %d 次\n", temp, count);
count = 1;
strcpy(temp, totalwordarray[i]);
}
}
}

void count2_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)
{
int count = 0,i,t,set=30; //count計算出現次數,set預設最高次數
int countsize[200]; //暫存每個字串的count數值
char temp[MAX_LETTER];
FILE *aptr,*bptr;

aptr=fopen("t.txt","w");
strcpy(temp, totalwordarray[0]); //字串複製
for(i=0; i<wordlength; i++) //wordlength=197
{
if(strcmpi(temp, totalwordarray[i]) == 0) //當字串相等
{
count++;
}
else
{
countsize[i]=count;
fprintf(aptr,"%d %s\n",countsize[i],temp);
count = 1;
strcpy(temp, totalwordarray[i]);
}
}
fclose(aptr);

bptr=fopen("t.txt","r");
while((wordlength--)>0) //跑[字串個數]197次
{
while(fscanf(bptr,"%d %s\n",&t,temp)!=EOF);
{
if(t==set);
{
printf("%-20s : 出現 %d 次\n", temp, t);
}
}
fseek(bptr,sizeof(int),SEEK_SET); //設定檔案指標從檔頭開始跑
set--; //次數遞減
}
fclose(bptr);
}
作者 : linuxk(k1) 人氣指數超過10000點
[ 貼文 121 | 人氣 28595 | 評價 40 | 評價/貼文 0.33 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/26 上午 08:47:08
void main()
{
    FILE *aptr; //指向檔案的指標
    char *token;
    char line[MAX_BUFFER], linebuf[MAX_BUFFER];
    char word[MAX_BUFFER];
    int totalword;
    int chioce;

    aptr = fopen("example.txt","r");
    if(aptr == NULL)
    {
printf("open file error!!\n");
return;
    }

    printf("*********** 讀檔開始 *****************\n");
    printf("檔案內容如下:\n");
    currline = 0;
    totalword = 0;
    while(!feof(aptr))
    {
fgets(line, MAX_BUFFER, aptr);
if(feof(aptr))
break;

// currline++; /* 現在行數 */
strcpy(linebuf, line);
printf("%s",linebuf);

token = strtok(linebuf, " ,.\n"); /* 取得 token */
while(token)
{
strcpy(word, strupr(token));

strcpy(&totalwordarray[totalword][0], word);
totalword++; /* 總字數 */

token = strtok(NULL, " ,.()'\n"); /* 取得 token */
}
/*根據字串是否有值判斷中斷點.....*/
    }
    printf("總字數:%d\n", totalword);
    printf("*********** 讀檔結束 *****************\n");
    fclose(aptr);

    printf("選擇你所要輸出的模式:[]\n");
    printf("[1].按字母順序排序\n");
    printf("[2].按出現次數順序排序\n");
scanf("%d",&chioce);
while(chioce!=1 && chioce!=2)
{
printf("選擇你所要輸出的模式,請符合規定:[]\n");
printf("[1].按字母順序排序\n");
printf("[2].按出現次數順序排序\n");
scanf("%d",&chioce);
}

    printf("*********** 分析開始 *****************\n");
if(chioce==1)
{
printf("按字母順序排序:\n");
sort_process(totalwordarray,totalword);

count1_process(totalwordarray,totalword);
}
else
{
printf("按出現次數順序排序\n");
sort_process(totalwordarray,totalword);

count2_process(totalwordarray,totalword);
}
printf("*********** 分析結束 *****************\n");

    system("pause");
}

以上是我針對第二功能寫的,原本我以為單純用一個整數陣列去處理字串字數出現次數就可以。發現排序輸出時會因為要重作sort跟字串變數很難排序[count值跟字串不符],於是我另存一個含count與字串的檔案,用一個最大值去找count在印出該行字串,count2_process是我主要的功能,可是卻都只輸出最後一行,不知道我的邏輯錯在哪?

懇請大大指教~~~
作者 : 7654321(0)
[ 貼文 112 | 人氣 254 | 評價 500 | 評價/貼文 4.46 | 送出評價 1 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
主題發起人linuxk註記此篇回應為很有道理 2005/12/26 上午 10:07:03
char totalwordarray2[MAX_TOTAL][MAX_LETTER];
int totalwordcount[MAX_TOTAL];

void count2_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)
{
    char temp[MAX_LETTER];
    int i, j, t;
    int totalword;

    memset(totalwordcount, 0, sizeof(totalwordcount));
    totalword = 0;
    strcpy(totalwordarray2[totalword], totalwordarray[0]);
    for(i=1; i<wordlength; i++)
    {
     if(strcmpi(temp, totalwordarray[i]) == 0) //當字串相等
     {
     totalwordcount[totalword]++;
     }
     else
     {
     totalword++;
     strcpy(totalwordarray2[totalword], totalwordarray[i]);
     strcpy(temp, totalwordarray[i]); //字串複製
     }
    }
    for(i=0; i<totalword; i++)
    {
     for(j=i+1; j<totalword; j++)
     {
     if(totalwordcount[j] > totalwordcount[i])
     {
     t = totalwordcount[j];
     totalwordcount[j] = totalwordcount[i];
     totalwordcount[i] = t;

     strcpy(temp, totalwordarray2[j]);
     strcpy(totalwordarray2[j], totalwordarray2[i]);
     strcpy(totalwordarray2[i], temp);
     }
     }
    }

    for(i=0; i<totalword; i++)
    {
     printf("%-20s : 出現 %d 次\n", totalwordarray2[i], totalwordcount[i] + 1);
    }
}
作者 : linuxk(k1) 人氣指數超過10000點
[ 貼文 121 | 人氣 28595 | 評價 40 | 評價/貼文 0.33 | 送出評價 11 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/26 下午 01:10:16
.......7654321(0) 大大
我真的很感激你熱心的幫我把作業弄好@@,上次你給我程式碼後我仔細研究許久,確實是很棒的演算邏輯,我想以我目前的程度一時還想不到這麼仔細說。

不過其實我更希望能告訴我以我原本的作法為何不能做到我想要的功能.....?
每次我問問題都希望是能讓回答我的大大能針對我的程式批評我哪裡寫法不對或是觀念錯在哪
所以我都盡量仔細的去把註解寫出來跟題目要求和想法
這才是我的初衷@@

不過真的7654321(0) 給的程式碼簡潔又直接,讓我能夠有不一樣的思考方式,非常感謝
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++曠世奇才新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4762 | 人氣 9172 | 評價 31290 | 評價/貼文 6.57 | 送出評價 140 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/29 上午 03:32:59
>#include <stdio.h>
>#include <stdlib.h>
>#include <string.h>
>#define MAX_BUFFER 80 //螢幕輸出最大行數
>#define MAX_TOTAL 6000 //設定全文總字數上限
>#define MAX_LETTER 20 //設定一個字串最長的字元數目
>int currline;
>char totalwordarray[MAX_TOTAL][MAX_LETTER];
>
>void sort_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)

最後一個參數的名字 'wordlength' 看起來好像是字的長度. 應該是用回 'totalword' 或 'wordcount' 比較恰當.


>{
> int i,j;
> char temp[MAX_LETTER];
> for(i=0; i<wordlength; i++) //totalword代表總字數,跑外部迴圈
> {
> for(j=i+1; j<wordlength; j++) //內部迴圈
> {
> if(strcmpi(wordarray[j], wordarray[i]) < 0)

strcmpi() 並不是一個標準的函式.

同時, 在 main() 的時候你已經把字轉換成大寫了 (同樣用的也不是標準的函式), 所以這裡 strcmpi() 就是多餘的.


//當totalwordarray[i]<totalwordarray[j]時,把字母序較高的往後排
> {
> strcpy(temp, wordarray[j]);
> strcpy(wordarray[j], wordarray[i]);
> strcpy(wordarray[i], temp);
> }
> }
> }
>}
>
>void count1_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)
>{
> int count = 0,i;
> char temp[MAX_LETTER];
>
> strcpy(temp, totalwordarray[0]);
> for(i=0; i<wordlength; i++)
> {
> if(strcmpi(temp, totalwordarray[i]) == 0)
> {
> count++;
> }
> else
> {
> printf("%-20s : 出現 %d 次\n", temp, count);
> count = 1;
> strcpy(temp, totalwordarray[i]);
> }
> }

這裡會少印最後一組. 所以你還要在 for-loop 結束後重複上面的 printf().


>}

[續...]
作者 : sflam(Raymond)討論區板主 Visual C++ .NET卓越專家VC++曠世奇才新手入門優秀好手資訊類作業求救頂尖高手C++一代宗師貼文超過4000則
[ 貼文 4762 | 人氣 9172 | 評價 31290 | 評價/貼文 6.57 | 送出評價 140 次 ] 
[ 給個讚 ]  [ 給個讚 ]  [ 回應本文 ]  [ 發表新文 ]  [ 回上頁 ] [ 回討論區列表 ] [ 回知識入口 ]
2005/12/29 上午 03:33:25
[...續]

>void count2_process(char wordarray[MAX_TOTAL][MAX_LETTER],int wordlength)
>{
> int count = 0,i,t,set=30; //count計算出現次數,set預設最高次數
> int countsize[200]; //暫存每個字串的count數值

不要直接在程式裡用像 200 這樣的數字. 用 #define 來定義符號, 就像 MAX_TOTAL 那樣.

這裡有一個邏輯上的嚴重錯誤....


> char temp[MAX_LETTER];
> FILE *aptr,*bptr;
>
> aptr=fopen("t.txt","w");
> strcpy(temp, totalwordarray[0]); //字串複製
> for(i=0; i<wordlength; i++) //wordlength=197

'i' 是用來 loop 檔案的字數.

> {
> if(strcmpi(temp, totalwordarray[i]) == 0) //當字串相等
> {
> count++;
> }
> else
> {
> countsize[i]=count;

如果檔案的字數超過 200, 你就超出了 'countsize' 陣列的範圍.


> fprintf(aptr,"%d %s\n",countsize[i],temp);
> count = 1;
> strcpy(temp, totalwordarray[i]);
> }
> }
> fclose(aptr);
>
> bptr=fopen("t.txt","r");
> while((wordlength--)>0) //跑[字串個數]197次
> {
> while(fscanf(bptr,"%d %s\n",&t,temp)!=EOF);
> {
> if(t==set);
> {
> printf("%-20s : 出現 %d 次\n", temp, t);
> }
> }
> fseek(bptr,sizeof(int),SEEK_SET); //設定檔案指標從檔頭開始跑
> set--; //次數遞減
> }
> fclose(bptr);
>}
>
>void main()

main() 的回傳類型是 int.

>{
> FILE *aptr; //指向檔案的指標
> char *token;
> char line[MAX_BUFFER], linebuf[MAX_BUFFER];
> char word[MAX_BUFFER];
> int totalword;
> int chioce;
>
> aptr = fopen("example.txt","r");
> if(aptr == NULL)
> {
> printf("open file error!!\n");
> return;
> }
>
> printf("*********** 讀檔開始 *****************\n");
> printf("檔案內容如下:\n");
> currline = 0;
> totalword = 0;
> while(!feof(aptr))
> {
> fgets(line, MAX_BUFFER, aptr);
> if(feof(aptr))
> break;

以 C 來說, feof() 的測試在多數的情況下是不需要的. 因為很多針對檔案的讀取函式會傳回是否該讀取的動作已超出 end of file.

像 fgets(), 如果讀取有錯誤或已經沒有資料可讀了, 就會傳回 NULL, 所以你可以用 fgets() 傳回的值來判斷是否 eof.

  while (fgets(line, MAX_BUFFER, aptr))
  {
    /* 還有資料, 繼續... */
  }

 板主 : Daniel
 > 資訊類作業 - 討論區
 - 最近熱門問答精華集
 - 全部歷史問答精華集
 - 資訊類作業 - 知識庫
  ■ 全站最新Post列表
  ■ 我的文章收藏
  ■ 我最愛的作者
  ■ 全站文章收藏排行榜
  ■ 全站最愛作者排行榜
  ■  月熱門主題
  ■  季熱門主題
  ■  熱門主題Top 20
  ■  本區Post排行榜
  ■  本區評價排行榜
  ■  全站專家名人榜
  ■  全站Post排行榜
  ■  全站評價排行榜
  ■  全站人氣排行榜
 請輸入關鍵字 
  開始搜尋
 
Top 10
評價排行
資訊類作業
1 Raymond 4340 
2 Ben 2880 
3 青衫 2260 
4 ozzy 1260 
5 HKLN.net 1010 
6 Daniel 780 
7 joe 740 
8 小朱 570 
9 Benson 440 
10 鬼翼@娃娃魚 400 
資訊類作業
  專家等級 評價  
  一代宗師 10000  
  曠世奇才 5000  
  頂尖高手 3000  
  卓越專家 1500  
  優秀好手 750  
Microsoft Internet Explorer 6.0. Screen 1024x768 pixel. High Color (16 bit).
2000-2014 程式設計俱樂部 http://www.programmer-club.com.tw/
0.078125