شارك المقالة

شرح مكتبة arabic_search في Flutter لتحسين البحث باللغة العربية

البحث داخل التطبيقات يعتبر من الوظائف الأساسية في كثير من مشاريع Flutter، ولكن عندما يكون التطبيق باللغة العربية تظهر مجموعة من المشاكل التي لا تظهر بنفس الصورة عند التعامل مع اللغة الإنجليزية.

فمثلًا يمكن أن يكتب المستخدم كلمة إسلام بينما تكون القيمة المخزنة داخل التطبيق اسلام، أو يبحث عن الاتصالات بينما تكون البيانات مكتوبة الإتصالات، وفي هذه الحالة قد يفشل البحث التقليدي باستخدام contains() رغم أن الكلمتين تحملان المعنى نفسه.

نفس المشكلة تظهر مع التشكيل، والمد، واختلاف شكل الألف والياء، وكذلك الأرقام العربية والإنجليزية.

هنا تأتي مكتبة arabic_search التي تم تصميمها خصيصًا لمعالجة مشاكل البحث العربي داخل تطبيقات Dart وFlutter، من خلال توحيد النصوص قبل البحث وإنشاء Search Keys تساعد على الوصول إلى النتائج بشكل أكثر دقة.

ما هي مكتبة arabic_search؟

مكتبة arabic_search هي Package مخصصة لتطبيع النص العربي وتحسين عمليات البحث والفلترة والمقارنة داخل تطبيقات Flutter أو أي مشروع يعمل باستخدام Dart.

الفكرة الأساسية للمكتبة هي تحويل الأشكال المختلفة للنص العربي إلى صيغة موحدة يمكن استخدامها في البحث، وبالتالي لا يصبح المستخدم مضطرًا لكتابة الكلمة بنفس الشكل الموجود حرفيًا داخل قاعدة البيانات.

على سبيل المثال يمكن التعامل مع الحالات التالية على أنها متقاربة في عملية البحث:

  • إسلام / اسلام
  • الإتصالات / الاتصالات
  • مُحَمَّد / محمد
  • ١٢٣ / 123

المكتبة تعمل كأداة مستقلة عن واجهة المستخدم، لذلك يمكنك استخدامها مع List أو البيانات القادمة من API أو قاعدة بيانات محلية أو أي مصدر آخر للبيانات.

لماذا نحتاج إلى مكتبة للبحث العربي في Flutter؟

عند تنفيذ البحث بالطريقة التقليدية، قد تقوم بكتابة:

final results = products
    .where((item) => item.name.contains(query))
    .toList();

هذه الطريقة تعمل عندما يكون النص متطابقًا تقريبًا، ولكنها لا تأخذ بعين الاعتبار الاختلافات الموجودة في كتابة اللغة العربية.

فإذا كان الاسم داخل البيانات:

مُحَمَّد

وقام المستخدم بكتابة:

محمد

فقد لا تحصل على النتيجة المطلوبة باستخدام contains() فقط.

مكتبة arabic_search تحل هذه المشكلة من خلال تطبيع النص قبل تنفيذ المقارنة.

مميزات مكتبة arabic_search

توفر المكتبة مجموعة من الوظائف التي تركز بشكل مباشر على معالجة النص العربي والبحث داخله.

  • إزالة التشكيل من النص العربي.
  • إزالة الـ Tatweel أو المد مثل ـ.
  • توحيد أشكال الألف أ / إ / آ / ٱ إلى ا.
  • توحيد الياء ى إلى ي.
  • توحيد التاء المربوطة ة إلى ه في وضع البحث.
  • تحويل الأرقام العربية إلى الإنجليزية والعكس.
  • إنشاء Search Keys مناسبة للبحث.
  • البحث باستخدام أكثر من كلمة.
  • دعم البحث بنمط AND أو OR.
  • دعم Ranked Search وترتيب النتائج حسب درجة التطابق.
  • إمكانية البحث داخل قوائم تحتوي على Search Keys محفوظة مسبقًا.
  • توفير Extensions لتسهيل التعامل مع النصوص والقوائم.
  • تعمل باستخدام Dart ويمكن استخدامها داخل Flutter أو Backend مكتوب بـ Dart.

هذه الوظائف تجعلها مفيدة بشكل خاص في التطبيقات التي تحتوي على عدد كبير من البيانات العربية وتحتاج إلى Search Experience أكثر مرونة.

تثبيت مكتبة arabic_search

يمكن إضافة المكتبة إلى مشروع Flutter باستخدام الأمر:

dart pub add arabic_search

أو إضافتها يدويًا داخل ملف pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter

  arabic_search: ^0.2.3

بعد ذلك قم بتشغيل:

flutter pub get

