xref: /php-src/ext/standard/soundex.c (revision 25a51461)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Author: Bjørn Borud - Guardian Networks AS <borud@guardian.no>       |
14    +----------------------------------------------------------------------+
15  */
16 
17 #include "php.h"
18 #include <stdlib.h>
19 #include <ctype.h>
20 
21 /* Simple soundex algorithm as described by Knuth in TAOCP, vol 3 */
22 /* {{{ Calculate the soundex key of a string */
PHP_FUNCTION(soundex)23 PHP_FUNCTION(soundex)
24 {
25 	char	*str;
26 	size_t	i, _small, str_len, code, last;
27 	char	soundex[4 + 1];
28 
29 	static const char soundex_table[26] =
30 	{0,							/* A */
31 	 '1',						/* B */
32 	 '2',						/* C */
33 	 '3',						/* D */
34 	 0,							/* E */
35 	 '1',						/* F */
36 	 '2',						/* G */
37 	 0,							/* H */
38 	 0,							/* I */
39 	 '2',						/* J */
40 	 '2',						/* K */
41 	 '4',						/* L */
42 	 '5',						/* M */
43 	 '5',						/* N */
44 	 0,							/* O */
45 	 '1',						/* P */
46 	 '2',						/* Q */
47 	 '6',						/* R */
48 	 '2',						/* S */
49 	 '3',						/* T */
50 	 0,							/* U */
51 	 '1',						/* V */
52 	 0,							/* W */
53 	 '2',						/* X */
54 	 0,							/* Y */
55 	 '2'};						/* Z */
56 
57 	ZEND_PARSE_PARAMETERS_START(1, 1)
58 		Z_PARAM_STRING(str, str_len)
59 	ZEND_PARSE_PARAMETERS_END();
60 
61 	/* build soundex string */
62 	last = -1;
63 	for (i = 0, _small = 0; i < str_len && _small < 4; i++) {
64 		/* convert chars to upper case and strip non-letter chars */
65 		/* BUG: should also map here accented letters used in non */
66 		/* English words or names (also found in English text!): */
67 		/* esstsett, thorn, n-tilde, c-cedilla, s-caron, ... */
68 		code = toupper((int)(unsigned char)str[i]);
69 		if (code >= 'A' && code <= 'Z') {
70 			if (_small == 0) {
71 				/* remember first valid char */
72 				soundex[_small++] = (char)code;
73 				last = soundex_table[code - 'A'];
74 			}
75 			else {
76 				/* ignore sequences of consonants with same soundex */
77 				/* code in trail, and vowels unless they separate */
78 				/* consonant letters */
79 				code = soundex_table[code - 'A'];
80 				if (code != last) {
81 					if (code != 0) {
82 						soundex[_small++] = (char)code;
83 					}
84 					last = code;
85 				}
86 			}
87 		}
88 	}
89 	/* pad with '0' and terminate with 0 ;-) */
90 	while (_small < 4) {
91 		soundex[_small++] = '0';
92 	}
93 	soundex[_small] = '\0';
94 
95 	RETURN_STRINGL(soundex, _small);
96 }
97 /* }}} */
98