Im gestrigen Artikel aus der Serie “Exotische PHP-Funktionen” berichtete ich über zwei Funktionen, mit deren Hilfe sich die Ähnlichkeit zweier Zeichenketten bestimmen lässt. In den Kommentaren wurde bereits erwähnt, dass metaphone() und soundex() nicht optimal für die deutsche Sprache geeignet sind. Deshalb hatte ich sowieso schon geplant, heute die Kölner Phonetik vorzustellen. Dabei handelt es sich um einen Algorithmus, der Wörtern eine Zeichenfolge nach ihrem Klang zuordnet.
Implementierung
Da dieser Algorithmus von Haus aus nicht in PHP implementiert ist, muss dies von Hand geschehen. Hierbei kann man auf die Lösung eines Kommentators im PHP Manual zurückgreifen, der die Kölner Phonetik bereits in eine Funktion verpackt hat.
Der Quelltext
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
<?php /** * A function for retrieving the Kölner Phonetik value of a string * * As described at http://de.wikipedia.org/wiki/Kölner_Phonetik * Based on Hans Joachim Postel: Die Kölner Phonetik. * Ein Verfahren zur Identifizierung von Personennamen auf der * Grundlage der Gestaltanalyse. * in: IBM-Nachrichten, 19. Jahrgang, 1969, S. 925-931 * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @package phonetics * @version 1.0 * @link http://www.einfachmarke.de * @license GPL 3.0 <http://www.gnu.org/licenses/> * @copyright 2008 by einfachmarke.de * @author Nicolas Zimmer <nicolas dot zimmer at einfachmarke.de> */ function cologne_phon($word) { /** * @param string $word string to be analyzed * @return string $value represents the Kölner Phonetik value * @access public */ // prepare for processing $word = strtolower($word); $substitution = array( "ä"=>"a", "ö"=>"o", "ü"=>"u", "ß"=>"ss", "ph"=>"f" ); foreach ($substitution as $letter => $substitution) { $word = str_replace($letter,$substitution,$word); } $len = strlen($word); // Rule for exeptions $exceptionsLeading = array( 4 => array("ca","ch","ck","cl","co","cq","cu","cx"), 8 => array("dc","ds","dz","tc","ts","tz") ); $exceptionsFollowing = array("sc","zc","cx","kx","qx"); //Table for coding $codingTable = array( 0 => array("a", "e", "i", "j", "o", "u", "y"), 1 => array("b", "p"), 2 => array("d", "t"), 3 => array("f", "v", "w"), 4 => array("c", "g", "k", "q"), 48 => array("x"), 5 => array("l"), 6 => array("m", "n"), 7 => array("r"), 8 => array("c", "s", "z"), ); for ($i=0; $i<$len; $i++) { $value[$i] = ""; //Exceptions if ($i == 0 && $word[$i].$word[$i+1] == "cr") { $value[$i] = 4; } foreach ($exceptionsLeading as $code => $letters) { if (in_array($word[$i].$word[$i+1], $letters)) { $value[$i] = $code; } } if ($i != 0 && (in_array($word[$i-1].$word[$i], $exceptionsFollowing))) { $value[$i] = 8; } // normal encoding if ($value[$i] == "") { foreach ($codingTable as $code => $letters) { if (in_array($word[$i], $letters)) { $value[$i] = $code; } } } } // delete double values $len = count($value); for ($i=1; $i<$len; $i++) { if ($value[$i] == $value[$i-1]) { $value[$i] = ""; } } // delete vocals for ($i=1; $i>$len; $i++) { // omitting first characer code and h if ($value[$i] == 0) { $value[$i] = ""; } } $value = array_filter($value); $value = implode("", $value); return $value; } |
Beispiel
Hier noch ein paar Beispiele:
1 2 3 4 |
echo cologne_phon("Hans"); // 68 echo cologne_phon("Franz"); // 3768 echo cologne_phon("Schokolade"); // 8452 echo cologne_phon("Raddampfer"); // 726137 |
24. März 2010 um 20:05 Uhr
Klasse, vielen Dank für diesen interessanten Artikel. Hatte mich vorher noch nicht mit der Ähnlichkeit von Wörtern beschäftigen müssen. Um so interessanter zu sehen, dass es Algorithmen dafür gibt die so in PHP implementiert werden können. Das Beispiel ist auch aussagekräftig, danke!
5. April 2011 um 17:27 Uhr
Hi,
vielen Dank für den Code, kann ich gut gebrauchen! Ich habe bei mir PHP streng eingestellt und es kommt bei mir in der Originalversion ein Fehler, weil über das Wortende hinaus gelesen wird. Ich habe deshalb in den Zeilen 72-83 ein paar kleine Änderungen vorgenommen:
//Exceptions
if ($i == 0 && $i<$len-1 && $word[$i].$word[$i+1] == "cr") {
$value[$i] = 4;
}
if($i<$len-1) {
foreach ($exceptionsLeading as $code => $letters) {
if (in_array($word[$i].$word[$i+1], $letters)) {
$value[$i] = $code;
}
}
}
Beste Grüße,
Andre
PS: Repost mit htmlencoded entities, da beim vorigen Eintrag ein Teil vom Code geschluckt wurde
4. September 2011 um 15:30 Uhr
Das Beispiel für Hans scheint mir nicht korrekt zu sein. 0 am Anfang bleibt laut wikipedia stehen, sollte also 068 sein. Ich schreibe gerade ein paar unit tests für diesen Algorithmus und werde mir demnächst wohl mal die Primärquelle anschauen.
25. Oktober 2011 um 01:51 Uhr
Zunächst erstmal Danke den Artikel!!
Hier zwei kleine Fehler, die in PHP 5.3.2 auftreten:
Zeile 107 sollte lauten (siehe kleiner Zeichen ist umgedreht): for ($i=1; $i<$len; $i++) {
Zeile 114 habe ich komplett auskommentiert, da dies auch 0'en entfernt, das wollen wir doch nicht
Danke nochmals,
Liebe Grüße
markus
25. Oktober 2011 um 21:33 Uhr
Habe gerade keine Zeit das zu überprüfen, aber vielen Dank für den Hinweis!