similar_text

Counts the matching characters between two strings and optionally reports a similarity percentage.

Signature
similar_text(string $string1, string $string2, float &$percent = null): int
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$string1stringThe first string.
$string2stringThe second string.
$percentoptionalfloat= nullPassed by reference. Receives the similarity as a percentage, computed as matches * 200 / (strlen(string1) + strlen(string2)).

Return value

intThe number of matching characters found in both strings.

similar_text finds the longest common substring of the two inputs, then recurses into the parts on either side of it, adding up the matches. The return value is that total character count; pass a third variable by reference to also get a percentage.

Percentage, not distance

This is the main reason to choose it over levenshtein: you get a directly usable 0–100 score without normalising anything yourself. Handy for ranking search results, spotting near-duplicate titles, or deciding whether two address strings are probably the same place.

Three things that catch people out

First, it is not symmetric. The greedy longest-common-substring search can find a different set of matches depending on which string comes first, so similar_text($a, $b) and similar_text($b, $a) can differ — sometimes dramatically. Pick a consistent argument order, or take the maximum of both directions.

Second, it is case-sensitive and byte-based. Lowercase both sides first, and be aware that multi-byte characters are compared as bytes.

Third, it is O(N³) in the length of the longer string. On short titles and names it is fine; on paragraphs or documents it will dominate your request time, and levenshtein at O(m·n) is the practical choice there.

Two empty strings give a count of 0 rather than a 100% match.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Rank candidate product titles by how closely they match a user's search phrase.
  • Detect near-duplicate article headlines before publishing.
  • Score how closely two free-text address lines agree during a data merge.

Frequently asked questions

Why does similar_text give different results when I swap the arguments?

Its greedy longest-common-substring algorithm can pick different match sets depending on which string it scans first, so the counts are not symmetric. Fix an argument order, or run it both ways and use the higher score.

What is the difference between similar_text and levenshtein?

similar_text counts matching characters and can hand back a percentage; levenshtein counts the edits needed to transform one string into the other. similar_text is more convenient for ranking, but is O(N³) and far slower on long strings.

How do I make similar_text case-insensitive?

Lowercase both inputs before passing them, for example similar_text(strtolower($a), strtolower($b), $pct). There is no flag for it, and the comparison is byte-based.

More examples

Order changes the answer

The first call reports 1 matching character and 15.38%; swapping the arguments reports 3 and 46.15%. Same two strings, three times the score. If a threshold decides whether two records are duplicates, this asymmetry will make the decision depend on iteration order — compute both directions and take the larger value.

Example · php
<?php
$a = 'testing';
$b = 'silent';

similar_text($a, $b, $p1);
printf("%s vs %s: %d chars, %.2f%%\n", $a, $b, similar_text($a, $b), $p1);

similar_text($b, $a, $p2);
printf("%s vs %s: %d chars, %.2f%%\n", $b, $a, similar_text($b, $a), $p2);

Ranking candidates by similarity

Scores come out at 88.24%, 26.32% and 89.47%. Lowercasing both sides first stops capitalisation differences from costing points. Note that 'The Quick Brown Dog' edges out 'Quick Brown Fox' because the shared prefix is longer, even though it swaps the more meaningful word — a reminder that this is a character-level, not semantic, measure.

Example · php
<?php
$title = 'The Quick Brown Fox';
$candidates = ['Quick Brown Fox', 'A Slow Green Turtle', 'The Quick Brown Dog'];

foreach ($candidates as $candidate) {
    similar_text(strtolower($title), strtolower($candidate), $pct);
    printf("%-20s %6.2f%%\n", $candidate, $pct);
}

Discussion

  • Be the first to comment on this lesson.