#include "postgres.h"#include "utils/builtins.h"#include <stdio.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <assert.h>
Go to the source code of this file.
Data Structures | |
| struct | metastring |
Defines | |
| #define | NDEBUG |
| #define | META_MALLOC(v, n, t) (v = (t*)palloc(((n)*sizeof(t)))) |
| #define | META_REALLOC(v, n, t) (v = (t*)repalloc((v),((n)*sizeof(t)))) |
| #define | META_FREE(x) |
Functions | |
| Datum | dmetaphone (PG_FUNCTION_ARGS) |
| Datum | dmetaphone_alt (PG_FUNCTION_ARGS) |
| static void | DoubleMetaphone (char *, char **) |
| PG_FUNCTION_INFO_V1 (dmetaphone) | |
| PG_FUNCTION_INFO_V1 (dmetaphone_alt) | |
| static metastring * | NewMetaString (char *init_str) |
| static void | DestroyMetaString (metastring *s) |
| static void | IncreaseBuffer (metastring *s, int chars_needed) |
| static void | MakeUpper (metastring *s) |
| static int | IsVowel (metastring *s, int pos) |
| static int | SlavoGermanic (metastring *s) |
| static char | GetAt (metastring *s, int pos) |
| static void | SetAt (metastring *s, int pos, char c) |
| static int | StringAt (metastring *s, int start, int length,...) |
| static void | MetaphAdd (metastring *s, char *new_str) |
| #define META_FREE | ( | x | ) |
Definition at line 201 of file dmetaphone.c.
Referenced by DestroyMetaString().
| #define META_MALLOC | ( | v, | ||
| n, | ||||
| t | ||||
| ) | (v = (t*)palloc(((n)*sizeof(t)))) |
Definition at line 188 of file dmetaphone.c.
Referenced by NewMetaString().
| #define META_REALLOC | ( | v, | ||
| n, | ||||
| t | ||||
| ) | (v = (t*)repalloc((v),((n)*sizeof(t)))) |
Definition at line 191 of file dmetaphone.c.
Referenced by IncreaseBuffer().
| #define NDEBUG |
Definition at line 107 of file dmetaphone.c.
| static void DestroyMetaString | ( | metastring * | s | ) | [static] |
Definition at line 261 of file dmetaphone.c.
References metastring::free_string_on_destroy, META_FREE, NULL, and metastring::str.
Referenced by DoubleMetaphone().
| Datum dmetaphone | ( | PG_FUNCTION_ARGS | ) |
Definition at line 132 of file dmetaphone.c.
References arg, cstring_to_text(), DoubleMetaphone(), PG_ARGISNULL, PG_GETARG_TEXT_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and text_to_cstring().
{
text *arg;
char *aptr,
*codes[2],
*code;
#ifdef DMETAPHONE_NOSTRICT
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
#endif
arg = PG_GETARG_TEXT_P(0);
aptr = text_to_cstring(arg);
DoubleMetaphone(aptr, codes);
code = codes[0];
if (!code)
code = "";
PG_RETURN_TEXT_P(cstring_to_text(code));
}
| Datum dmetaphone_alt | ( | PG_FUNCTION_ARGS | ) |
Definition at line 161 of file dmetaphone.c.
References arg, cstring_to_text(), DoubleMetaphone(), PG_ARGISNULL, PG_GETARG_TEXT_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, and text_to_cstring().
{
text *arg;
char *aptr,
*codes[2],
*code;
#ifdef DMETAPHONE_NOSTRICT
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
#endif
arg = PG_GETARG_TEXT_P(0);
aptr = text_to_cstring(arg);
DoubleMetaphone(aptr, codes);
code = codes[1];
if (!code)
code = "";
PG_RETURN_TEXT_P(cstring_to_text(code));
}
| static void DoubleMetaphone | ( | char * | str, | |
| char ** | codes | |||
| ) | [static] |
Definition at line 393 of file dmetaphone.c.
References DestroyMetaString(), metastring::free_string_on_destroy, GetAt(), IsVowel(), metastring::length, MakeUpper(), MetaphAdd(), NewMetaString(), SetAt(), SlavoGermanic(), metastring::str, and StringAt().
Referenced by dmetaphone(), and dmetaphone_alt().
{
int length;
metastring *original;
metastring *primary;
metastring *secondary;
int current;
int last;
current = 0;
/* we need the real length and last prior to padding */
length = strlen(str);
last = length - 1;
original = NewMetaString(str);
/* Pad original so we can index beyond end */
MetaphAdd(original, " ");
primary = NewMetaString("");
secondary = NewMetaString("");
primary->free_string_on_destroy = 0;
secondary->free_string_on_destroy = 0;
MakeUpper(original);
/* skip these when at start of word */
if (StringAt(original, 0, 2, "GN", "KN", "PN", "WR", "PS", ""))
current += 1;
/* Initial 'X' is pronounced 'Z' e.g. 'Xavier' */
if (GetAt(original, 0) == 'X')
{
MetaphAdd(primary, "S"); /* 'Z' maps to 'S' */
MetaphAdd(secondary, "S");
current += 1;
}
/* main loop */
while ((primary->length < 4) || (secondary->length < 4))
{
if (current >= length)
break;
switch (GetAt(original, current))
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
case 'Y':
if (current == 0)
{
/* all init vowels now map to 'A' */
MetaphAdd(primary, "A");
MetaphAdd(secondary, "A");
}
current += 1;
break;
case 'B':
/* "-mb", e.g", "dumb", already skipped over... */
MetaphAdd(primary, "P");
MetaphAdd(secondary, "P");
if (GetAt(original, current + 1) == 'B')
current += 2;
else
current += 1;
break;
case '\xc7': /* C with cedilla */
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
current += 1;
break;
case 'C':
/* various germanic */
if ((current > 1)
&& !IsVowel(original, current - 2)
&& StringAt(original, (current - 1), 3, "ACH", "")
&& ((GetAt(original, current + 2) != 'I')
&& ((GetAt(original, current + 2) != 'E')
|| StringAt(original, (current - 2), 6, "BACHER",
"MACHER", ""))))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
current += 2;
break;
}
/* special case 'caesar' */
if ((current == 0)
&& StringAt(original, current, 6, "CAESAR", ""))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
current += 2;
break;
}
/* italian 'chianti' */
if (StringAt(original, current, 4, "CHIA", ""))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
current += 2;
break;
}
if (StringAt(original, current, 2, "CH", ""))
{
/* find 'michael' */
if ((current > 0)
&& StringAt(original, current, 4, "CHAE", ""))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "X");
current += 2;
break;
}
/* greek roots e.g. 'chemistry', 'chorus' */
if ((current == 0)
&& (StringAt(original, (current + 1), 5,
"HARAC", "HARIS", "")
|| StringAt(original, (current + 1), 3, "HOR",
"HYM", "HIA", "HEM", ""))
&& !StringAt(original, 0, 5, "CHORE", ""))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
current += 2;
break;
}
/* germanic, greek, or otherwise 'ch' for 'kh' sound */
if (
(StringAt(original, 0, 4, "VAN ", "VON ", "")
|| StringAt(original, 0, 3, "SCH", ""))
/* 'architect but not 'arch', 'orchestra', 'orchid' */
|| StringAt(original, (current - 2), 6, "ORCHES",
"ARCHIT", "ORCHID", "")
|| StringAt(original, (current + 2), 1, "T", "S",
"")
|| ((StringAt(original, (current - 1), 1,
"A", "O", "U", "E", "")
|| (current == 0))
/*
* e.g., 'wachtler', 'wechsler', but not 'tichner'
*/
&& StringAt(original, (current + 2), 1, "L", "R",
"N", "M", "B", "H", "F", "V", "W",
" ", "")))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
}
else
{
if (current > 0)
{
if (StringAt(original, 0, 2, "MC", ""))
{
/* e.g., "McHugh" */
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
}
else
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "K");
}
}
else
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
}
}
current += 2;
break;
}
/* e.g, 'czerny' */
if (StringAt(original, current, 2, "CZ", "")
&& !StringAt(original, (current - 2), 4, "WICZ", ""))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "X");
current += 2;
break;
}
/* e.g., 'focaccia' */
if (StringAt(original, (current + 1), 3, "CIA", ""))
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
current += 3;
break;
}
/* double 'C', but not if e.g. 'McClellan' */
if (StringAt(original, current, 2, "CC", "")
&& !((current == 1) && (GetAt(original, 0) == 'M')))
{
/* 'bellocchio' but not 'bacchus' */
if (StringAt(original, (current + 2), 1, "I", "E", "H", "")
&& !StringAt(original, (current + 2), 2, "HU", ""))
{
/* 'accident', 'accede' 'succeed' */
if (
((current == 1)
&& (GetAt(original, current - 1) == 'A'))
|| StringAt(original, (current - 1), 5, "UCCEE",
"UCCES", ""))
{
MetaphAdd(primary, "KS");
MetaphAdd(secondary, "KS");
/* 'bacci', 'bertucci', other italian */
}
else
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
}
current += 3;
break;
}
else
{ /* Pierce's rule */
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
current += 2;
break;
}
}
if (StringAt(original, current, 2, "CK", "CG", "CQ", ""))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
current += 2;
break;
}
if (StringAt(original, current, 2, "CI", "CE", "CY", ""))
{
/* italian vs. english */
if (StringAt
(original, current, 3, "CIO", "CIE", "CIA", ""))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "X");
}
else
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
}
current += 2;
break;
}
/* else */
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
/* name sent in 'mac caffrey', 'mac gregor */
if (StringAt(original, (current + 1), 2, " C", " Q", " G", ""))
current += 3;
else if (StringAt(original, (current + 1), 1, "C", "K", "Q", "")
&& !StringAt(original, (current + 1), 2,
"CE", "CI", ""))
current += 2;
else
current += 1;
break;
case 'D':
if (StringAt(original, current, 2, "DG", ""))
{
if (StringAt(original, (current + 2), 1,
"I", "E", "Y", ""))
{
/* e.g. 'edge' */
MetaphAdd(primary, "J");
MetaphAdd(secondary, "J");
current += 3;
break;
}
else
{
/* e.g. 'edgar' */
MetaphAdd(primary, "TK");
MetaphAdd(secondary, "TK");
current += 2;
break;
}
}
if (StringAt(original, current, 2, "DT", "DD", ""))
{
MetaphAdd(primary, "T");
MetaphAdd(secondary, "T");
current += 2;
break;
}
/* else */
MetaphAdd(primary, "T");
MetaphAdd(secondary, "T");
current += 1;
break;
case 'F':
if (GetAt(original, current + 1) == 'F')
current += 2;
else
current += 1;
MetaphAdd(primary, "F");
MetaphAdd(secondary, "F");
break;
case 'G':
if (GetAt(original, current + 1) == 'H')
{
if ((current > 0) && !IsVowel(original, current - 1))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
current += 2;
break;
}
if (current < 3)
{
/* 'ghislane', ghiradelli */
if (current == 0)
{
if (GetAt(original, current + 2) == 'I')
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "J");
}
else
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
}
current += 2;
break;
}
}
/*
* Parker's rule (with some further refinements) - e.g.,
* 'hugh'
*/
if (
((current > 1)
&& StringAt(original, (current - 2), 1,
"B", "H", "D", ""))
/* e.g., 'bough' */
|| ((current > 2)
&& StringAt(original, (current - 3), 1,
"B", "H", "D", ""))
/* e.g., 'broughton' */
|| ((current > 3)
&& StringAt(original, (current - 4), 1,
"B", "H", "")))
{
current += 2;
break;
}
else
{
/*
* e.g., 'laugh', 'McLaughlin', 'cough', 'gough',
* 'rough', 'tough'
*/
if ((current > 2)
&& (GetAt(original, current - 1) == 'U')
&& StringAt(original, (current - 3), 1, "C",
"G", "L", "R", "T", ""))
{
MetaphAdd(primary, "F");
MetaphAdd(secondary, "F");
}
else if ((current > 0)
&& GetAt(original, current - 1) != 'I')
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
}
current += 2;
break;
}
}
if (GetAt(original, current + 1) == 'N')
{
if ((current == 1) && IsVowel(original, 0)
&& !SlavoGermanic(original))
{
MetaphAdd(primary, "KN");
MetaphAdd(secondary, "N");
}
else
/* not e.g. 'cagney' */
if (!StringAt(original, (current + 2), 2, "EY", "")
&& (GetAt(original, current + 1) != 'Y')
&& !SlavoGermanic(original))
{
MetaphAdd(primary, "N");
MetaphAdd(secondary, "KN");
}
else
{
MetaphAdd(primary, "KN");
MetaphAdd(secondary, "KN");
}
current += 2;
break;
}
/* 'tagliaro' */
if (StringAt(original, (current + 1), 2, "LI", "")
&& !SlavoGermanic(original))
{
MetaphAdd(primary, "KL");
MetaphAdd(secondary, "L");
current += 2;
break;
}
/* -ges-,-gep-,-gel-, -gie- at beginning */
if ((current == 0)
&& ((GetAt(original, current + 1) == 'Y')
|| StringAt(original, (current + 1), 2, "ES", "EP",
"EB", "EL", "EY", "IB", "IL", "IN", "IE",
"EI", "ER", "")))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "J");
current += 2;
break;
}
/* -ger-, -gy- */
if (
(StringAt(original, (current + 1), 2, "ER", "")
|| (GetAt(original, current + 1) == 'Y'))
&& !StringAt(original, 0, 6,
"DANGER", "RANGER", "MANGER", "")
&& !StringAt(original, (current - 1), 1, "E", "I", "")
&& !StringAt(original, (current - 1), 3, "RGY", "OGY",
""))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "J");
current += 2;
break;
}
/* italian e.g, 'biaggi' */
if (StringAt(original, (current + 1), 1, "E", "I", "Y", "")
|| StringAt(original, (current - 1), 4,
"AGGI", "OGGI", ""))
{
/* obvious germanic */
if (
(StringAt(original, 0, 4, "VAN ", "VON ", "")
|| StringAt(original, 0, 3, "SCH", ""))
|| StringAt(original, (current + 1), 2, "ET", ""))
{
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
}
else
{
/* always soft if french ending */
if (StringAt
(original, (current + 1), 4, "IER ", ""))
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "J");
}
else
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "K");
}
}
current += 2;
break;
}
if (GetAt(original, current + 1) == 'G')
current += 2;
else
current += 1;
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
break;
case 'H':
/* only keep if first & before vowel or btw. 2 vowels */
if (((current == 0) || IsVowel(original, current - 1))
&& IsVowel(original, current + 1))
{
MetaphAdd(primary, "H");
MetaphAdd(secondary, "H");
current += 2;
}
else
/* also takes care of 'HH' */
current += 1;
break;
case 'J':
/* obvious spanish, 'jose', 'san jacinto' */
if (StringAt(original, current, 4, "JOSE", "")
|| StringAt(original, 0, 4, "SAN ", ""))
{
if (((current == 0)
&& (GetAt(original, current + 4) == ' '))
|| StringAt(original, 0, 4, "SAN ", ""))
{
MetaphAdd(primary, "H");
MetaphAdd(secondary, "H");
}
else
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "H");
}
current += 1;
break;
}
if ((current == 0)
&& !StringAt(original, current, 4, "JOSE", ""))
{
MetaphAdd(primary, "J"); /* Yankelovich/Jankelowicz */
MetaphAdd(secondary, "A");
}
else
{
/* spanish pron. of e.g. 'bajador' */
if (IsVowel(original, current - 1)
&& !SlavoGermanic(original)
&& ((GetAt(original, current + 1) == 'A')
|| (GetAt(original, current + 1) == 'O')))
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "H");
}
else
{
if (current == last)
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "");
}
else
{
if (!StringAt(original, (current + 1), 1, "L", "T",
"K", "S", "N", "M", "B", "Z", "")
&& !StringAt(original, (current - 1), 1,
"S", "K", "L", ""))
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "J");
}
}
}
}
if (GetAt(original, current + 1) == 'J') /* it could happen! */
current += 2;
else
current += 1;
break;
case 'K':
if (GetAt(original, current + 1) == 'K')
current += 2;
else
current += 1;
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
break;
case 'L':
if (GetAt(original, current + 1) == 'L')
{
/* spanish e.g. 'cabrillo', 'gallegos' */
if (((current == (length - 3))
&& StringAt(original, (current - 1), 4, "ILLO",
"ILLA", "ALLE", ""))
|| ((StringAt(original, (last - 1), 2, "AS", "OS", "")
|| StringAt(original, last, 1, "A", "O", ""))
&& StringAt(original, (current - 1), 4,
"ALLE", "")))
{
MetaphAdd(primary, "L");
MetaphAdd(secondary, "");
current += 2;
break;
}
current += 2;
}
else
current += 1;
MetaphAdd(primary, "L");
MetaphAdd(secondary, "L");
break;
case 'M':
if ((StringAt(original, (current - 1), 3, "UMB", "")
&& (((current + 1) == last)
|| StringAt(original, (current + 2), 2, "ER", "")))
/* 'dumb','thumb' */
|| (GetAt(original, current + 1) == 'M'))
current += 2;
else
current += 1;
MetaphAdd(primary, "M");
MetaphAdd(secondary, "M");
break;
case 'N':
if (GetAt(original, current + 1) == 'N')
current += 2;
else
current += 1;
MetaphAdd(primary, "N");
MetaphAdd(secondary, "N");
break;
case '\xd1': /* N with tilde */
current += 1;
MetaphAdd(primary, "N");
MetaphAdd(secondary, "N");
break;
case 'P':
if (GetAt(original, current + 1) == 'H')
{
MetaphAdd(primary, "F");
MetaphAdd(secondary, "F");
current += 2;
break;
}
/* also account for "campbell", "raspberry" */
if (StringAt(original, (current + 1), 1, "P", "B", ""))
current += 2;
else
current += 1;
MetaphAdd(primary, "P");
MetaphAdd(secondary, "P");
break;
case 'Q':
if (GetAt(original, current + 1) == 'Q')
current += 2;
else
current += 1;
MetaphAdd(primary, "K");
MetaphAdd(secondary, "K");
break;
case 'R':
/* french e.g. 'rogier', but exclude 'hochmeier' */
if ((current == last)
&& !SlavoGermanic(original)
&& StringAt(original, (current - 2), 2, "IE", "")
&& !StringAt(original, (current - 4), 2, "ME", "MA", ""))
{
MetaphAdd(primary, "");
MetaphAdd(secondary, "R");
}
else
{
MetaphAdd(primary, "R");
MetaphAdd(secondary, "R");
}
if (GetAt(original, current + 1) == 'R')
current += 2;
else
current += 1;
break;
case 'S':
/* special cases 'island', 'isle', 'carlisle', 'carlysle' */
if (StringAt(original, (current - 1), 3, "ISL", "YSL", ""))
{
current += 1;
break;
}
/* special case 'sugar-' */
if ((current == 0)
&& StringAt(original, current, 5, "SUGAR", ""))
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "S");
current += 1;
break;
}
if (StringAt(original, current, 2, "SH", ""))
{
/* germanic */
if (StringAt
(original, (current + 1), 4, "HEIM", "HOEK", "HOLM",
"HOLZ", ""))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
}
else
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
}
current += 2;
break;
}
/* italian & armenian */
if (StringAt(original, current, 3, "SIO", "SIA", "")
|| StringAt(original, current, 4, "SIAN", ""))
{
if (!SlavoGermanic(original))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "X");
}
else
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
}
current += 3;
break;
}
/*
* german & anglicisations, e.g. 'smith' match 'schmidt',
* 'snider' match 'schneider' also, -sz- in slavic language
* although in hungarian it is pronounced 's'
*/
if (((current == 0)
&& StringAt(original, (current + 1), 1,
"M", "N", "L", "W", ""))
|| StringAt(original, (current + 1), 1, "Z", ""))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "X");
if (StringAt(original, (current + 1), 1, "Z", ""))
current += 2;
else
current += 1;
break;
}
if (StringAt(original, current, 2, "SC", ""))
{
/* Schlesinger's rule */
if (GetAt(original, current + 2) == 'H')
{
/* dutch origin, e.g. 'school', 'schooner' */
if (StringAt(original, (current + 3), 2,
"OO", "ER", "EN",
"UY", "ED", "EM", ""))
{
/* 'schermerhorn', 'schenker' */
if (StringAt(original, (current + 3), 2,
"ER", "EN", ""))
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "SK");
}
else
{
MetaphAdd(primary, "SK");
MetaphAdd(secondary, "SK");
}
current += 3;
break;
}
else
{
if ((current == 0) && !IsVowel(original, 3)
&& (GetAt(original, 3) != 'W'))
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "S");
}
else
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
}
current += 3;
break;
}
}
if (StringAt(original, (current + 2), 1,
"I", "E", "Y", ""))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
current += 3;
break;
}
/* else */
MetaphAdd(primary, "SK");
MetaphAdd(secondary, "SK");
current += 3;
break;
}
/* french e.g. 'resnais', 'artois' */
if ((current == last)
&& StringAt(original, (current - 2), 2, "AI", "OI", ""))
{
MetaphAdd(primary, "");
MetaphAdd(secondary, "S");
}
else
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
}
if (StringAt(original, (current + 1), 1, "S", "Z", ""))
current += 2;
else
current += 1;
break;
case 'T':
if (StringAt(original, current, 4, "TION", ""))
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
current += 3;
break;
}
if (StringAt(original, current, 3, "TIA", "TCH", ""))
{
MetaphAdd(primary, "X");
MetaphAdd(secondary, "X");
current += 3;
break;
}
if (StringAt(original, current, 2, "TH", "")
|| StringAt(original, current, 3, "TTH", ""))
{
/* special case 'thomas', 'thames' or germanic */
if (StringAt(original, (current + 2), 2, "OM", "AM", "")
|| StringAt(original, 0, 4, "VAN ", "VON ", "")
|| StringAt(original, 0, 3, "SCH", ""))
{
MetaphAdd(primary, "T");
MetaphAdd(secondary, "T");
}
else
{
MetaphAdd(primary, "0");
MetaphAdd(secondary, "T");
}
current += 2;
break;
}
if (StringAt(original, (current + 1), 1, "T", "D", ""))
current += 2;
else
current += 1;
MetaphAdd(primary, "T");
MetaphAdd(secondary, "T");
break;
case 'V':
if (GetAt(original, current + 1) == 'V')
current += 2;
else
current += 1;
MetaphAdd(primary, "F");
MetaphAdd(secondary, "F");
break;
case 'W':
/* can also be in middle of word */
if (StringAt(original, current, 2, "WR", ""))
{
MetaphAdd(primary, "R");
MetaphAdd(secondary, "R");
current += 2;
break;
}
if ((current == 0)
&& (IsVowel(original, current + 1)
|| StringAt(original, current, 2, "WH", "")))
{
/* Wasserman should match Vasserman */
if (IsVowel(original, current + 1))
{
MetaphAdd(primary, "A");
MetaphAdd(secondary, "F");
}
else
{
/* need Uomo to match Womo */
MetaphAdd(primary, "A");
MetaphAdd(secondary, "A");
}
}
/* Arnow should match Arnoff */
if (((current == last) && IsVowel(original, current - 1))
|| StringAt(original, (current - 1), 5, "EWSKI", "EWSKY",
"OWSKI", "OWSKY", "")
|| StringAt(original, 0, 3, "SCH", ""))
{
MetaphAdd(primary, "");
MetaphAdd(secondary, "F");
current += 1;
break;
}
/* polish e.g. 'filipowicz' */
if (StringAt(original, current, 4, "WICZ", "WITZ", ""))
{
MetaphAdd(primary, "TS");
MetaphAdd(secondary, "FX");
current += 4;
break;
}
/* else skip it */
current += 1;
break;
case 'X':
/* french e.g. breaux */
if (!((current == last)
&& (StringAt(original, (current - 3), 3,
"IAU", "EAU", "")
|| StringAt(original, (current - 2), 2,
"AU", "OU", ""))))
{
MetaphAdd(primary, "KS");
MetaphAdd(secondary, "KS");
}
if (StringAt(original, (current + 1), 1, "C", "X", ""))
current += 2;
else
current += 1;
break;
case 'Z':
/* chinese pinyin e.g. 'zhao' */
if (GetAt(original, current + 1) == 'H')
{
MetaphAdd(primary, "J");
MetaphAdd(secondary, "J");
current += 2;
break;
}
else if (StringAt(original, (current + 1), 2,
"ZO", "ZI", "ZA", "")
|| (SlavoGermanic(original)
&& ((current > 0)
&& GetAt(original, current - 1) != 'T')))
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "TS");
}
else
{
MetaphAdd(primary, "S");
MetaphAdd(secondary, "S");
}
if (GetAt(original, current + 1) == 'Z')
current += 2;
else
current += 1;
break;
default:
current += 1;
}
/*
* printf("PRIMARY: %s\n", primary->str); printf("SECONDARY: %s\n",
* secondary->str);
*/
}
if (primary->length > 4)
SetAt(primary, 4, '\0');
if (secondary->length > 4)
SetAt(secondary, 4, '\0');
*codes = primary->str;
*++codes = secondary->str;
DestroyMetaString(original);
DestroyMetaString(primary);
DestroyMetaString(secondary);
}
| static char GetAt | ( | metastring * | s, | |
| int | pos | |||
| ) | [static] |
Definition at line 326 of file dmetaphone.c.
References metastring::length, and metastring::str.
Referenced by DoubleMetaphone().
| static void IncreaseBuffer | ( | metastring * | s, | |
| int | chars_needed | |||
| ) | [static] |
Definition at line 274 of file dmetaphone.c.
References assert, metastring::bufsize, META_REALLOC, NULL, and metastring::str.
Referenced by MetaphAdd().
| static int IsVowel | ( | metastring * | s, | |
| int | pos | |||
| ) | [static] |
Definition at line 293 of file dmetaphone.c.
References metastring::length, and metastring::str.
Referenced by DoubleMetaphone().
| static void MakeUpper | ( | metastring * | s | ) | [static] |
Definition at line 283 of file dmetaphone.c.
References i, and metastring::str.
Referenced by DoubleMetaphone().
| static void MetaphAdd | ( | metastring * | s, | |
| char * | new_str | |||
| ) | [static] |
Definition at line 376 of file dmetaphone.c.
References metastring::bufsize, IncreaseBuffer(), metastring::length, NULL, and metastring::str.
Referenced by DoubleMetaphone().
| static metastring* NewMetaString | ( | char * | init_str | ) | [static] |
Definition at line 236 of file dmetaphone.c.
References assert, metastring::bufsize, metastring::free_string_on_destroy, metastring::length, META_MALLOC, NULL, and metastring::str.
Referenced by DoubleMetaphone().
{
metastring *s;
char empty_string[] = "";
META_MALLOC(s, 1, metastring);
assert(s != NULL);
if (init_str == NULL)
init_str = empty_string;
s->length = strlen(init_str);
/* preallocate a bit more for potential growth */
s->bufsize = s->length + 7;
META_MALLOC(s->str, s->bufsize, char);
assert(s->str != NULL);
strncpy(s->str, init_str, s->length + 1);
s->free_string_on_destroy = 1;
return s;
}
| PG_FUNCTION_INFO_V1 | ( | dmetaphone | ) |
| PG_FUNCTION_INFO_V1 | ( | dmetaphone_alt | ) |
| static void SetAt | ( | metastring * | s, | |
| int | pos, | |||
| char | c | |||
| ) | [static] |
Definition at line 336 of file dmetaphone.c.
References metastring::length, and metastring::str.
Referenced by DoubleMetaphone().
| static int SlavoGermanic | ( | metastring * | s | ) | [static] |
Definition at line 310 of file dmetaphone.c.
References metastring::str.
Referenced by DoubleMetaphone().
| static int StringAt | ( | metastring * | s, | |
| int | start, | |||
| int | length, | |||
| ... | ||||
| ) | [static] |
Definition at line 349 of file dmetaphone.c.
References metastring::length, and metastring::str.
Referenced by DoubleMetaphone().
1.7.1