الإصدار الحالي الموجود على pub.dev هو 0.2.3، ويتطلب Dart SDK 3.3 على الأقل. كما أن الحزمة تدعم Android وiOS وWeb وWindows وmacOS وLinux.

استيراد المكتبة داخل Flutter

بعد التثبيت يمكنك استيراد المكتبة داخل ملف Dart:

import 'package:arabic_search/arabic_search.dart';

إنشاء Search Key للنص العربي

أحد أهم المفاهيم في المكتبة هو Search Key.

بدلًا من مقارنة النص كما هو، يتم إنشاء نسخة موحدة من النص يمكن استخدامها أثناء البحث.

توضح المكتبة Extensions مثل arabicSearchKey لتسهيل الحصول على القيمة المناسبة للبحث.

const text = 'مُحَمَّد';

final searchKey = text.arabicSearchKey;

print(searchKey);

الفكرة هنا أن النص الأصلي يمكن الاحتفاظ به كما هو لعرضه للمستخدم، بينما يتم استخدام Search Key في عمليات البحث والمقارنة.

البحث مع اختلاف أشكال الألف

من أشهر المشاكل في البحث العربي اختلاف أشكال الألف.

على سبيل المثال:

إسلام
اسلام
الإسلام

المكتبة تقوم بتوحيد أشكال الألف أثناء معالجة النص، مما يجعل البحث أكثر مرونة في مثل هذه الحالات.

وهذا مفيد جدًا في التطبيقات التي تحتوي على أسماء أو منتجات أو مقالات أو بيانات عربية يتم إدخالها من أكثر من مصدر.

إزالة التشكيل والمد

يمكن أن يحتوي النص العربي على علامات التشكيل أو المد، مثل:

مُحَمَّد
الســــلام

وهذه الاختلافات يمكن أن تؤثر على البحث التقليدي، بينما تقوم المكتبة بمعالجتها ضمن عملية التطبيع الخاصة بها.

البحث باستخدام الأرقام العربية والإنجليزية

من المشاكل الشائعة أيضًا اختلاف طريقة كتابة الأرقام.

قد تكون البيانات:

رقم الطلب: 12345

بينما يقوم المستخدم بالبحث عن:

١٢٣٤٥

مكتبة arabic_search تدعم تحويل الأرقام العربية إلى الإنجليزية والعكس، مما يسمح بالتعامل مع الصيغتين أثناء البحث.

استخدام arabicSearchKey مع المنتجات

لنفترض أن لدينا قائمة منتجات داخل تطبيق Flutter:

final products = [
  'تفاح أحمر',
  'موز',
  'إسلام',
  'كتاب البرمجة',
  'هاتف ذكي',
];

يمكن إنشاء Search Key لكل عنصر والاحتفاظ به لاستخدامه أثناء البحث.

final searchKeys = products.map(
  (item) => item.arabicSearchKey,
).toList();

for (final key in searchKeys) {
  print(key);
}

هذه الفكرة مفيدة خصوصًا في التطبيقات التي تنفذ عددًا كبيرًا من عمليات البحث، لأنك تستطيع الاحتفاظ بالقيمة المطبعة بدلًا من إعادة معالجة النص في كل مرة.

البحث داخل List باستخدام arabicSearch

من ضمن Extensions التي تمت إضافتها إلى المكتبة وجود arabicSearch() للعمل مباشرة مع القوائم.

final products = [
  'هاتف سامسونج',
  'هاتف آيفون',
  'جهاز كمبيوتر',
  'هاتف هواوي',
];

final results = products.arabicSearch('هاتف');

وبذلك يمكن الحصول على العناصر المطابقة دون الحاجة إلى كتابة عملية التطبيع والفلترة يدويًا في كل مشروع.

البحث باستخدام أكثر من كلمة

تدعم المكتبة أيضًا مفهوم البحث المعتمد على Tokens، وهو مفيد عندما يكتب المستخدم أكثر من كلمة في مربع البحث.

على سبيل المثال:

هاتف سامسونج

يمكن للمكتبة تقسيم الاستعلام إلى كلمات مستقلة والتعامل معها أثناء عملية البحث بدلًا من اعتبار النص عبارة واحدة فقط.

ووفق تحديثات الإصدار 0.2.x أصبح من الممكن التعامل مع البحث باستخدام AND أو OR، بحيث يمكنك تحديد ما إذا كنت تريد ظهور العناصر التي تحتوي على جميع الكلمات أو أي كلمة منها.

البحث بنظام AND و OR

في تطبيقات المتاجر مثلًا، قد يكون المستخدم يبحث عن:

هاتف سامسونج

في وضع AND يكون المطلوب العثور على العناصر التي تحتوي على الكلمتين.

