/* I add modifications to the traditional metaphone algorithm that you mightfindinbooks.Definethisifyouwantmetaphonetobehave
traditionally */ #undef USE_TRADITIONAL_METAPHONE
/* Special encodings */ #define SH 'X' #define TH '0'
staticchar Lookahead(char *word, int how_far); staticvoid _metaphone(char *word, int max_phonemes, char **phoned_word);
/* Metachar.h ... little bits about characters for metaphone */
/*-- Character encoding array & accessing macros --*/ /* Stolen directly out of the book... */ staticconstchar _codes[26] = { 1, 16, 4, 16, 9, 2, 4, 16, 9, 2, 0, 2, 2, 2, 1, 4, 0, 2, 4, 4, 1, 0, 0, 0, 8, 0 /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
};
staticint
getcode(char c)
{ if (isalpha((unsignedchar) c))
{
c = toupper((unsignedchar) c); /* Defend against non-ASCII letters */ if (c >= 'A' && c <= 'Z') return _codes[c - 'A'];
} return0;
}
#define isvowel(c) (getcode(c) & 1) /* AEIOU */
/* These letters are passed through unchanged */ #define NOCHANGE(c) (getcode(c) & 2) /* FJMNR */
/* These form diphthongs when preceding H */ #define AFFECTH(c) (getcode(c) & 4) /* CGPST */
/* These make C and G soft */ #define MAKESOFT(c) (getcode(c) & 8) /* EIY */
/* These prevent GH from becoming F */ #define NOGHTOF(c) (getcode(c) & 16) /* BDH */
PG_FUNCTION_INFO_V1(levenshtein_with_costs);
Datum
levenshtein_with_costs(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_PP(0);
text *dst = PG_GETARG_TEXT_PP(1); int ins_c = PG_GETARG_INT32(2); int del_c = PG_GETARG_INT32(3); int sub_c = PG_GETARG_INT32(4); constchar *s_data; constchar *t_data; int s_bytes,
t_bytes;
/* Extract a pointer to the actual character data */
s_data = VARDATA_ANY(src);
t_data = VARDATA_ANY(dst); /* Determine length of each string in bytes */
s_bytes = VARSIZE_ANY_EXHDR(src);
t_bytes = VARSIZE_ANY_EXHDR(dst);
PG_FUNCTION_INFO_V1(levenshtein);
Datum
levenshtein(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_PP(0);
text *dst = PG_GETARG_TEXT_PP(1); constchar *s_data; constchar *t_data; int s_bytes,
t_bytes;
/* Extract a pointer to the actual character data */
s_data = VARDATA_ANY(src);
t_data = VARDATA_ANY(dst); /* Determine length of each string in bytes */
s_bytes = VARSIZE_ANY_EXHDR(src);
t_bytes = VARSIZE_ANY_EXHDR(dst);
PG_FUNCTION_INFO_V1(levenshtein_less_equal_with_costs);
Datum
levenshtein_less_equal_with_costs(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_PP(0);
text *dst = PG_GETARG_TEXT_PP(1); int ins_c = PG_GETARG_INT32(2); int del_c = PG_GETARG_INT32(3); int sub_c = PG_GETARG_INT32(4); int max_d = PG_GETARG_INT32(5); constchar *s_data; constchar *t_data; int s_bytes,
t_bytes;
/* Extract a pointer to the actual character data */
s_data = VARDATA_ANY(src);
t_data = VARDATA_ANY(dst); /* Determine length of each string in bytes */
s_bytes = VARSIZE_ANY_EXHDR(src);
t_bytes = VARSIZE_ANY_EXHDR(dst);
PG_FUNCTION_INFO_V1(levenshtein_less_equal);
Datum
levenshtein_less_equal(PG_FUNCTION_ARGS)
{
text *src = PG_GETARG_TEXT_PP(0);
text *dst = PG_GETARG_TEXT_PP(1); int max_d = PG_GETARG_INT32(2); constchar *s_data; constchar *t_data; int s_bytes,
t_bytes;
/* Extract a pointer to the actual character data */
s_data = VARDATA_ANY(src);
t_data = VARDATA_ANY(dst); /* Determine length of each string in bytes */
s_bytes = VARSIZE_ANY_EXHDR(src);
t_bytes = VARSIZE_ANY_EXHDR(dst);
/* return an empty string if we receive one */ if (!(str_i_len > 0))
PG_RETURN_TEXT_P(cstring_to_text(""));
if (str_i_len > MAX_METAPHONE_STRLEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument exceeds the maximum length of %d bytes",
MAX_METAPHONE_STRLEN)));
reqlen = PG_GETARG_INT32(1); if (reqlen > MAX_METAPHONE_STRLEN)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output exceeds the maximum length of %d bytes",
MAX_METAPHONE_STRLEN)));
if (!(reqlen > 0))
ereport(ERROR,
(errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
errmsg("output cannot be empty string")));
/* I suppose I could have been using a character pointer instead of
* accessing the array directly... */
/* Look at the next letter in the word */ #define Next_Letter (toupper((unsignedchar) word[w_idx+1])) /* Look at the current letter in the word */ #define Curr_Letter (toupper((unsignedchar) word[w_idx])) /* Go N letters back. */ #define Look_Back_Letter(n) \
(w_idx >= (n) ? toupper((unsignedchar) word[w_idx-(n)]) : '\0') /* Previous letter. I dunno, should this return null on failure? */ #define Prev_Letter (Look_Back_Letter(1)) /* Look two letters down. It makes sure you don't walk off the string. */ #define After_Next_Letter \
(Next_Letter != '\0' ? toupper((unsignedchar) word[w_idx+2]) : '\0') #define Look_Ahead_Letter(n) toupper((unsignedchar) Lookahead(word+w_idx, n))
/* Allows us to safely look ahead an arbitrary # of letters */ /* I probably could have just used strlen... */ staticchar
Lookahead(char *word, int how_far)
{ char letter_ahead = '\0'; /* null by default */ int idx;
for (idx = 0; word[idx] != '\0' && idx < how_far; idx++); /* Edge forward in the string... */
letter_ahead = word[idx]; /* idx will be either == to how_far or at the
* end of the string */ return letter_ahead;
}
/* phonize one letter */ #define Phonize(c) do {(*phoned_word)[p_idx++] = c;} while (0) /* Slap a null character on the end of the phoned word */ #define End_Phoned_Word do {(*phoned_word)[p_idx] = '\0';} while (0) /* How long is the phoned word? */ #define Phone_Len (p_idx)
/* Note is a letter is a 'break' in the word */ #define Isbreak(c) (!isalpha((unsignedchar) (c)))
staticvoid
_metaphone(char *word, /* IN */ int max_phonemes, char **phoned_word) /* OUT */
{ int w_idx = 0; /* point in the phonization we're at. */ int p_idx = 0; /* end of the phoned phrase */
/* Negative phoneme length is meaningless */ if (!(max_phonemes > 0)) /* internal error */
elog(ERROR, "metaphone: Requested output length must be > 0");
/* Empty/null string is meaningless */ if ((word == NULL) || !(strlen(word) > 0)) /* internal error */
elog(ERROR, "metaphone: Input string length must be > 0");
/*-- Allocate memory for our phoned_phrase --*/ if (max_phonemes == 0)
{ /* Assume largest possible */
*phoned_word = palloc(sizeof(char) * strlen(word) + 1);
} else
{
*phoned_word = palloc(sizeof(char) * max_phonemes + 1);
}
/*-- The first phoneme has to be processed specially. --*/ /* Find our first letter */ for (; !isalpha((unsignedchar) (Curr_Letter)); w_idx++)
{ /* On the off chance we were given nothing but crap... */ if (Curr_Letter == '\0')
{
End_Phoned_Word; return;
}
}
switch (Curr_Letter)
{ /* AE becomes E */ case'A': if (Next_Letter == 'E')
{
Phonize('E');
w_idx += 2;
} /* Remember, preserve vowels at the beginning */ else
{
Phonize('A');
w_idx++;
} break; /* [GKP]N becomes N */ case'G': case'K': case'P': if (Next_Letter == 'N')
{
Phonize('N');
w_idx += 2;
} break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.