במשימה זו עלינו לכתוב תוכנית לחיפוש מספר מילים בתוך קטע טקסט ארוך.
על התוכנית להשיב כמה פעמים מופיעה כל מילה.
פרטים:
- התוכנית מקבלת מהמשתמש (באמצעות קובץ טקסט או הקלדה ישירה למסך) טקסט ארוך ושומרת אותו במערך long_text.
[באמצעות הקצאה דינאמית משתמשת בזיכרון המינימלי שנחוץ]
- התוכנית מקבלת מהמשתמש מספר n. מספר זה מייצג את מספר המילים שהמשתמש רוצה לחפש.
[ניצור מערך בגודל n שיכיל בעתיד מצביעים לכל המילים. גם זה בשימוש בהקצאה דינאמית]
- התוכנית קולטת מהמשתמש n מילים. כל מילה חייבת להכיל לפחות תו אחד, אחרת אינה חוקית.
כמובן שמילה לא יכולה להכיל רווחים, tab, או אנטר.
שימו לב: אסור לאותה מילה להיכנס פעמיים למאגר המילים.
[באמצעות הקצאה דינאמית כל מילה תשתמש בזיכרון המינימלי שנחוץ לה]
- התוכנית מדפיסה כמה פעמים מופיעה כל מילה במערך long_text.
התוכנית מחפשת רק כמה פעמים המילה מופיעה לבדה ב-long_text, ולא כחלק ממילה אחרת.
לדוגמה, התוכנית תשיב שהמילה "עם" מופיעה בטקסט "עם נועם" פעם אחת ולא פעמיים.
- על התוכנית להיות בטוחה ככל האפשר מקלט לא מתאים של המשתמש (כלומר היא תדע להגיב לו בלי שגיאות).
נסו לכתוב את הקוד בעצמכם!
תוכנית שכתבתי בשפת C:
V0.9
V0.9
#include <stdio.h> #include <stdlib.h> #include <string.h> int len_of_long_text; #define SIZE 6000 // כמות תווים מקסימלית בטקסט. ניתן לשינוי char* From_Big_String_To_dynamic_String(){ char get_a_big_string[SIZE], *Pstring; printf("Enter the long text:\n"); flushall(); do{ gets(get_a_big_string); len_of_long_text = strlen(get_a_big_string); if(len_of_long_text <= 1) { printf("Please type at least two character.\nEnter again:\n"); continue;} Pstring = (char*) malloc ((len_of_long_text+1) * sizeof(char)); // המסיים NULL מוסיפים 1 עבור ה if (Pstring == NULL) { printf("\nNo enough memory!.\nEnter again:\n"); continue; } break; }while(1); strcpy(Pstring, get_a_big_string); return Pstring; } int How_many_times_the_word_appear(const char *word, const char *long_tex, int Len_of_long_text){ int sum = 0, i, j, word_len; word_len = strlen(word); if(word_len>Len_of_long_text) return 0; for(i=0; i<Len_of_long_text; i++){ if(i>0 && !((long_tex[i-1]>=' ' && long_tex[i-1]<='@') || (long_tex[i-1]>=91 && long_tex[i-1]<=96) || long_tex[i-1]>=123 || long_tex[i-1]=='\n' || long_tex[i-1] == '\t')) continue; // זה כדי לבדוק שמילה לא מתחילה מאמצע מילה אחרת for(j=0; j<word_len && j+i<Len_of_long_text && word[j] == long_tex[i+j]; j++); if(j==word_len && (((long_tex[i+j]>=' ' && long_tex[i+j]<='@') || (long_tex[i+j]>=91 && long_tex[i+j]<=96) || long_tex[i+j]>=123 || long_tex[i+j]=='\n' || long_tex[i+j] == '\t') || j+i==Len_of_long_text)) sum++; // התנאי הארוך הזה מוודא שאחרי המילה שנמצאה יש רווח או כל תו שהוא לא אות. התווים האלה מפרידים בין מילים // אחרת הוא ימצא מילה שהיא חלקית מילה אחרת. לדוגמה: הוא ימצא 'ילד' בתוך ילדים // (עשינו בדיקה רק עבור סוף המילה, לא עבור ההתחלה. כי את תחילת המילה כבר בדקנו) } return sum; } int This_word_already_exists(char tmpStr[50], const char **Array_of_words){ // C זו אמורה להיות פונקציה בוליאנית, אבל אנחנו משתמשים בשפת int i, tmpStr_len; tmpStr_len = strlen(tmpStr); for(i=0; Array_of_words[i]; i++){ if(How_many_times_the_word_appear(tmpStr, Array_of_words[i], strlen(Array_of_words[i]))==1 && tmpStr_len == strlen(Array_of_words[i])) // הבדיקה של האורך נועדה לוודא שלא תהיה בעיה על מילה (שנגמרת בתו שאינו אות) שמכילה באופן חלקי מילה אחרת // asd ואחריו asd1 לדוגמה // we ואחריו qwe או return 1; } return 0; } void From_Big_word_To_dynamic_word(int num, const char **Array_of_words){ char tmpStr[50], *Pstring; int len, i; flushall(); do{ printf("%d. Enter word: ", num+1); gets(tmpStr); len = strlen(tmpStr); if(len == 0) { printf("Please type at least one character.\nEnter again:\n"); continue;} for(i=0; i<len; i++){ if(tmpStr[i] == ' ' || tmpStr[i] == '\t' || tmpStr[i] == '\n'){ printf("Please type only one word.\nEnter again:\n"); break; } } if(i!=len) continue; // כאן נגמרת בדיקת התווים if(This_word_already_exists(tmpStr, Array_of_words)==1){ // בודק שמילה לא מופיעה כבר printf("This word already exists.\nEnter again:\n"); continue; } Pstring = (char*) malloc ((len+1) * sizeof(char)); if (Pstring == NULL) { printf("\nNo enough memory!.\nEnter again:\n"); continue; } break; ////////////// אני לא אוהב את הכתיבה הזו של ברייק מיד לפני הוויל, אבל לא עולה לי רעיון אחר כרגע }while(1); strcpy(Pstring, tmpStr); Array_of_words[num] = Pstring; } int Get_Save_int_Number_From_User(char *str){ /* פונקציה מעולה לטיפול בבעיות הקטנות שבקליטת מספרים לא חוקיים מהמשתמש int אפשר להעתיק את הפונקציה הזו ולעשות בה שימוש בהרבה מאוד תוכניות לקליטה בטוחה של מספר */ int number=0, i, len, minusFlag=0; char tmpS[200]; // printf("\n"); flushall(); do{ printf("%s",str); gets(tmpS); len=strlen(tmpS); if(len>10 || len==0) continue; if((tmpS[0]>'9' || tmpS[0]<'0') && tmpS[0]!='-') continue; for(i=1; i<len; i++) if(tmpS[i]>'9' || tmpS[i]<'0') break; if(i<len) continue; if(tmpS[0] == '-'){ minusFlag=1; for(i=0; i<len; i++){ // אני מעביר כאן גם את הנאל המסיים tmpS[i] = tmpS[i+1]; } len--; } if(tmpS[0]=='0') continue; // יתכן שלא כולם יסכימו שמספר שמתחיל באפס הוא לא חוקי if(len==10){ // 2147483647 :זה המספר הכי גדול שמותר if(tmpS[0]>'2') continue; if(tmpS[0]=='2' && tmpS[1]>'1') continue; if(tmpS[0]=='2' && tmpS[1]=='1' && tmpS[2]>='4') continue; // מספיק הפירוט הזה. אין באמת טעם לפרט הכל } break; }while(1); for(i=1; len>0; i*=10, len--){ number += (tmpS[len-1]-'0')*i; } if (minusFlag == 1) number *= -1; return number; } void remove_Quotation_Marks (char str[], int len){ int i; for(i=0; i<len; i++) str[i] = str[i+1]; str[len] = NULL; } void Check_characters_in_path(char str[]){ int i; flushall(); do{ if (str[0]=='"' && str[strlen(str)-1]!='"'){ printf("*Illegal!*\nReinsert path: "); gets(str); continue; } for (i=0; str[i]!=NULL; i++){ if (str[i]<0 || str[i]>126){ printf("*Only English characters!*\nReinsert path: "); gets(str); break; } } if (str[i]!=NULL) continue; break; }while(1); } char* From_Text_File_To_dynamic_String(){ FILE *fp ; char str[200], get_a_big_string[SIZE], *Pstring; int i; flushall(); do{ printf("Enter path: "); do{ gets(str); Check_characters_in_path(str); if (str[0]=='"') remove_Quotation_Marks (str,strlen(str)-2); fp = fopen(str , "r"); if(fp == NULL) printf("Can't open file.\nEnter path Again:\n"); }while(fp == NULL); for(i=0; i<SIZE-1 && !feof(fp); i++){ get_a_big_string[i] = fgetc(fp); } get_a_big_string[i-1] =NULL; // תמיד 'כאילו' מוסיפה אחד feof(fp) בגלל שהפונקציה i-1 עושים len_of_long_text = i-1; if(len_of_long_text <= 1) { printf("Please give text file with at least two character.\nAgain:\n"); fclose (fp); continue;} Pstring = (char*) malloc ((len_of_long_text+1) * sizeof(char)); // המסיים NULL מוסיפים 1 עבור ה if (Pstring == NULL) { printf("\nNo enough memory! %d characters in the file.\nAgain:\n", len_of_long_text); fclose (fp); continue; } break; }while(1); fclose (fp); strcpy(Pstring, get_a_big_string); return Pstring; } void main(){ char *P_long_text, **Array_of_words; int n, i, *The_sum_of_occurrences_of_each_word; do{ n = Get_Save_int_Number_From_User("From text file or type now? ('1'-file / '2'-text): "); }while (n!=1 && n!=2); if(n==1) { P_long_text = From_Text_File_To_dynamic_String(); if (len_of_long_text < 80 ) printf("%s\n\n", P_long_text); } else P_long_text = From_Big_String_To_dynamic_String(); do{ n = Get_Save_int_Number_From_User("Enter the number of words you want to search: "); }while(n<=0); The_sum_of_occurrences_of_each_word = (int*) malloc(n * sizeof(int)); Array_of_words = (char**) calloc(n, sizeof(char*)); /* "This_word_already_exists()" בכוונה כאן יש קאלוק ולא מאלוק, עבור הפונקציה */ for(i=0; i<n; i++){ From_Big_word_To_dynamic_word(i, Array_of_words); The_sum_of_occurrences_of_each_word[i] = How_many_times_the_word_appear(Array_of_words[i], P_long_text, len_of_long_text); } printf("\n\n\n---Results:\n"); for(i=0; i<n; i++){ printf("Word number %d (\"%s\") appears in the text:\n%d times\n\n", i+1, Array_of_words[i], The_sum_of_occurrences_of_each_word[i]); } { free(P_long_text); for(i=0; i<n; i++){ free(Array_of_words[i]); } free(Array_of_words); free(The_sum_of_occurrences_of_each_word); } scanf("%d",&n); // שלא תיסגר התוכנית }
בהצלחה.
אין תגובות:
הוסף רשומת תגובה