2) {
return get_common_surnames($min/2);
} else {
uksort($topsurns, 'utf8_strcasecmp');
foreach ($topsurns as $key=>$value) {
$topsurns[$key]=array('name'=>$key, 'match'=>$value);
}
return $topsurns;
}
}
/**
* strip name prefixes
*
* this function strips the prefixes of lastnames
* get rid of jr. Jr. Sr. sr. II, III and van, van der, de lowercase surname prefixes
* a . and space must be behind a-z to ensure shortened prefixes and multiple prefixes are removed
* @param string $lastname The name to strip
* @return string The updated name
*/
function strip_prefix($lastname){
$name = preg_replace(array('/ [jJsS][rR]\.?,/', '/ I+,/', '/^([a-z]{1,4}[\. \_\-\(\[])+/'), array(',',',',''), $lastname);
$name = trim($name);
if ($name=='') return $lastname;
return $name;
}
/**
* This function replaces @N.N. and @P.N. with the language specific translations
* @param mixed $names $names could be an array of name parts or it could be a string of the name
* @return string
*/
function check_NN($names) {
global $UNDERLINE_NAME_QUOTES;
global $UNKNOWN_NN, $UNKNOWN_PN;
$fullname = '';
if (!is_array($names)){
$script = utf8_script($names);
$NN = $UNKNOWN_NN[$script];
$names = preg_replace(array('~ /~','~/,~','~/~'), array(' ', ',', ' '), $names);
$names = preg_replace(array('/@N.N.?/','/@P.N.?/'), array($UNKNOWN_NN[$script],$UNKNOWN_PN[$script]), trim($names));
//-- underline names with a * at the end
//-- see this forum thread http://sourceforge.net/forum/forum.php?thread_id=1223099&forum_id=185165
if ($UNDERLINE_NAME_QUOTES) {
$names = preg_replace('/"(.+)"/', '$1', $names);
}
$names = preg_replace('/([^ ]+)\*/', '$1', $names);
return $names;
}
if (count($names) == 2 && stristr($names[0], '@N.N') && stristr($names[1], '@N.N')){
$fullname = i18n::translate('(unknown)'). ' + '. i18n::translate('(unknown)');
} else {
for($i=0; $i3) {
$fullname .= ' + ';
} else {
$fullname .= ', ';
}
$fullname .= trim($names[$i]);
}
}
$fullname = trim($fullname);
if (substr($fullname,-1)==',') $fullname = substr($fullname,0,strlen($fullname)-1);
if (substr($fullname,0,2)==', ') $fullname = substr($fullname,2);
$fullname = trim($fullname);
if (empty($fullname)) return i18n::translate('(unknown)');
return $fullname;
}
// Returns 1 if $string is valid 7 bit ASCII and 0 otherwise.
function is_7bitascii($string) {
return preg_match('/^(?:[\x09\x0A\x0D\x20-\x7E])*$/', $string);
}
// Returns 1 if $string is valid UTF-8 and 0 otherwise.
// See http://w3.org/International/questions/qa-forms-utf-8.html
function is_utf8($string) {
return preg_match('/^(?:[\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})*$/', $string);
}
/**
* determine the Daitch-Mokotoff Soundex code for a word
* @param string $name The name
* @return array The array of codes
* @author G. Kroll (canajun2eh), after a previous implementation by Boudewijn Sjouke
*/
function DMSoundex($name) {
global $transformNameTable, $dmsounds, $maxchar;
// If the code tables are not loaded, reload! Keep them global!
if (!defined('WT_DMSOUNDS_UTF8_PHP')) {
require WT_ROOT.'includes/dmsounds_UTF8.php';
}
// Apply special transformation rules to the input string
$name = utf8_strtoupper($name);
foreach($transformNameTable as $transformRule) {
$name = str_replace($transformRule[0], $transformRule[1], $name);
}
// Initialize
$name_script = utf8_script($name);
if ($name_script == 'hebrew' || $name_script == 'arabic') $noVowels = true;
else $noVowels = false;
$lastPos = strlen($name) - 1;
$currPos = 0;
$state = 1; // 1: start of input string, 2: before vowel, 3: other
$result = array(); // accumulate complete 6-digit D-M codes here
$partialResult = array(); // accumulate incomplete D-M codes here
$partialResult[] = array('!'); // initialize 1st partial result ('!' stops "duplicate sound" check)
// Loop through the input string.
// Stop when the string is exhausted or when no more partial results remain
while (count($partialResult) !=0 && $currPos <= $lastPos) {
// Find the DM coding table entry for the chunk at the current position
$thisEntry = substr($name, $currPos, $maxchar); // Get maximum length chunk
while ($thisEntry != '') {
if (isset($dmsounds[$thisEntry])) break;
$thisEntry = substr($thisEntry, 0, -1); // Not in table: try a shorter chunk
}
if ($thisEntry == '') {
$currPos ++; // Not in table: advance pointer to next byte
continue; // and try again
}
$soundTableEntry = $dmsounds[$thisEntry];
$workingResult = $partialResult;
$partialResult = array();
$currPos += strlen($thisEntry);
if ($state != 1) { // Not at beginning of input string
if ($currPos <= $lastPos) {
// Determine whether the next chunk is a vowel
$nextEntry = substr($name, $currPos, $maxchar); // Get maximum length chunk
while ($nextEntry != '') {
if (isset($dmsounds[$nextEntry])) break;
$nextEntry = substr($nextEntry, 0, -1); // Not in table: try a shorter chunk
}
} else $nextEntry = '';
if ($nextEntry != '' && $dmsounds[$nextEntry][0] != '0') $state = 2; // Next chunk is a vowel
else $state = 3;
}
while ($state < count($soundTableEntry)) {
if ($soundTableEntry[$state] == '') { // empty means 'ignore this sound in this state'
foreach($workingResult as $workingEntry) {
$tempEntry = $workingEntry;
$tempEntry[count($tempEntry)-1] .= '!'; // Prevent false 'doubles'
$partialResult[] = $tempEntry;
}
} else {
foreach($workingResult as $workingEntry) {
if ($soundTableEntry[$state] !== $workingEntry[count($workingEntry)-1]) {
// Incoming sound isn't a duplicate of the previous sound
$workingEntry[] = $soundTableEntry[$state];
} else {
// Incoming sound is a duplicate of the previous sound
// For Hebrew and Arabic, we need to create a pair of D-M sound codes,
// one of the pair with only a single occurrence of the duplicate sound,
// the other with both occurrences
if ($noVowels) {
// $partialResult[] = $workingEntry;
$workingEntry[] = $soundTableEntry[$state];
}
}
if (count($workingEntry) < 7) $partialResult[] = $workingEntry;
else {
// This is the 6th code in the sequence
// We're looking for 7 entries because the first is '!' and doesn't count
$tempResult = str_replace('!', '', implode('', $workingEntry)) . '000000';
$result[] = substr($tempResult, 0, 6);
}
}
}
$state = $state + 3; // Advance to next triplet while keeping the same basic state
}
}
// Zero-fill and copy all remaining partial results
foreach ($partialResult as $workingEntry) {
$tempResult = str_replace('!', '', implode('', $workingEntry)) . '000000';
$result[] = substr($tempResult, 0, 6);
}
$result = array_flip(array_flip($result)); // Kill the double results in the array
// We're done. All that's left is to sort the result
sort($result);
return $result;
}
// Wrapper function for soundex function. Return a colon separated list of values.
function soundex_std($text) {
Character_Substitute($text);
$words=explode(' ', $text);
$soundex_array=array();
foreach ($words as $word) {
if ($word) {
$soundex_array[]=soundex($word);
}
}
if (count($words)>1) {
$soundex_array[]=soundex(strtr($text, ' ', ''));
}
// A varchar(255) column can only hold 51 4-character codes (plus 50 delimiters)
$soundex_array=array_slice($soundex_array, 0, 51);
return implode(':', array_unique($soundex_array));
}
// Wrapper function for soundex function. Return a colon separated list of values.
function soundex_dm($text) {
Character_Substitute($text);
$words=explode(' ', $text);
$soundex_array=array();
$combined = '';
foreach ($words as $word) {
if ($word) {
$soundex_array=array_merge($soundex_array, DMSoundex($word));
}
}
if (count($words)>1) {
$soundex_array=array_merge($soundex_array, DMSoundex(strtr($text, ' ', '')));
}
// A varchar(255) column can only hold 36 6-entries (plus 35 delimiters)
$soundex_array=array_slice($soundex_array, 0, 36);
return implode(':', array_unique($soundex_array));
}
?>