תוכנית חיפוש בC# - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

תוכנית חיפוש בC#


~שירה

Recommended Posts

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

איך עושים את זה?

איך עושים את זה?

איך לחפש ביטויים מורכבים עם && או || או ()?

קישור לתוכן
שתף באתרים אחרים

קודם כל תצטרכי להסביר קצת יותר טוב.

התכנית צריכה לחפש מחרוזת כמו שהיא, או שהיא צריכה לחפש מילים נפרדות?

אם החיפוש הוא חד פעמי, לא כדאי לשמור את המילים מהטקסט במילון. הכי פשוט זה לפתוח את הקובץ, וכל פעם לקרוא שורה ממנו ולבצע את החיפוש בתוכה.

קישור לתוכן
שתף באתרים אחרים

התכנית מקבלת מהמשתמש שם של קובץ מתיקיה מסוימת (ובודקת אם הוא נמצא).

מחפשת מילים או מחרוזת. (או סופרת מספר מופעים של מילה או ביטוי).

החיפוש הוא רב פעמי -אז איך כדאי לשמור את המילים? ולבנות מנגנון חיפוש שיתאים לכמה קבצים ?

קישור לתוכן
שתף באתרים אחרים

בעקרון מה שאת רוצה לעשות זה מנגנון אינדקס:

http://en.wikipedia.org/wiki/Index_(search_engine)

באופן הכי פשטני, את רוצה לממש מילון (Dictionary) שעבור כל מילה שנתקלת בה, הוא יחזיק רשימה המכילה את שמות הקבצים שבהם המילה מופיעה (ואת יכולה להוסיף פרטים נוספים, כמו איפה מופיעה המילה בתוך הקובץ, וכמה פעמים).

החיפוש ייעשה ע"י שליפת הרשימות הנ"ל מתוך המילון. אם לדוגמה את רוצה לחפש את כל הקבצים שמופיעה בהם אחת מכמה מילים נתונות, אז תחפשי כל מילה בנפרד ותאחדי את התוצאות. אם את רוצה לחפש את כל הקבצים שמופיעות בהם כל המילים הנתונות, אז תצליבי את התוצאות.

קישור לתוכן
שתף באתרים אחרים

אם מצאתי את המילה בקובץ - ויש לי את ההסט אליה מתחילת הקובץ, איך אני יכולה לקרוא את השורה שלה (נניח5 מילים לפניה ואחריה?)

ניסיתי ככה וה לא עובד:


//המופע הראשון של המילה בקובץ
firstMofa = dictionary[words[0][0] - 'a'][i].appear[0];

int index = Convert.ToInt32(firstMofa);
index = index - 50;
if (index < 0)
{
index = 0;
}


//פתיחת הקובץ לקריאה
TextReader currentFile = new StreamReader(path);

currentFile.ReadBlock(result.ToCharArray(), index, 100);

וגם - איך לבדוק ש50 ביטים לפני זה לא אמצע מילה, ושקראתי 5 מילים לפחות?

קישור לתוכן
שתף באתרים אחרים

אי אפשר ככה, כי את לא יכולה לדעת מראש כמה תווים תתפוס כל שורה או מילה.

הדרך היחידה היא לקרוא כל שורה בנפרד, ולחשב את האינדקס המצטבר.

כלומר, נניח שבקובץ יש 5 שורות באורכים 10,20,15,30,40, והמילה שאת מחפשת נמצאת באינדקס 40.

אז בהתחלה האינדקס יצביע ל-0. את קוראת שורה ראשונה, רואה שהיא באורך 10, אז את מוסיפה לאינדקס 10. קוראת שורה שנייה, רואה שהיא באורך 20, אז את מוסיפה 20 לאינדקס ויש לך 30. קוראת שורה שלישית, רואה שהיא באורך 15, מוסיפה לאינדקס, וקיבלת 45. כלומר המילה שאת מחפשת נמצאת בשורה השלישית (כי היא בין האינדקסים 30 ו-45).

כמובן אפשר לעשוןת את זה בצורה יעילה - בזמן האינדוקס, את יכולה לרשום לא רק באיזה מקום בקובץ מופיעה המילה, אלא איפה בקובץ מתחילה השורה שבה היא נמצאת, ועוד פרטים (הרי המילון שלך לא חייב להיות של int, הוא יכול להחזיק גם מבנים יותר מתוחכמים).

קישור לתוכן
שתף באתרים אחרים

נראה לי שמסתבכים פה יותר מדי.

לפי הפוסט הראשון הקלט של התוכנה הוא:

1. הקובץ שבו יש לחפש את המחרוזת

2. המחרוזת אותה יש לחפש

מזה אני מבין שכל פעם שהתוכנה מורצת יכול להיות שהיא מחפשת בקובץ אחר. כלומר אין סיבה לעשות אינדוקס - הרי עבור כל קובץ מתבצע חיפוש אחד. יותר מהר לעשות חיפוש לא מאונדקס מלאנדקס ואז להריץ חיפוש אחד.

לפני שאת מממשת חיפוש מאונקס, בדקי שהמימוש הזה לא מספיק מהיר בשבילך:


TextReader fileReader = new StreamReader(filePath);
string line = fileReader.ReadLine();
while(!string.IsNullOrEmpty(line))
if (line.Contains(requestedText))
return line;

קישור לתוכן
שתף באתרים אחרים

בשביל זה את צריכה לבנות קודם כל מנגנון שיידע לפרסר (parse) מחרוזות מהצורה הזו (באמצעות חיפושים בתוך המחרוזת הנתונה, או באמצעות ביטויים רגולרים).

