Here comes a memo for using Levenshstein algorythm

xquery version "3.1";

declare function local:levenshtein-distance($string1 as xs:string?, $string2 as xs:string?)
as xs:integer
{
  if ( fn:min( (fn:string-length($string1), fn:string-length($string2)) ) = 0 )
  then 
    fn:max((fn:string-length($string1), fn:string-length($string2)))
  else
    local:_levenshtein-distance(
                        fn:string-to-codepoints($string1),
                        fn:string-to-codepoints($string2),
                        fn:string-length($string1),
                        fn:string-length($string2),
                       (1, 0, 1),
                       2
  ) 
};

declare function local:_levenshtein-distance(
                                              $chars1 as xs:integer*, 
                                              $chars2 as xs:integer*, 
                                              $length1 as xs:integer, 
                                              $length2 as xs:integer,
                                              $lastDiag as xs:integer*, 
                                              $total as xs:integer)
as xs:integer 
{ 
  let $shift := if ($total > $length2) then ($total - ($length2 + 1)) else 0 
  let $diag := 
    for $i in (fn:max((0, $total - $length2)) to fn:min(($total, $length1))) 
  let $j := $total - $i let $d := ($i - $shift) * 2 
  return ( 
    if ($j lt $length2) then 
      $lastDiag[$d - 1]
    else () ,
    if ($i = 0) then $j 
    else if ($j = 0) then $i 
    else fn:min(($lastDiag[$d - 1] + 1, 
                      $lastDiag[$d + 1] + 1,
                      $lastDiag[$d] + (if ($chars1[$i] = $chars2[$j]) then 0 else 1)
                    ))
    )
  return
    if ($total = $length1 + $length2) then fn:exactly-one($diag)
    else local:_levenshtein-distance($chars1, $chars2, $length1, $length2, $diag, $total + 1) 
};

let $input := (
"  2 Etablissement public pour l'aménagement de la région de La Défense"
,"  3 Etablissement public pour l'aménagement de la région dite “de la Défense”"
," 29 Etablissement public pour l'aménagement de la région dite « de la Défense »"
,"  1 Etablissement public pour l'aménagement de la région dite “de La Défense”"
,"  2 groupement de coopération sanitaire « Centre régional de compétence en surdité infantile »"
,"  1 groupement de coopération sanitaire « Centre régional de compétence en surdité infantile » (CRCSI)"
)
let $input := for $e in $input return substring($e,5)
return
  <div>
    <ol>{for $l in $input return <li>{$l}</li>}</ol>
    <table >
<table >
    <tr><td/>{
        for $s at $p in $input return <td>{$p}</td>
    }</tr>
    {for $s1 at $p1 in $input
        return <tr>
            <td>{$p1}</td>
        {
            for $s2 at $p2 in $input 
            return if ($p1>$p2) then <td></td> else  <td>{local:levenshtein-distance($s1, $s2)}</td>
        }
        </tr>
  </div>
}</table>

with the result :

  1. Etablissement public pour l'aménagement de la région de La Défense
  2. Etablissement public pour l'aménagement de la région dite “de la Défense”
  3. Etablissement public pour l'aménagement de la région dite « de la Défense »
  4. Etablissement public pour l'aménagement de la région dite “de La Défense”
  5. groupement de coopération sanitaire « Centre régional de compétence en surdité infantile »
  6. groupement de coopération sanitaire « Centre régional de compétence en surdité infantile » (CRCSI)
1 2 3 4 5 6
1 0 8 10 7 67 75
2 0 4 1 66 74
3 0 5 64 72
4 0 66 74
5 0 8
6 0

I love the eXistdb tools for such kind of quick data analysis.

I made this post following a forum’s question on etalab