ثانوية أرشيف المدونة

لماذا يجد بحثنا اسمك حتى لو كتبته بشكل مختلف؟

حين تبحث عن نتيجتك بالاسم،‏ فأنت تكتب اسمك كما تعرفه،‏ لكن الاسم المسجّل في الكشف قد يكون مكتوبًا بشكل آخر: «أحمد» بدل «احمد»،‏ «مصطفى» بدل «مصطفي»،‏ «فاطمة» بدل «فاطمه». هذه الاختلافات الصغيرة هي التي تجعل بحثًا يجد اسمك وآخر يقول لك «لا توجد نتائج».

لنرَ لماذا،‏ بالكود. الأمثلة التالية مبسّطة لتوضيح الفكرة،‏ وهي ليست كود أي موقع بعينه،‏ وكلها تبحث في خمسة أسماء تجريبية:

محمد علي محمد،‏ محمد محمد علي،‏ محمد محمود علي،‏ محمد احمد علي،‏ مريم محمد علي

الطريقة الأولى: البحث بالبداية

يُعرض كل اسم يبدأ بالنص الذي كتبته تمامًا.

الكود بلغة بايثون
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 و7 و9 و10. وتنبّه إلى أن المجموعات الكبيرة جدًا (فوق خمسين ألف رقم) تبطئ الصفحة،‏ فاجعل المجموعة على قدر حاجتك.

السرعة والاعتمادية

لأن البحث لا يمرّ على خادم واحد يعالج طلبات الجميع،‏ فلا يتأثر بزحام يوم إعلان النتيجة كما يتأثر بحث يعتمد على خادم واحد.

نصائح لنتيجة أدق

وإن جرّبت كل ما سبق ولم تجد الاسم،‏ فالأرجح أن المشكلة ليست في البحث،‏ بل في أنك تتجسس على نتيجة شخص آخر. وأقصر طريق إليها أن تسأله: «نتيجتك كام؟»

جرّب الآن في صفحة النتيجة.

وجدت خطأ في المقال أو عندك اقتراح؟ 📧 تواصل معنا

← كل المقالات