لماذا يجد بحثنا اسمك حتى لو كتبته بشكل مختلف؟
حين تبحث عن نتيجتك بالاسم، فأنت تكتب اسمك كما تعرفه، لكن الاسم المسجّل في الكشف قد يكون مكتوبًا بشكل آخر: «أحمد» بدل «احمد»، «مصطفى» بدل «مصطفي»، «فاطمة» بدل «فاطمه». هذه الاختلافات الصغيرة هي التي تجعل بحثًا يجد اسمك وآخر يقول لك «لا توجد نتائج».
لنرَ لماذا، بالكود. الأمثلة التالية مبسّطة لتوضيح الفكرة، وهي ليست كود أي موقع بعينه، وكلها تبحث في خمسة أسماء تجريبية:
محمد علي محمد، محمد محمد علي، محمد محمود علي، محمد احمد علي، مريم محمد علي
الطريقة الأولى: البحث بالبداية
يُعرض كل اسم يبدأ بالنص الذي كتبته تمامًا.
الكود بلغة بايثون
from dataclasses import dataclass
@dataclass
class Student:
"""student dataclass"""
id: str
name: str
mark: float
... # other info
student_1 = Student("1", "محمد علي محمد", 320.0)
student_2 = Student("2", "محمد محمد علي", 320.0)
student_3 = Student("3", "محمد محمود علي", 320.0)
student_4 = Student("4", "محمد احمد علي", 320.0)
student_5 = Student("5", "مريم محمد علي", 320.0)
all_students: list[Student] = [student_1, student_2, student_3, student_4, student_5]
def search_by_prefix(name: str) -> list[Student]:
"""return list of students who start with the same exact name"""
result: list[Student] = []
trimmed_name: str = name.strip()
for student in all_students:
if student.name.startswith(trimmed_name):
result.append(student)
return result
def main():
print(
search_by_prefix("محمد علي")
) # [Student(id='1', name='محمد علي محمد', mark=320.0)]
print(search_by_prefix("محمد أحمد")) # []
print(search_by_prefix("محمد علي محمود")) # []
print(
search_by_prefix("محمد محمد")
) # [Student(id='2', name='محمد محمد علي', mark=320.0)]
if __name__ == "__main__":
main()الكود بلغة سي بلس بلس
#include <iostream>
#include <vector>
#include <string>
#ifdef WIN32
#include "Windows.h"
#endif
// g++ -std=c++17 prefix.cpp -o prefix <-DWIN32>
struct Student
{
const std::string_view id;
const std::string_view name;
const double mark;
Student(std::string_view id, std::string_view name, double mark)
: id(id), name(name), mark(mark)
{
}
};
auto student_1 = Student("1", "محمد علي محمد", 329.0);
auto student_2 = Student("2", "محمد محمد علي", 344.0);
auto student_3 = Student("3", "محمد محمود علي", 220.0);
auto student_4 = Student("4", "محمد احمد علي", 310.0);
auto student_5 = Student("5", "مريم محمد علي", 370.0);
const std::vector<Student>
allStudents = {student_1, student_2, student_3, student_4, student_5};
std::string_view trim(std::string_view s)
{
auto is_space = [](unsigned char c)
{ return std::isspace(c); };
size_t start = 0;
while (start < s.size() && is_space(s[start]))
start++;
size_t end = s.size();
while (end > start && is_space(s[end - 1]))
end--;
return s.substr(start, end - start);
}
std::vector<Student> searchByPrefix(const std::string &name)
{
const std::string_view trimmedName = trim(name);
std::vector<Student> result;
result.reserve(1000);
for (auto const &student : allStudents)
{
if (student.name.rfind(trimmedName, 0) == 0)
{
result.emplace_back(student);
}
}
return result;
}
void printStudents(const std::vector<Student> &students)
{
std ::cout << "[";
auto first = true;
for (auto const &student : students)
{
if (!first)
std::cout << ", ";
std::cout << "Student(id='" << student.id << "', " << "name='" << student.name << "', " << "mark=" << student.mark << ")";
first = false;
}
std::cout << "]";
std::cout << "\n";
}
int main()
{
#ifdef WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
printStudents(searchByPrefix("محمد علي")); // [Student(id='1', name='محمد علي محمد', mark=329)]
printStudents(searchByPrefix("محمد أحمد")); // []
printStudents(searchByPrefix("محمد علي محمود")); // []
printStudents(searchByPrefix("محمد محمد")); // [Student(id='2', name='محمد محمد علي', mark=344)]
}وهي سريعة وبسيطة، لكن أي اختلاف في الترتيب أو في شكل حرف واحد يعني «لا نتائج»: من يكتب «محمد أحمد» بالهمزة لا يجد «محمد احمد علي»، ومن يكتب «محمد علي محمود» لا يجد «محمد محمود علي» لأن الترتيب مختلف.
الطريقة الثانية: البحث بالكلمات المطابقة
يُعرض كل اسم تظهر فيه كل كلمة كتبتها كما هي، في أي مكان وبأي ترتيب.
الكود بلغة بايثون
from dataclasses import dataclass
@dataclass
class Student:
"""student dataclass"""
id: str
name: str
mark: float
... # other info
student_1 = Student("1", "محمد علي محمد", 320.0)
student_2 = Student("2", "محمد محمد علي", 320.0)
student_3 = Student("3", "محمد محمود علي", 320.0)
student_4 = Student("4", "محمد احمد علي", 320.0)
student_5 = Student("5", "مريم محمد علي", 320.0)
all_students: list[Student] = [student_1, student_2, student_3, student_4, student_5]
def are_tokens_valid(name_tokens: list[str], candidates_tokens: list[str]) -> bool:
for token in name_tokens:
if token not in candidates_tokens:
return False
return True
def search_by_words(name: str) -> list[Student]:
"""return list of students who share the same exact parts"""
result: list[Student] = []
trimmed_name: str = name.strip()
name_tokens: list[str] = name.split(" ")
for student in all_students:
student_tokens: list[str] = student.name.split(" ")
if are_tokens_valid(name_tokens, student_tokens):
result.append(student)
return result
def main():
print(search_by_words("محمد علي"))
# [Student(id='1', name='محمد علي محمد', mark=320.0),
# Student(id='2', name='محمد محمد علي', mark=320.0),
# Student(id='3', name='محمد محمود علي', mark=320.0),
# Student(id='4', name='محمد احمد علي', mark=320.0),
# Student(id='5', name='مريم محمد علي', mark=320.0)]
print(search_by_words("محمد أحمد")) # []
print(
search_by_words("محمد علي محمود")
) # [Student(id='3', name='محمد محمود علي', mark=320.0)]
print(search_by_words("محمد محمد"))
# [Student(id='1', name='محمد علي محمد', mark=320.0),
# Student(id='2', name='محمد محمد علي', mark=320.0),
# Student(id='3', name='محمد محمود علي', mark=320.0),
# Student(id='4', name='محمد احمد علي', mark=320.0),
# Student(id='5', name='مريم محمد علي', mark=320.0)]
if __name__ == "__main__":
main()الكود بلغة سي بلس بلس
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#ifdef WIN32
#include "Windows.h"
#endif
// g++ -std=c++17 words.cpp -o words <-DWIN32>
struct Student
{
const std::string_view id;
const std::string_view name;
const double mark;
Student(std::string_view id, std::string_view name, double mark)
: id(id), name(name), mark(mark)
{
}
};
auto student_1 = Student("1", "محمد علي محمد", 329.0);
auto student_2 = Student("2", "محمد محمد علي", 344.0);
auto student_3 = Student("3", "محمد محمود علي", 220.0);
auto student_4 = Student("4", "محمد احمد علي", 310.0);
auto student_5 = Student("5", "مريم محمد علي", 370.0);
const std::vector<Student>
allStudents = {student_1, student_2, student_3, student_4, student_5};
constexpr inline bool is_space(unsigned char c)
{
return std::isspace(c);
}
std::string_view trim(std::string_view s)
{
size_t start = 0;
while (start < s.size() && is_space(s[start]))
start++;
size_t end = s.size();
while (end > start && is_space(s[end - 1]))
end--;
return s.substr(start, end - start);
}
bool areTokensValid(const std::vector<std::string_view> &name_tokens,
const std::vector<std::string_view> &candidates_tokens)
{
for (auto &token : name_tokens)
{
if (std::find(std::begin(candidates_tokens), std::end(candidates_tokens), token) == std::end(candidates_tokens))
return false;
}
return true;
}
std::vector<std::string_view> tokenize(const std::string_view &name)
{
std::vector<std::string_view> result;
result.reserve(10);
size_t start = 0;
for (size_t i = 0; i < name.size(); i++)
{
if (is_space(name[i]))
{
auto remainder = i - start;
if (remainder > 0)
{
result.emplace_back(&name[start], i - start);
}
start = i + 1;
}
}
auto remainder = name.size() - start;
if (remainder > 0)
result.emplace_back(&name[start], remainder);
return result;
}
std::vector<Student> searchByWords(const std::string &name)
{
const std::string_view trimmedName = trim(name);
std::vector<Student> result;
result.reserve(100);
auto tokenized_name = tokenize(name);
for (auto const &student : allStudents)
{
auto tokenized_candidate = tokenize(student.name);
if (areTokensValid(tokenized_name, tokenized_candidate))
{
result.emplace_back(student);
}
}
return result;
}
void printStudents(const std::vector<Student> &students)
{
std ::cout << "[";
auto first = true;
for (auto const &student : students)
{
if (!first)
std::cout << ", ";
std::cout << "Student(id='" << student.id << "', " << "name='" << student.name << "', " << "mark=" << student.mark << ")";
first = false;
}
std::cout << "]";
std::cout << "\n";
}
int main()
{
#ifdef WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
printStudents(searchByWords("محمد علي"));
// [Student(id='1', name='محمد علي محمد', mark=329),
// Student(id='2', name='محمد محمد علي', mark=344),
// Student(id='3', name='محمد محمود علي', mark=220),
// Student(id='4', name='محمد احمد علي', mark=310),
// Student(id='5', name='مريم محمد علي', mark=370)]
printStudents(searchByWords("محمد أحمد")); // []
printStudents(searchByWords("محمد علي محمود")); // [Student(id='3', name='محمد محمود علي', mark=220)]
printStudents(searchByWords("محمد محمد"));
// [Student(id='1', name='محمد علي محمد', mark=329),
// Student(id='2', name='محمد محمد علي', mark=344),
// Student(id='3', name='محمد محمود علي', mark=220),
// Student(id='4', name='محمد احمد علي', mark=310),
// Student(id='5', name='مريم محمد علي', mark=370)]
}هذه تحلّ مشكلة الترتيب، لكنها تخلق مشكلة أسوأ: تبحث عن «محمد علي» فيظهر لك أيضًا «مريم محمد علي»، أي طالبة والدها أو جدّها يحمل اسمك. فالكلمة تُعتبر مطابقة أينما وقعت في الاسم، ولا فرق عندها بين الاسم الأول واسم الأب أو الجد. وتبحث عن «محمد محمد» فيظهر كل من اسمه «محمد» مرة واحدة، لأن تكرار الكلمة لا يُحسب. ثم إن النتائج كلها بلا ترتيب، فتبحث عن اسمك وسط الباقين.
وما زالت همزة واحدة كافية لتضيع كل شيء: «محمد أحمد» لا تجد «محمد احمد علي» هنا أيضًا.
ماذا يفعل بحثنا
- يوحّد أشكال الحروف: الهمزات والألف (أ إ آ ا)، والياء والألف المقصورة (ي ى)، والتاء المربوطة والهاء (ة ه)، والتشكيل والتطويل، وغيرها مما يُكتب بأكثر من شكل. فلا يهم كيف كتبت أو كيف سُجّل الاسم.
- يتسامح مع الأخطاء: إن أخطأت في حرف أو نسيت واحدًا فسيجد الأسماء القريبة مما كتبت بدل أن يعيد لك صفحة فارغة.
- يعطي الاسم الأول وزنه: فلا يخلط بينك وبين طالبة والدها أو جدها يحمل اسمك، كما في الطريقة الثانية.
- يرتّب الأقرب أولًا: فيظهر الأقرب إلى ما كتبت في الأعلى بدل أن تقلّب صفحات من الأسماء المتشابهة.
وهذه مقارنة سريعة على الأسماء نفسها:
| ما تكتبه | البحث بالبداية | البحث بالكلمات المطابقة | بحثنا |
|---|---|---|---|
| محمد أحمد | لا شيء | لا شيء | يجد «محمد احمد علي» |
| محمد علي | الأسماء التي تبدأ بـ«محمد علي» فقط | الأسماء الخمسة كلها، حتى «مريم محمد علي» | الأسماء القريبة، الأقرب أولًا، بدون «مريم» |
| محمد احمد | يجد «محمد احمد علي» | يجد «محمد احمد علي» | يجد «محمد احمد علي» |
الفلتر: اسم شائع؟ ضيّق البحث برقم الجلوس
في «علامة الترس» بجانب البحث تجد فلتر رقم الجلوس: تكتب رقم جلوس قريبًا منك (رقمك أنت، أو رقم زميل لك) وتحدد «المدى»، فيبحث الموقع بالاسم بين أصحاب الأرقام القريبة منه فقط. وهذه ميزة لا تجدها في الطرق الأبسط التي رأيتها أعلاه.
وهو يفيدك في أمرين:
- أسرع: يقارن الاسم بعدد أقل بكثير من الأسماء.
- أدق: لن تجد بين النتائج عشرات الأسماء المتشابهة من أنحاء البلاد.
وهو أيضًا الحل الأخير إن كنت لا تذكر من الاسم إلا الاسم الأول: اكتب الاسم الأول، وضع رقمًا قريبًا وحدد المدى، وستظهر لك أسماء من حولك فقط.
البحث المتقدم: مجموعة محددة من الطلاب
إن أردت أن ترى مجموعة محددة من أرقام الجلوس لا طالبًا واحدًا، فاختر «البحث المتقدم» واكتبها كقواعد:
- الفاصلة تفصل الأرقام:
1,2,3 - الشرطة بين رقمين نطاق كامل:
6-10 - الشرطة قبل الرقم أو النطاق تستبعده:
-8 - القواعد تُطبَّق من اليسار إلى اليمين، وآخر قاعدة هي التي تُعتمد.
فالتعبير 1,2,3,6-10,-8 يعرض: 1 و2 و3 و6 و7 و9 و10. وتنبّه إلى أن المجموعات الكبيرة جدًا (فوق خمسين ألف رقم) تبطئ الصفحة، فاجعل المجموعة على قدر حاجتك.
السرعة والاعتمادية
لأن البحث لا يمرّ على خادم واحد يعالج طلبات الجميع، فلا يتأثر بزحام يوم إعلان النتيجة كما يتأثر بحث يعتمد على خادم واحد.
نصائح لنتيجة أدق
- اكتب الأجزاء المميزة من اسمك وتجنّب الأسماء الشائعة مثل «محمد»، فالاسم النادر يضيّق النتائج أكثر بكثير.
- اكتب الاسم القانوني للطالب فقط، كما هو مسجّل في أوراقك، لا اسم الشهرة ولا اسم الدلع.
- إن لم يفلح كل ذلك، استخدم الفلتر بالاسم الأول وحده، واكتبه بعدة صور مختلفة. فبعض الأسماء المركّبة مثل «معتز بالله» وما يشبهها قد تفلت من البحث بحسب طريقة كتابتها (بمسافة أو بدونها أو بغير ذلك)، ولا يمكن حصر كل الصور الممكنة لها. فجرّب أكثر من صورة، وابقَ على الفلتر ليظل البحث أسرع ما يمكن.
- رقم الجلوس يبقى أضمن طريقة، فكل طالب له رقم واحد فقط.
وإن جرّبت كل ما سبق ولم تجد الاسم، فالأرجح أن المشكلة ليست في البحث، بل في أنك تتجسس على نتيجة شخص آخر. وأقصر طريق إليها أن تسأله: «نتيجتك كام؟»
جرّب الآن في صفحة النتيجة.