IndicPhone is a universal algorithm for phonetically hashing Indic-language words written in all Brahmic scripts in the Unicode table, similar to the Metaphone algorithm for English. For a given word, it generates three Romanized phonetic keys (hashes), each representing an increasing degree of affinity to various phonetic properties of the original word. It was originally written in 2013 for enabling fuzzy search in the Olam Malayalam dictionary.
The algorithm generates phonetic hashes for Indic words by accounting for linguistic features such as compounding and gemination. It exploits the consistent phonetic ordering of glyphs (derived from the ISCII-based Unicode layout) in Brahmic scripts in their respective Unicode blocks, to transform all Indic glyphs in a single pass using a universal mapping of phonetic offsets to alphanumeric Roman characters.
| Input | key0 | key1 | key2 |
|---|
| Input | key0 | key1 | key2 |
|---|---|---|---|
| Kamala | |||
| कमल | KML | KML | KML |
| কমল | KML | KML | KML |
| ಕಮಲ | KML | KML | KML |
| കമല | KML | KML | KML |
| Svatantra | |||
| स्वतन्त्र | SV0N0R | SV0N0R | SV0N0R |
| স্বতন্ত্র | SB0N0R | SB0N0R | SB0N0R |
| ಸ್ವತನ್ತ್ರ | SV0N0R | SV0N0R | SV0N0R |
| സ്വതന്ത്ര | SV0N0R | SV0N0R | SV0N0R |
| Namaste | |||
| नमस्ते | NMS0 | NMS0 | NMS06 |
| নমস্তে | NMS0 | NMS0 | NMS06 |
| ನಮಸ್ತೇ | NMS0 | NMS0 | NMS06 |
| നമസ്തേ | NMS0 | NMS0 | NMS06 |
| Nīlakkuyil | |||
| नीलक्कुयिल् | NLKYL | NLKYL | N4LK25Y4L |
| নীলক্কুযিল্ | NLKYL | NLKYL | N4LK25Y4L |
| ನೀಲಕ್ಕುಯಿಲ್ | NLKYL | NLKYL | N4LK25Y4L |
| നീലക്കുയിൽ | NLKYL | NLKYL | N4LK25Y4L |
| Gaṅgā | |||
| गंग | K3K | K3K | K3K |
| গংগ | K3K | K3K | K3K |
| ಗಂಗ | K3K | K3K | K3K |
| ഗംഗ | K3K | K3K | K3K |
| Himālaya | |||
| हिमालय | HMLY | HMLY | H4MLY |
| হিমালয় | HMLY | HMLY | H4MLY |
| ಹಿಮಾಲಯ | HMLY | HMLY | H4MLY |
| ഹിമാലയ | HMLY | HMLY | H4MLY |
IndicPhone converts a word in any Indic/Brahmic script into three phonetic hashes in a single left-to-right pass. The crux of the algorithm is a universal phonetic mapping table that is shared across every script, which is used to map sounds to specific Roman characters.
Each Brahmic script has its own distinctive 128-point Unicode block, where all blocks follow the same ISCII-derived phonetic ordering. A given offset (the position of a glyph within a block) represents the same sound in every script. For example, offset 0x15 is क in Devanagari, ক in Bengali, ಕ in Kannada, and ക in Malayalam, all the same K sound.
| offset | Devanagari | Bengali | Kannada | Malayalam | Code |
|---|---|---|---|---|---|
| Vowels | |||||
| 0x5 | अ | অ | ಅ | അ | A |
| 0x6 | आ | আ | ಆ | ആ | A |
| 0x7 | इ | ই | ಇ | ഇ | I |
| 0x8 | ई | ঈ | ಈ | ഈ | I |
| 0x9 | उ | উ | ಉ | ഉ | U |
| 0xa | ऊ | ঊ | ಊ | ഊ | U |
| 0xb | ऋ | ঋ | ಋ | ഋ | R |
| 0xe | ऎ | — | ಎ | എ | E |
| 0xf | ए | এ | ಏ | ഏ | E |
| 0x10 | ऐ | ঐ | ಐ | ഐ | AI |
| 0x12 | ऒ | — | ಒ | ഒ | O |
| 0x13 | ओ | ও | ಓ | ഓ | O |
| 0x14 | औ | ঔ | ಔ | ഔ | O |
| 0x60 | ॠ | ৠ | ೠ | ൠ | R |
| Consonants | |||||
| 0x15 | क | ক | ಕ | ക | K |
| 0x16 | ख | খ | ಖ | ഖ | K |
| 0x17 | ग | গ | ಗ | ഗ | K |
| 0x18 | घ | ঘ | ಘ | ഘ | K |
| 0x19 | ङ | ঙ | ಙ | ങ | NG |
| 0x1a | च | চ | ಚ | ച | C |
| 0x1b | छ | ছ | ಛ | ഛ | C |
| 0x1c | ज | জ | ಜ | ജ | J |
| 0x1d | झ | ঝ | ಝ | ഝ | J |
| 0x1e | ञ | ঞ | ಞ | ഞ | NJ |
| 0x1f | ट | ট | ಟ | ട | T |
| 0x20 | ठ | ঠ | ಠ | ഠ | T |
| 0x21 | ड | ড | ಡ | ഡ | T |
| 0x22 | ढ | ঢ | ಢ | ഢ | T |
| 0x23 | ण | ণ | ಣ | ണ | N1 |
| 0x24 | त | ত | ತ | ത | 0 |
| 0x25 | थ | থ | ಥ | ഥ | 0 |
| 0x26 | द | দ | ದ | ദ | 0 |
| 0x27 | ध | ধ | ಧ | ധ | 0 |
| 0x28 | न | ন | ನ | ന | N |
| 0x2a | प | প | ಪ | പ | P |
| 0x2b | फ | ফ | ಫ | ഫ | F |
| 0x2c | ब | ব | ಬ | ബ | B |
| 0x2d | भ | ভ | ಭ | ഭ | B |
| 0x2e | म | ম | ಮ | മ | M |
| 0x2f | य | য | ಯ | യ | Y |
| 0x30 | र | র | ರ | ര | R |
| 0x31 | ऱ | — | ಱ | റ | R1 |
| 0x32 | ल | ল | ಲ | ല | L |
| 0x33 | ळ | — | ಳ | ള | L1 |
| 0x34 | ऴ | — | — | ഴ | Z |
| 0x35 | व | — | ವ | വ | V |
| 0x36 | श | শ | ಶ | ശ | S1 |
| 0x37 | ष | ষ | ಷ | ഷ | S1 |
| 0x38 | स | স | ಸ | സ | S |
| 0x39 | ह | হ | ಹ | ഹ | H |
Blank cell = no glyph at the particular Unicode offset.
As Brahmic scripts are abugidas, a consonant carries the inherent a sound. This is assumed to be the default. Other phonetic properties are denoted by appending a specific modifier digit to the consonant's code (see §3). The broader keys are derived by dropping specific digit classes (see §3.1).
| Input | Rule | → key2 |
|---|---|---|
| mlക hiक bnক knಕ | inherent 'a' | K |
| mlകി hiकि bnকি knಕಿ | vowel sign (mātrā) | K4 |
| mlകു hiकु bnকু knಕು | vowel sign | K5 |
| mlക്ക hiक्क bnক্ক knಕ್ಕ | gemination (doubled glyphs) | K2 |
| mlകം hiकं bnকং knಕಂ | anusvāra | K3 |
K0K.A; ഇ, इ → I.Phonetic details beyond the mapped letter in the table is recorded by appending a modifier digit to that letter's Roman code. The finest key, key2, retains all properties; the coarser key1 and key0 are formed by stripping specific digit classes from them.
| Digit | Description | Example | Exists in |
|---|---|---|---|
| 1 | "Hard" sound (retroflex vs. sibilant distinction) | ण → N1, ष → S1 | key1, key2 |
| 2 | Gemination (doubled consonant) | ക്ക → K2 | key2 |
| 3 | Anusvāra | കം → K3 | key0, key1, key2 |
| 4–9 | Mātrā (vowel signs) 4 = i/ī 5 = u/ū 6 = e/ē 7 = ai 8 = o/ō 9 = au |
കി → K4 | key2 |
0 is not in any digit classes. 0 is not a modifier digit, but is a base sound coded after the Greek θ's "th" for the dental plosives ('dantya', eg: त थ द ध). While the anusvāra 3 is a modifier, nasalisation inherently changes a word's identity too much, so it is not discarded like other digit classes. So, both these digits are retained in every key, while every other digit class ([1], 02, 4–9) are dropped in classes to form the coarser keys.
| Key | Type | Result |
|---|---|---|
| key2 | Full encoding | Retain all digits |
| key1 | key2 sans [2] and [4-9] | Drops gemination and vowel signs. Keeps hard sounds [1] and anusvāra [3] |
| key0 | key1 sans [1] | Drops hard sounds and keeps only anusvāra [3] |
The algorithm parses a word character by character, left to right, in one pass. It holds at most one consonant at a time and tracks three states (idle, holding a consonant, and
| Character | Type | State | Code | key2 |
|---|---|---|---|---|
| ന | consonant | Hold consonant N | — | |
| ◌ീ | vowel sign (ī) | Emit held N and then the vowel | N4 | N4 |
| ല | consonant | Hold consonant L | — | N4 |
| ക | consonant | Emit held L and hold K | L | N4L |
| ◌് | virama | Begin conjunct while K still held | — | N4L |
| ക | consonant | Same consonant after virama, so it's a geminate | K2 | N4LK2 |
| ◌ു | vowel sign (u) | Attach the vowel | 5 | N4LK25 |
| യ | consonant | Hold consonant Y | — | N4LK25 |
| ◌ി | vowel sign (i) | Emit held Y and then the vowel | Y4 | N4LK25Y4 |
| ൽ | chillu (ḷ) | Emit the bare consonant directly | L | N4LK25Y4L |
The final key2 is then reduced to two coarser keys by stripping away classes of digits:
| Key | Hash | Digits stripped |
|---|---|---|
| key2 | N4LK25Y4L | — |
| key1 | NLKYL | Vowel/gemination digits [2], [4-9] |
| key0 | NLKYL | Hard-sound marker [1] |