ویژگی تصویر

تابع similar_text() در PHP

  /  PHP   /  تابع similar_text() در PHP
بنر تبلیغاتی الف
آموزش PHP

تابع similar_text() در PHP برای سنجش شباهت بین دو رشته طراحی شده است. این تابع تعداد کاراکترهای «مشابه» بین دو رشته را بازمی‌گرداند و می‌تواند درصد شباهت را نیز در یک پارامتر مرجع قرار دهد. کاربردهای رایج شامل تشخیص شباهت بین نام‌ها، جستجوی فازی، و پاکسازی داده‌ها قبل از مقایسه هستند.

امضای تابع و رفتار کلی

امضای تابع:

تابعپارامترهاخروجی
similar_text(string $first, string $second, float &$percent = null): int$first، $second: رشته‌ها — $percent: مقدار درصد شباهت (اختیاری)تعداد کاراکترهای مشابه (عدد صحیح)

مثال پایه

<?php
$a = "Hello world";
$b = "Hello there";
$match = similar_text($a, $b, $percent);
echo "Matched chars: $matchn";
echo "Similarity: $percent %n";
?>

در این مثال تابع تعداد کاراکترهای مشابه را محاسبه و درصد شباهت را در متغیر $percent قرار می‌دهد. این روش برای رشته‌های لاتین و تک‌بایتی عموماً قابل اعتماد است.

محدودیت‌ها و نکات مهم

  • محاسبات بایت‌محور: similar_text در سطح بایت کار می‌کند، نه کاراکتر یونیکد. بنابراین برای رشته‌های UTF-8 (مانند فارسی، عربی یا سایر حروف چندبایتی) ممکن است نتایج غیرمنتظره‌ای بدهد.
  • پیچیدگی زمانی: الگوریتم مشابهت در این تابع زمانی نسبتاً بالا دارد (می‌تواند تقریباً O(n*m) باشد)، پس برای رشته‌های بسیار طولانی یا مقایسه‌های دسته‌ای سریع مناسب نیست.
  • نوع تشابه: این تابع مبتنی بر پیدا کردن بخش‌های مشترک است و با اندازه‌گیری طول بزرگ‌ترین زیررشته‌های مشترک (و بازگشت مجموع)، رفتار متفاوتی نسبت به فاصله لوونشتاین (Levenshtein) یا LCS خواهد داشت.

نمونه مشکل با UTF-8 (فارسی)

<?php
$s1 = "سلام دنیا";
$s2 = "سلام دنیا!";
$match = similar_text($s1, $s2, $percent);
echo "Matched: $match, Percent: $percentn";
?>

در بسیاری از موارد این مقایسه برای رشته‌های فارسی نتیجهٔ منطقی خواهد داد، ولی چون هر کاراکتر فارسی در UTF-8 چند بایت است، تابع مشابهت ممکن است با تعداد بایت کار کند و درصد دقیق کاراکتر-محور را نشان ندهد. برای اطمینان، باید قبل از مقایسه پردازش روی رشته‌ها انجام شود یا از روش‌های مخصوص یونیکد استفاده گردد.

راهکارهای کار کردن صحیح با رشته‌های چندبایتی

چند راهکار برای کاهش خطا و بهبود دقت در زبان‌های غیرلاتین:

  • از توابع mb_* برای نرمال‌سازی، کوچک‌سازی (mb_strtolower) و گرفتن طول (mb_strlen) استفاده کنید.
  • نسبت به حذف نویسه‌های کنترلی، فاصله‌های اضافه و تگ‌های HTML اقدام کنید.
  • اگر نیاز به ناوبری کاراکتر-محور دارید، از mb_str_split یا preg_split('//u') برای تبدیل رشته به آرایهٔ کاراکترها استفاده کنید و یک الگوریتم LCS یا Levenshtein بر روی آرایه‌ها پیاده کنید.

تابع جایگزین برای پشتیبانی کامل از یونیکد (نمونه)

<?php
function unicode_similarity_percent(string $a, string $b): float {
    // split into unicode characters (PHP 7.4+ has mb_str_split)
    $charsA = preg_split('//u', $a, -1, PREG_SPLIT_NO_EMPTY);
    $charsB = preg_split('//u', $b, -1, PREG_SPLIT_NO_EMPTY);

    $lenA = count($charsA);
    $lenB = count($charsB);
    if ($lenA === 0 && $lenB === 0) return 100.0;
    if ($lenA === 0 || $lenB === 0) return 0.0;

    // LCS dynamic programming
    $dp = array_fill(0, $lenA + 1, array_fill(0, $lenB + 1, 0));
    for ($i = 1; $i <= $lenA; $i++) {
        for ($j = 1; $j <= $lenB; $j++) {
            if ($charsA[$i - 1] === $charsB[$j - 1]) {
                $dp[$i][$j] = $dp[$i - 1][$j - 1] + 1;
            } else {
                $dp[$i][$j] = max($dp[$i - 1][$j], $dp[$i][$j - 1]);
            }
        }
    }
    $lcs = $dp[$lenA][$lenB];
    $percent = ($lcs / max($lenA, $lenB)) * 100.0;
    return $percent;
}
?>

کد بالا از الگوریتم Longest Common Subsequence (LCS) برای محاسبهٔ میزان شباهت بر پایهٔ کاراکتر یونیکد استفاده می‌کند. ابتدا رشته‌ها را به آرایهٔ کاراکتر تبدیل می‌کند (با preg_split('//u')) سپس ماتریس DP را می‌سازد و طول LCS را محاسبه می‌کند. در نهایت درصد را بر پایهٔ طول بزرگ‌تر دو رشته برمی‌گرداند. این روش برای متن‌های فارسی دقیق‌تر است اما هزینهٔ محاسباتی قابل توجهی دارد.

توصیه‌های عملی و بهینه‌سازی‌ها

  • برای مجموعه‌های بزرگ داده، ابتدا مقایسهٔ ساده و سریع (مثل بررسی طول یا هش) انجام داده، سپس موارد مشکوک را با توابع دقیق‌تر بررسی کنید.
  • اگر معیار شما ویرایش است (تغییرات، حذف یا اضافه)، از levenshtein() استفاده کنید؛ اگر به تشابه آوایی نیاز دارید، از metaphone() یا soundex() کمک بگیرید.
  • قبل از مقایسه، رشته‌ها را نرمال‌سازی (Normalizing) کنید: حذف تکرار فاصله، تبدیل به حروف کوچک، حذف نقطه‌گذاری و نرمال‌سازی یونیکد با intl (اگر در دسترس است).
  • برای مقایسهٔ مقیاس‌پذیر، از الگوریتم‌هایی مانند MinHash یا LSH برای شباهت اسناد استفاده کنید و سپس از similar_text یا الگوریتم‌های دقیق‌تر در سطح جزیی استفاده کنید.

نتیجه‌گیری

تابع similar_text() ابزار ساده و مفیدی برای مقایسهٔ رشته‌هاست ولی برای متن‌های یونیکد و مجموعه‌های بزرگ باید با احتیاط و پس از نرمال‌سازی استفاده شود. برای پروژه‌های جدی و زبان‌های چندبایتی، ترکیب توابع mb_*، نرمال‌سازی و الگوریتم‌های جایگزین مثل Levenshtein یا LCS عملکرد و دقت بهتری فراهم می‌کند.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: