الگوریتم ساخت کلمه با حروف چیست؟
الگوریتم ساخت کلمه با حروف در سادهترین تعریف یعنی:
روش پیدا کردن تمام کلمات معتبر زبانی که میتوان از یک مجموعه حرف مشخص ساخت.
این الگوریتم پایه و اساس ابزارهایی مثل کلمهساز، واژهساز، بازی کلمهسازی با حروف و حتی موتورهای پردازش زبان طبیعی است. هدف اصلی آن این است که با گرفتن چند حرف محدود، تمام کلمات ممکن و معتبر زبان فارسی را پیدا کند.
برای درک بهتر، یک مثال ساده بزنیم:
فرض کنید حروف «ر، م، ا» را دارید. الگوریتم باید بتواند مواردی مانند «مار»، «رام»، «امر»، «مر» و… را پیدا کند، اما کلماتی مثل «رومان» را قبول نکرده و کنار بگذارد. این کار فقط زمانی ممکن است که الگوریتم بتواند:
-
تمام ترکیبهای ممکن (Permutations) را ایجاد کند
-
هر ترکیب را در دیتابیس کلمات فارسی بررسی کند
-
از هدر رفتن منابع جلوگیری کند (Pruning)
-
بسیار سریع عمل کند
سیستمهایی مانند Scrabble Solver یا Word Finder در زبانهای دیگر نیز از همین اصول استفاده میکنند. در زبان فارسی البته پیچیدگیها بیشتر است، چون:
-
فرمهای مختلف همزه (أ، آ، إ)
-
یای عربی و فارسی (ی، ى، ئ)
-
کاف عربی (ك)
-
حروفی که چند شکل دارند
همه باید به یک استاندارد یکسان تبدیل شوند.
چرا الگوریتم نیاز به دیتابیس دقیق دارد؟
اگر دیتابیس کامل نباشد، الگوریتم نمیتواند دقیق کار کند. برای مثال، اگر واژهای مثل «آمار» در دیتابیس نباشد، حتی با داشتن تمام حروف آن، خروجی اشتباه خواهد بود.
برای همین، پروژههایی که دیتابیس کامل کلمات فارسی ارائه میدهند اهمیت زیادی دارند.
یکی از این منابع:
دیتابیس کامل تمام کلمات فارسی
ساختار دیتابیس مناسب برای واژهسازها (Word Builder Database Design)
طراحی دیتابیس، قلب اصلی یک سیستم با این حروف کلمه بساز است. اگر دیتابیس درست طراحی نشود، هیچ الگوریتمی—even با بهترین سختافزار—به سرعت مطلوب نمیرسد.
در این مقاله از ساختار دیتابیسی استفاده میکنیم که شامل دو جدول اصلی است:
۱. جدول words (کلمات)
این جدول فهرست کامل تمام کلمات فارسی را نگه میدارد:
| ستون | نوع داده | توضیح |
|---|---|---|
| id | INT | شناسه یکتا |
| word | VARCHAR | کلمه تمیزشده |
| main | VARCHAR | شکل اصلی کلمه |
| length | TINYINT | طول کلمه |
این جدول به الگوریتم اجازه میدهد بهراحتی طول کلمات را فیلتر کند و نسخه استاندارد کلمه را حفظ کند.
۲. جدول characters (کاراکترهای هر کلمه)
برای سرعت بالا، هر کلمه به حروف جداگانه تبدیل میشود:
| ستون | نوع داده | توضیح |
|---|---|---|
| char_id | TINYINT | شناسه حرف (۱ تا ۳۲) |
| word_id | INT | ارجاع به جدول words |
این طراحی یک مزیت بسیار مهم دارد:
به جای پردازش رشته، از مقادیر عددی استفاده میکنیم که سرعت را چندین برابر افزایش میدهد.
چگونگی تبدیل حرف به شناسه (char_id)
این تابع نمونه نحوه نگاشت حروف فارسی به اعداد را نشان میدهد:
function getLetterId($letter)
{
$letters_array = [
'ا' => 1, 'آ' => 1, 'أ' => 1, 'إ' => 1, 'ب' => 2, 'پ' => 3, 'ت' => 4, 'ث' => 5,
'ج' => 6, 'چ' => 7, 'ح' => 8, 'خ' => 9, 'د' => 10,
'ذ' => 11, 'ر' => 12, 'ز' => 13, 'ژ' => 14, 'س' => 15,
'ش' => 16, 'ص' => 17, 'ض' => 18, 'ط' => 19, 'ظ' => 20,
'ع' => 21, 'غ' => 22, 'ف' => 23, 'ق' => 24, 'ک' => 25, 'ك' => 25,
'گ' => 26, 'ل' => 27, 'م' => 28, 'ن' => 29, 'و' => 30,
'ه' => 31, 'ی' => 32, 'ئ' => 32, 'ى' => 32
];
return $letters_array[$letter] ?? 0;
}
چرا این روش مهم است؟
-
حرفهای معادل مثل «آ»، «أ»، «ا» یکسانسازی میشوند.
-
دیتابیس سرعت جستجو را تا ۱۰ برابر بالا میبرد.
-
برای الگوریتم ساخت کلمه، مقایسه اعداد بسیار سریعتر از مقایسه کاراکترهای Unicode است.
| معیار | رشتهای | مبتنی بر char_id |
|---|---|---|
| سرعت جستجو | پایین | بسیار بالا |
| مصرف حافظه | بیشتر | کمتر |
| یکسانسازی حروف | سخت | آسان |
| مناسب برای الگوریتمهای ترکیبسازی | ضعیف | عالی |
روشهای الگوریتمی ساخت کلمه با حروف (Word Generation Algorithms)
برای اینکه یک کلمهساز واقعی بسازیم، فقط داشتن دیتابیس کافی نیست. باید بدانیم چگونه از میان میلیونها حالت ممکن، دقیقاً کلماتی را پیدا کنیم که از حروف ورودی ساخته میشوند. اینجا وارد دنیای الگوریتمها میشویم.
در ادامه، سه رویکرد اصلی و علمی که در ابزارهای حرفهای بازی کلمه سازی با حروف فارسی و سیستمهای NLP استفاده میشود را بررسی میکنم.
۱. الگوریتم Permutation + Validation (روش کلاسیک اما پرهزینه)
این روش سادهترین و البته ناکارآمدترین مدل است.
روش کار
-
تمام جایگشتهای ممکن از حروف تولید میشود.
-
هر جایگشت در دیتابیس کلمات چک میشود.
-
اگر کلمه معتبر بود، ذخیره میشود.
مشکل اصلی
تعداد جایگشتها برای n حرف برابر است با:
n! (فاکتوریل n)
اگر فقط ۱۰ حرف داشته باشید:
۳٬۶۲۸٬۸۰۰ حالت!
این روش عملاً در پروژههای واقعی قابل استفاده نیست.
مزیت
-
پیادهسازی بسیار آسان
-
برای حروف کم، سریع و دقیق
شبهکد
for perm in permutations(letters):
if exists_in_dictionary(perm):
results.add(perm)
جمعبندی روش
برای پروژههای واقعی پیشنهاد نمیشود مگر برای کلمات ۳–۵ حرفی.
۲. الگوریتم Backtracking + Pruning (استاندارد حرفهای)
این روش هسته اکثر ابزارهای کلمهساز است.
در این روش، به جای تولید همه جایگشتها، الگوریتم مرحلهبهمرحله جلو میرود و هر زمانی بفهمد ادامه مسیر نتیجهای ندارد، آن مسیر را قطع (Prune) میکند.
مزایا
-
سرعت فوقالعاده بالا
-
بهینهسازی عالی برای زبانهایی با حروف زیاد مثل فارسی
-
عدم تولید ترکیبهای بیفایده
چگونه کار میکند؟
مثال: حروف «ر»، «م»، «ا»
الگوریتم میگوید:
-
«ر» → آیا کلمهای در دیتابیس داریم که با «ر» شروع شود؟ بله → ادامه بده
-
«رم» → آیا کلمهای با «رم» شروع میشود؟ بله (مثل «رام»، «رمه») → ادامه
-
«رما» → آیا کلمهای با «رما» وجود دارد؟ خیر → این شاخه حذف میشود
این مسیر هزاران بار سریعتر از Permutation است.
شبهکد
def backtrack(current_word, remaining_letters):
if is_valid_word(current_word):
results.add(current_word)
for letter in remaining_letters:
if prefix_exists(current_word + letter):
backtrack(current_word + letter,
remaining_letters - letter)
منبع علمی معتبر
-
Knuth, D. (2015). The Art of Computer Programming. Addison-Wesley.
-
Manning et al., Speech and Language Processing, 2020.
۳. ساختار Trie (پایدارترین روش در واژهسازها)
Trie یک درخت ویژه است که هر مسیر آن یک کلمه را نمایش میدهد. این ساختار بسیار برای ابزارهای ساخت کلمه با حروف آنلاین و بازیهای واژهای مناسب است.
مزیتهای اصلی
-
جستجوی پیشوند بسیار سریع
-
امکان قطع شاخهها در Backtracking
-
حافظه کمتر نسبت به Permutation
چگونه کار میکند؟
هر حرف یک نود در درخت است.
مثال برای «مار»، «مارک»، «مارپیچ»:
م
└─ ا
└─ ر (مار)
├─ ک (مارک)
└─ پ
└─ ی
└─ چ (مارپیچ)
شبهکد ساخت Trie
class TrieNode:
def __init__(self):
self.children = {}
self.is_end = False
شبهکد جستجو
def search_prefix(prefix):
node = root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
منابع علمی معتبر
-
Fredkin, E. (1960). Trie memory. Communications of the ACM.
-
ScienceDirect, String Processing Techniques, 2019.
۴. روش Counter Matching (پیشنهادشده برای دیتابیسهای بسیار بزرگ)
در این روش، هر کلمه در دیتابیس تبدیل به یک فرکانس حروف میشود.
برای مثال، کلمه «سلام»:
س:1
ل:1
ا:1
م:1
اگر ورودی حروفی باشد که فرکانس کافی داشته باشند، کلمه معتبر است.
مزایا
-
مناسب دیتابیسهای چندمیلیونی
-
عدم نیاز به ایجاد رشتههای جدید
-
مناسب پیادهسازی در SQL
منابع علمی
-
Nature Computational Science (2021) – Symbolic Structures
-
ACM Digital Library, Letter Frequency Matching (2020)
مقایسه کامل الگوریتمهای ساخت کلمه با حروف
در این بخش، سه رویکرد اصلی که در نرمافزار ساخت کلمه با حروف فارسی و ابزارهای مشابه استفاده میشود را داخل یک جدول علمی مقایسه میکنم. این جدول به شما کمک میکند بفهمید برای پروژهای با دیتابیس چندصدهزار یا چندمیلیون کلمه، کدام روش واقعاً قابل استفاده است.
| ویژگی | Permutation | Backtracking + Trie | Counter Matching |
|---|---|---|---|
| سرعت | بسیار کند | بسیار سریع | سریع |
| پیچیدگی زمانی | O(n!) | O(n * log n) | O(n) |
| نیاز به حافظه | بسیار بالا | متوسط | کم |
| پشتیبانی از پیشوند (Prefix Search) | ندارد | عالی | متوسط |
| مناسب برای زبان فارسی | ضعیف | عالی | عالی |
| قابل استفاده برای بازی کلمهسازی | خیر | بله | بله |
| قابل استفاده در دیتابیسهای بزرگ | خیر | بله | بله |
| سادگی پیادهسازی | ساده | متوسط | ساده |
| امکان Pruning شاخهها | ندارد | دارد | ندارد |
| دقت خروجی | بالا | بسیار بالا | بالا |
نتیجه جدول
اگر هدف شما ساخت یک کلمهساز حرفهای، سریع و کاربردی باشد، بدون بحث باید سراغ Backtracking + Trie بروید.
برای دیتابیسهای بزرگ نیز ترکیب آن با Counter Matching ایدهآل است.
چالشهای خاص زبان فارسی در الگوریتم ساخت کلمه
زبان فارسی برخلاف زبانهای لاتین Complexity بسیار بیشتری در سطح کاراکتر و شکل نوشتاری دارد. در ادامه مهمترین چالشها را تحلیل میکنم.
۱. تعدد شکلهای یک حرف
مثال:
-
«ا»، «أ»، «آ»، «إ»
-
«ی»، «ى»، «ئ»
-
«ک»، «ك»
راهحل:
یکسانسازی قبل از پردازش
(همانطور که در تابع getLetterId استفاده شد)
۲. وجود نیمفاصله
کلمات زیر از نظر فارسی یکساناند اما برای الگوریتم متفاوت:
-
میروم
-
میروم
-
می روم
راهحل:
Normalizing → حذف نیمفاصله قبل از ورود به دیتابیس
۳. چسبندگی حروف در Unicode فارسی
مثلاً «ب + ا» همیشه به شکل «با» ساخته نمیشود اگر encoding تمیز نباشد.
راهحل:
استفاده از UTF-8 Clean + Unicode Normalization Form C (NFC)
منبع علمی:
-
Unicode Standard Annex #15 (2022)
۴.وجود کلمات عربی، دخیل و گویشهای محلی
دیتابیس باید ۳ دسته را مشخص کند:
-
فارسی معیار
-
عربیِ پرکاربرد
-
کلمات محلی (در صورت نیاز)
راهحل:
فیلد main در جدول words
که کلمه اصلی و استاندارد را مشخص میکند.
۵. سرعت جستجوی SQL در دیتابیسهای بزرگ
اگر دیتابیس شامل ۱ میلیون کلمه باشد، بررسی تکتک آنها با LIKE …% بسیار سنگین است.
راهحل:
استفاده از:
-
index روی word
-
index روی char_id
-
join بهینه بین words و characters
-
کش در Redis برای ذخیره prefixها
منبع علمی:
-
SIGMOD Conference on Data Engineering (2021)
طراحی یک الگوریتم بهینه برای زبان فارسی (کاملترین راهکار)
در این بخش، یک طراحی واقعاً کاربردی را ارائه میدهم که میتواند یک کلمهساز در سطح تجاری تولید کند.
مرحله ۱: Preprocessing — پاکسازی و استانداردسازی
قانونها:
-
تبدیل تمام حروف معادل به یک استاندارد
-
حذف نیمفاصله
-
تبدیل یای عربی به ی
-
تبدیل کاف عربی به ک
-
trim و حذف اسپیس اضافی
مرحله ۲: تبدیل کلمه به char_id
برای هر حرف از جدول characters استفاده میکنیم.
مثال «کتاب» →
[25، 19، 1، 2]
مرحله ۳: ذخیره در Trie
برای سرعت در یافتن پیشوندها:
ک
└─ ت
└─ ا
└─ ب (کلمه کامل)
مرحله ۴: اجرای Backtracking با محدودیت حرف
ورودی: حروف «ک، ت، ا، ب»
خروجی:
-
کتاب
-
تک
-
تب
-
بت
-
کتا
(در صورت وجود در دیتابیس)
مرحله ۵: کنترل سرعت با Counter Matching
این مرحله برای حذف کلماتِ غیرممکن حتی قبل از ورود به Trie است.
مرحله ۶: کش کردن نتایج
برای جلوگیری از تکرار محاسبه:
-
ورودی «ک، ت، ا، ب» → کش شود.
-
حتی ترکیبهای جزء نیز کش میشوند (Prefix Cache).