יום ראשון, 22 באוקטובר 2017

תוכנית רצינית - חיפוש מילים בטקסט

במשימה זו עלינו לכתוב תוכנית לחיפוש מספר מילים בתוך קטע טקסט ארוך.
על התוכנית להשיב כמה פעמים מופיעה כל מילה.


פרטים:

- התוכנית מקבלת מהמשתמש (באמצעות קובץ טקסט או הקלדה ישירה למסך) טקסט ארוך ושומרת אותו במערך long_text.
[באמצעות הקצאה דינאמית משתמשת בזיכרון המינימלי שנחוץ]

- התוכנית מקבלת מהמשתמש מספר n. מספר זה מייצג את מספר המילים שהמשתמש רוצה לחפש.
[ניצור מערך בגודל n שיכיל בעתיד מצביעים לכל המילים. גם זה בשימוש בהקצאה דינאמית]

- התוכנית קולטת מהמשתמש n מילים. כל מילה חייבת להכיל לפחות תו אחד, אחרת אינה חוקית.
  כמובן שמילה לא יכולה להכיל רווחים, tab, או אנטר.
  שימו לב: אסור לאותה מילה להיכנס פעמיים למאגר המילים.
[באמצעות הקצאה דינאמית כל מילה תשתמש בזיכרון המינימלי שנחוץ לה]

- התוכנית מדפיסה כמה פעמים מופיעה כל מילה במערך long_text.
  התוכנית מחפשת רק כמה פעמים המילה מופיעה לבדה ב-long_text, ולא כחלק ממילה אחרת.
  לדוגמה, התוכנית תשיב שהמילה "עם" מופיעה בטקסט "עם נועם" פעם אחת ולא פעמיים.


- על התוכנית להיות בטוחה ככל האפשר מקלט לא מתאים של המשתמש (כלומר היא תדע להגיב לו בלי שגיאות).





נסו לכתוב את הקוד בעצמכם!





תוכנית שכתבתי בשפת C:
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 *wordconst char *long_texint Len_of_long_text){
 int sum = 0, i, j, word_len;
 word_len = strlen(word);
 
 if(word_len>Len_of_long_textreturn 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(tmpStrArray_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 numconst 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]!=NULLcontinue;
 
  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); // שלא תיסגר התוכנית
}






בהצלחה.






אין תגובות:

הוסף רשומת תגובה