fuzzy_duplicate_detector 1.0.0
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 [...]
// 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');
}