המנגנון יפרק את המחרוזת לרכיבים השונים שלה, ואז תוכלי לחפש כל אחד מהם בנפרד, ולהרכיב את התוצאות בחזרה.

קישור לתוכן
שתף באתרים אחרים

את בעצם רוצה instance של אובייקט שתבני אותו בתחילת התוכנית ע"פ המחרוזת שנותן המשתמש ואז תריצי מתודה שלו על כל שורה בקובץ והיא תחזיר אמת (השורה עונה על התנאי) או שקר (השורה לא עונה על התנאי).

זה תרגיל טוב בOOP.

יש שלושה סוגים של תנאים (מעכשיו Conditions): תנאי Contains, תנאי Or ותנאי And. כולם מחלקות שיורשות ממחלקה אבסטרקטית Condition (כנראה שכדאי ש AndCondition ו- OrCondition ירשו ממחלקה אבסטרקטית ConditionWithChildren שתירש מCondition אבל זה לא אסון עיצובי אם בהתחלה כל השלוש יורשות ישירות מ-Condition ן).

Condition מכילה מתודה אבסטרקטית

abstract bool IsLineMeetsCondition(string line);

שתמומש בצורה שונה עבור כל אחת משלושת המחלקות שיורשות מ Condition כך:

AndCondition תחזיר אמת אם ההרצה של הפונקציה IsLineMeetsCondition על כל הבנים מחזירה אמת, אחרת שקר.

OrCondition תחזיר אמת אם ההרצה של הפונקציה על לפחות אחד מהבנים מחזירה אמת.

ContainsCondition תחזיר אמת אם המחרוזת נמצאת ב-line.

החלק הכי קשה בכל הסיפור הוא לבנות בפעם הראשונה את המחלקות האלה מהקלט של המשתמש. אני ממליץ להכריח את המשתמש להכניס את הקלט שלו בדומה לאיך שקוראים לפונקציות בשפת התכנות Scheme (אפשר לראות דוגמאות בויקיפדיה ואני גם מפרט פה). לדוגמא, בשביל להציג שורות שיש בהן foo או bar המשתמש יצטרך להכניס:

(OR foo bar)

בשביל להציג שורות שיש בהן גם foo וגם אחת מהמחרוזות: bar1 bar2 המשתמש יכניס

(AND foo (OR bar1 bar2))

זה פחות אינטואיטיבי למשתמש ואפשר להחליף את השיטה הזאת למשהו יותר נורמאלי בהמשך, אבל זאת דרך טובה להתחיל לפתור את הבעייה.

קישור לתוכן
שתף באתרים אחרים



//פתיחת הקובץ לאינדוקס
TextReader currentFile = new StreamReader(path + '/' + filename + ".txt");//פתיחת הקובץ לאינדוקס


TextReader stopFile = null;//פתיחת קובץ סטופ
if (File.Exists(path + '/' + this.docName + ".stop"))//if stop file exists.
{
stopFile = new StreamReader(path + '/' + this.docName + ".stop");
}
else
{
stopFile = new StreamReader(path.Substring(0, path.Length - nameFromPath(path).Length) + "lst.stop");
}


string[] noIndex = stopFile.ReadToEnd().Split('\n');
if (noIndex.Length > 0)
{
noIndex[0] = noIndex[0].Substring(0, noIndex[0].Length - 1);
}

long offset = 0; //ההסט של המילה מתחילת הקובץ
string nextLine = currentFile.ReadLine(); //קריאת שורה מהקובץ
string[] word;
milon temp;
mikum mk;
bool kayam = false;
long lineNum = -1;


dictionary = new List<milon>[26];//הצהרה על מערך של רשימות בגודל 26
int moneWord;

for (i = 0; i < 26; i++)
{
dictionary[i] = new List<milon>();
}

//קריאת הקובץ לפי שורות
while (nextLine != null)
{
word = nextLine.Split(' ');//חלוקה למילים
moneWord = -1;
lineNum = lineNum + 1;

while (moneWord < word.Length)//כל עוד יש מילים בשורה
{
moneWord++;

if ((word[moneWord] == "") || (noIndex.Contains<string>(word[moneWord])))//if the word does not appear in stop file as non-index word, it should be indexed.
{
continue;
}
else
{//enter to dictionary

if (word[moneWord] == "")
{
moneWord++;
}
if ((IsTav(word[moneWord][0]) == true) && (dictionary[word[moneWord][0] - 'a'].Count == 0))
{//יצירת רשימה
temp = new milon(word[moneWord][0], word[moneWord], offset, lineNum);
dictionary[word[moneWord][0] - 'a'].Add(temp);
}
else if (IsTav(word[moneWord][0]) == true)
{//הכנסה לרשימה

temp = new milon(word[moneWord][0], word[moneWord], offset, lineNum);

//בדיקה אם המילה קיימת
for (i = 0; i < dictionary[word[moneWord][0] - 'a'].Count; i++)
{
if (dictionary[word[moneWord][0] - 'a'][i].Word == word[moneWord])
{//עדכון המופעים של המילה

mk = new mikum(offset, lineNum);
dictionary[word[moneWord][0] - 'a'][i].Appear.Add(mk);
kayam = true;
break;
}
}
if (kayam == false)
{///הוספת מילה
dictionary[word[moneWord][0] - 'a'].Add(temp);
}
}

}

offset = offset + word[moneWord].Length;
kayam = false;

if (moneWord == word.Length - 1)
{
break;
}
}

nextLine = currentFile.ReadLine();
}

this.beNewIdx = true;
}

הערב: בקובץ סטופ יש מילים שלא נכנסות לאינדקס.

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

×
  • צור חדש...