بينما في وضع OR يمكن أن تظهر العناصر التي تحتوي على إحدى الكلمات.

هذا النوع من البحث يكون مفيدًا جدًا مع Search Bars التي تسمح للمستخدم بإدخال أكثر من كلمة.

Ranked Search في Flutter

البحث التقليدي يعتمد غالبًا على وجود تطابق أو عدم وجوده، ولكن في بعض الحالات نحتاج إلى ترتيب النتائج حسب قوة التطابق.

تضيف مكتبة arabic_search دعمًا لـ Ranked Search، بحيث يتم إعطاء التطابقات درجات مختلفة وفقًا لقوة المطابقة.

منطق الترتيب في النسخ الحديثة يميز بين:

  • Exact Match.
  • Prefix Match.
  • Contains Match.

وبالتالي يمكن وضع النتائج الأكثر ارتباطًا بالاستعلام في البداية بدلًا من عرضها بترتيب عشوائي.

استخدام Search Keys المحفوظة مسبقًا

عندما يحتوي التطبيق على آلاف العناصر، قد لا يكون من الأفضل معالجة النص الأصلي مرة جديدة مع كل عملية بحث.

لهذا أضافت المكتبة searchInListNormalized() للتعامل مع القوائم التي تم تجهيز Search Keys الخاصة بها مسبقًا.

الفكرة تكون كالتالي:

البيانات الأصلية
        ↓
إنشاء Search Key
        ↓
تخزين Search Key
        ↓
تنفيذ البحث
        ↓
إظهار النتائج

هذا الأسلوب يمكن أن يكون مفيدًا في التطبيقات الكبيرة التي تحتوي على عدد كبير من العناصر وعمليات البحث المتكررة.

استخدام المكتبة مع TextField داخل Flutter

يمكن ربط المكتبة بسهولة مع TextField بحيث يتم تنفيذ البحث عند تغيير النص.

TextField(
  onChanged: (query) {
    final results = products.arabicSearch(query);

    setState(() {
      filteredProducts = results;
    });
  },
  decoration: const InputDecoration(
    hintText: 'ابحث عن منتج',
    prefixIcon: Icon(Icons.search),
  ),
)

في هذه الحالة يصبح المستخدم قادرًا على البحث باستخدام أشكال مختلفة من الكتابة العربية، بينما تتولى المكتبة عملية التطبيع والبحث.

مثال عملي على شاشة بحث عربية

يمكن بناء صفحة بسيطة تحتوي على قائمة منتجات وحقل بحث في أعلى الصفحة:

import 'package:flutter/material.dart';
import 'package:arabic_search/arabic_search.dart';

class ArabicSearchPage extends StatefulWidget {
  const ArabicSearchPage({super.key});

  @override
  State<ArabicSearchPage> createState() => _ArabicSearchPageState();
}

class _ArabicSearchPageState extends State<ArabicSearchPage> {
  final products = const [
    'هاتف سامسونج',
    'هاتف آيفون',
    'جهاز كمبيوتر',
    'سماعة لاسلكية',
    'شاحن سريع',
    'كتاب البرمجة',
  ];

  late List<String> filteredProducts;

  @override
  void initState() {
    super.initState();
    filteredProducts = products;
  }

