fuzzy_duplicate_detector 1.0.0 copy "fuzzy_duplicate_detector: ^1.0.0" to clipboard
fuzzy_duplicate_detector: ^1.0.0 copied to clipboard

A lightweight Dart/Flutter package for detecting fuzzy duplicates in Arabic and English text using phonetic matching, edit distance, and similarity scoring, with support for diacritics removal, transl [...]

example/main.dart

// ignore_for_file: avoid_print
import 'package:fuzzy_duplicate_detector/fuzzy_duplicate_detector.dart';

void main() {
  _example1BasicUsage();
  _example2SinglePair();
  _example3CustomConfig();
  _example4AsMap();
  _example5Deduplicate();
  _example6CrmUseCase();
  _example7BankingKyc();
  _example8Reporting();
}

// ════════════════════════════════════════════════════════════════════════════
// Example 1 — Basic usage
// ════════════════════════════════════════════════════════════════════════════
void _example1BasicUsage() {
  _header('Example 1 — Basic Usage');

  final names = [
    'محمد علي',
    'محمد عَلي',   // same name, diacritics
    'M.ALI',        // transliterated + punctuation
    'أحمد',         // different person
    'علي محمد',     // word-order swap
  ];

  final groups = FuzzyDedup.find(names);

  if (groups.isEmpty) {
    print('No duplicate groups found.');
  } else {
    for (final g in groups) {
      print('📌 Group (${g.confidencePercent} avg confidence)');
      print('   Canonical : "${g.canonical}"');
      print('   Members   : ${g.members}');
      print('   Size      : ${g.size}');
      print('');
    }
  }
}

// ════════════════════════════════════════════════════════════════════════════
// Example 2 — Single pair deep analysis
// ════════════════════════════════════════════════════════════════════════════
void _example2SinglePair() {
  _header('Example 2 — Single Pair Deep Analysis');

  final pairs = [
    ('محمد علي',   'محمد عَلي'),
    ('Abdullah',   'عبدالله'),
    ('مصطفى',      'مصطفي'),
    ('Mohamed',    'محمد'),
    ('completely', 'different'),
  ];

  for (final (a, b) in pairs) {
    final r = FuzzyDedup.compare(
      a, b,
      config: const DedupConfig(threshold: 0.70, enableTransliteration: true),
    );
    print(r.toString());
  }
  print('');

  // Detailed breakdown for one pair
  print('── Detailed Breakdown ──────────────────────');
  final detail = FuzzyDedup.compare('Abdullah', 'عبدالله',
      config: const DedupConfig(
          threshold: 0.60, enableTransliteration: true));
  print(detail.toDetailedString());
  print('');
}

// ════════════════════════════════════════════════════════════════════════════
// Example 3 — Custom config & presets
// ════════════════════════════════════════════════════════════════════════════
void _example3CustomConfig() {
  _header('Example 3 — Config Presets');

  final names = ['عمر', 'عمرو', 'محمد', 'محمود', 'أحمد', 'أحمد'];

  final strict  = FuzzyDedup.find(names, config: DedupConfig.strict);
  final normal  = FuzzyDedup.find(names);
  final lenient = FuzzyDedup.find(names, config: DedupConfig.lenient);

  print('Strict  (≥92%) : ${strict.length} group(s)');
  print('Normal  (≥80%) : ${normal.length} group(s)');
  print('Lenient (≥65%) : ${lenient.length} group(s)');
  print('');

  // Custom weights
  final phoneticHeavy = FuzzyDedup.find(
    names,
    config: DedupConfig(
      threshold: 0.75,
      weights: AlgorithmWeights.phoneticHeavy,
    ),
  );
  print('PhoneticHeavy weights: ${phoneticHeavy.length} group(s)');
  print('');
}

// ════════════════════════════════════════════════════════════════════════════
// Example 4 — findAsMap()
// ════════════════════════════════════════════════════════════════════════════
void _example4AsMap() {
  _header('Example 4 — As Map');

  final names = [
    'محمد علي',
    'محمد عَلي',
    'أحمد',
    'احمد',        // Alef variant
    'خالد',
    'فاطمة',
    'فاطمه',       // Teh Marbuta variant
  ];

  final map = FuzzyDedup.findAsMap(names);
  map.forEach((canonical, dups) {
    print('  "$canonical"  →  $dups');
  });
  print('');
}

// ════════════════════════════════════════════════════════════════════════════
// Example 5 — deduplicate()
// ════════════════════════════════════════════════════════════════════════════
void _example5Deduplicate() {
  _header('Example 5 — deduplicate()');

  final raw = [
    'محمد علي',
    'محمد عَلي',   // ← duplicate
    'خالد',
    'أحمد',
    'احمد',        // ← duplicate
    'نورة',
  ];

  print('Before: $raw');
  final clean = FuzzyDedup.deduplicate(raw);
  print('After : $clean');
  print('Reduction: ${raw.length} → ${clean.length} items');
  print('');
}

// ════════════════════════════════════════════════════════════════════════════
// Example 6 — CRM use case
// ════════════════════════════════════════════════════════════════════════════
void _example6CrmUseCase() {
  _header('Example 6 — CRM Customer Deduplication');

  final customers = [
    // Same person, different spellings
    'سارة عبدالله',
    'سارة عبد الله',
    'Sarah Abdullah',
    // Same person, ى vs ي inconsistency
    'خالد الغامدي',
    'خالد الغامدى',
    // Exact duplicate
    'فيصل بن سعود',
    'فيصل بن سعود',
    // Close but different
    'عمر الشريف',
    'عمرو الشريف',
    // Cross-script
    'Nora Ahmed',
    'نورة أحمد',
  ];

  const crmConfig = DedupConfig(
    threshold: 0.72,
    enableTransliteration: true,
  );

  final groups = FuzzyDedup.find(customers, config: crmConfig);
  print('Found ${groups.length} duplicate group(s) in ${customers.length} customer records:\n');

  for (int i = 0; i < groups.length; i++) {
    final g = groups[i];
    print('  Group ${i + 1}  →  Canonical: "${g.canonical}"');
    print('           Members : ${g.members}');
    print('           Avg confidence: ${g.confidencePercent}');
    print('');
  }
}

// ════════════════════════════════════════════════════════════════════════════
// Example 7 — Banking KYC (strict mode)
// ════════════════════════════════════════════════════════════════════════════
void _example7BankingKyc() {
  _header('Example 7 — Banking KYC (Strict Mode)');

  final applicants = [
    'أحمد محمد يوسف',
    'احمد محمد يوسف',     // Alef variant
    'Ahmed Mohamed Yousef',
    'سعد الدين ابراهيم',
    'سعدالدين إبراهيم',   // spacing + Alef variant
    'منى الأحمدي',
    'منى الاحمدي',
  ];

  final groups = FuzzyDedup.find(
    applicants,
    config: DedupConfig.strict,  // high precision for banking
  );

  print('Strict KYC dedup (threshold=0.92):');
  print('  Input records : ${applicants.length}');
  print('  Duplicate groups found: ${groups.length}');
  for (final g in groups) {
    print('  ⚠️  POTENTIAL DUPLICATE: ${g.members}  (${g.confidencePercent})');
  }
  print('');
}

// ════════════════════════════════════════════════════════════════════════════
// Example 8 — groupSummary() report
// ════════════════════════════════════════════════════════════════════════════
void _example8Reporting() {
  _header('Example 8 — Group Summary Report');

  final data = [
    'محمد علي', 'محمد عَلي', 'م.علي',
    'عبدالله', 'عبد الله',
    'خالد',
  ];

  print(FuzzyDedup.groupSummary(
    data,
    config: const DedupConfig(threshold: 0.70),
  ));
}

// ── Utility ─────────────────────────────────────────────────────────────────
void _header(String title) {
  print('\n${'═' * 60}');
  print('  $title');
  print('${'═' * 60}\n');
}
0
likes
140
points
23
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A lightweight Dart/Flutter package for detecting fuzzy duplicates in Arabic and English text using phonetic matching, edit distance, and similarity scoring, with support for diacritics removal, transliteration, and word-order-independent comparison.

Repository (GitHub)
View/report issues

Topics

#text #nlp #fuzzy-matching #deduplication #arabic

License

MIT (license)

Dependencies

characters, collection

More

Packages that depend on fuzzy_duplicate_detector