  void searchProducts(String query) {
    setState(() {
      if (query.trim().isEmpty) {
        filteredProducts = products;
        return;
      }

      filteredProducts = products.arabicSearch(query);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('البحث العربي'),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: TextField(
              textDirection: TextDirection.rtl,
              onChanged: searchProducts,
              decoration: const InputDecoration(
                hintText: 'ابحث عن منتج',
                prefixIcon: Icon(Icons.search),
                border: OutlineInputBorder(),
              ),
            ),
          ),

          Expanded(
            child: ListView.builder(
              itemCount: filteredProducts.length,
              itemBuilder: (context, index) {
                final product = filteredProducts[index];

                return ListTile(
                  title: Text(
                    product,
                    textDirection: TextDirection.rtl,
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

استخدام arabic_search مع بيانات API

يمكن استخدام المكتبة أيضًا مع البيانات القادمة من REST API.

على سبيل المثال قد تحصل على البيانات التالية من الخادم:

[
  {
    "name": "مُحَمَّد",
    "category": "البرمجة"
  },
  {
    "name": "إسلام",
    "category": "التقنية"
  }
]

بعد تحويل البيانات إلى Models داخل Flutter، يمكن إنشاء Search Key لكل اسم أو عنوان واستخدامه في البحث المحلي دون الحاجة إلى إرسال كل عملية بحث إلى الخادم.

استخدام المكتبة مع التطبيقات العربية

يمكن استخدام arabic_search في العديد من أنواع تطبيقات Flutter، ومنها:

  • تطبيقات المتاجر والـ E-Commerce.
  • تطبيقات نقاط البيع POS.
  • تطبيقات الأخبار والمقالات.
  • تطبيقات الكتب والمحتوى العربي.
  • التطبيقات التعليمية.
  • تطبيقات إدارة العملاء والبيانات.
  • تطبيقات البحث داخل قواعد البيانات المحلية.
  • تطبيقات تحتوي على بيانات عربية كبيرة.

هل المكتبة تعمل خارج Flutter؟

نعم، المكتبة مبنية باستخدام Dart ويمكن استخدامها مع Flutter أو أي Backend مكتوب بلغة Dart.

وهذا يجعلها مختلفة عن الحزم المرتبطة فقط بواجهة Flutter، لأنها تركز على معالجة النص والبحث نفسه.

ما الفرق بين arabic_search و contains()؟

الدالة contains() تبحث عن تطابق مباشر داخل النص، ولذلك فهي لا تفهم الاختلافات المتعلقة بالصياغة العربية.

أما arabic_search فتركز على تطبيع النص أولًا، بحيث يتم التعامل مع اختلافات الألف والياء والتشكيل والمد والأرقام، بالإضافة إلى دعم البحث بالكلمات وترتيب النتائج.

لذلك يمكن اعتبار contains() مناسبة للبحث البسيط، بينما توفر arabic_search طبقة أكثر تخصصًا عندما تكون البيانات عربية وتحتاج إلى مرونة أكبر في البحث.

الخلاصة

مكتبة arabic_search تقدم حلًا متخصصًا لمشكلة شائعة في تطبيقات Flutter وهي البحث باللغة العربية.

بدلًا من كتابة مجموعة كبيرة من عمليات replaceAll() ومعالجة كل حالة يدوية داخل كل مشروع، توفر المكتبة طبقة جاهزة لتطبيع النص العربي، وإنشاء Search Keys، والبحث باستخدام الكلمات، وترتيب النتائج حسب قوة التطابق.

وتصبح المكتبة مفيدة بشكل أكبر عندما يحتوي التطبيق على عدد كبير من البيانات العربية، مثل المنتجات أو العملاء أو المقالات أو المحتوى التعليمي، وتحتاج إلى جعل تجربة البحث أكثر مرونة للمستخدم.

إذا كنت تعمل على مشروع Flutter عربي وتستخدم حقل بحث في بيانات التطبيق، فإن arabic_search يمكن أن تكون إضافة مناسبة لبناء نظام بحث يفهم الاختلافات الشائعة في كتابة النص العربي بدل الاعتماد على التطابق الحرفي فقط.



مكتبة arabic_search على pub.dev

المزيد من مقالات Flutter على Geecoders

الكود كامل

import 'package:flutter/material.dart';
import 'package:arabic_search/arabic_search.dart';

class ArabicSearchPage extends StatefulWidget {
  const ArabicSearchPage({super.key});

  @override
  State<ArabicSearchPage> createState() => _ArabicSearchPageState();
}

class _ArabicSearchPageState extends State<ArabicSearchPage> {
  final products = const [
    'هاتف سامسونج',
    'هاتف آيفون',
    'جهاز كمبيوتر',
    'سماعة لاسلكية',
    'شاحن سريع',
    'كتاب البرمجة',
    'إسلام',
    'مُحَمَّد',
  ];

  late List<String> filteredProducts;

  @override
  void initState() {
    super.initState();
    filteredProducts = products;
  }

  void searchProducts(String query) {
    setState(() {
      if (query.trim().isEmpty) {
        filteredProducts = products;
        return;
      }

      filteredProducts = products.arabicSearch(query);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Directionality(
      textDirection: TextDirection.rtl,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('البحث العربي'),
        ),
        body: Column(
          children: [
            Padding(
              padding: const EdgeInsets.all(16),
              child: TextField(
                onChanged: searchProducts,
                decoration: const InputDecoration(
                  hintText: 'ابحث عن منتج أو اسم',
                  prefixIcon: Icon(Icons.search),
                  border: OutlineInputBorder(),
                ),
              ),
            ),

            Expanded(
              child: ListView.builder(
                itemCount: filteredProducts.length,
                itemBuilder: (context, index) {
                  final item = filteredProducts[index];

                  return ListTile(
                    leading: const Icon(Icons.search),
                    title: Text(item),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

إضافة المكتبة إلى المشروع

dependencies:
  flutter:
    sdk: flutter

  arabic_search: ^0.2.3
flutter pub get
شاهد أيضًا
مقالات ذات صلة

🚫 مانع الإعلانات مفعل

يجب إيقاف مانع الإعلانات لاستكمال تصفح الموقع