142.md 4.5 KB
Newer Older
W
wizardforcel 已提交
1 2 3 4 5 6
# 使用 Soundex 算法实现语音搜索

> 原文: [https://howtodoinjava.com/algorithm/implement-phonetic-search-using-soundex-algorithm/](https://howtodoinjava.com/algorithm/implement-phonetic-search-using-soundex-algorithm/)

您是否曾经想过,在任何单词编辑器中,拼写检查器会如何在您遇到任何拼写错误时建议您列出其他可能的单词? 这是通过**语音搜索**完成的。 **Soundex** 是一种语音算法,用于通过声音索引名称(英语发音)。 我们的目标是将同音异义词(发音与另一个单词相同,但含义不同,并且拼写可能有所不同)被编码为相同的表示形式,以便尽管拼写稍有不同(例如, `bear - beer``Nelson - Neilson - Neelson`

W
wizardforcel 已提交
7
现在,它已成为流行的数据库软件(例如 *DB2,PostgreSQL,MySQL,Ingres,MS SQL Server 和 Oracle*)以及一些主要单词编辑器的标准功能。
W
wizardforcel 已提交
8 9 10 11 12 13 14 15 16 17 18

## Soundex 算法

该算法由罗伯特·罗素(Robert Russell)在 1910 年针对英语单词开发。 该算法的主要原理是,辅音根据序数进行分组,最后被编码为与其他辅音匹配的值。 它旨在通过上述过程为每个单词找到一个代码,称为 soundex 代码。

```java
The Soundex code for a name consists of a letter followed by three numerical digits: the letter is the first letter of the name, and the digits encode the remaining consonants.
```

查找 soundex 代码的完整算法如下:

W
wizardforcel 已提交
19
1.  保留名称的第一个字母,并删除所有其他出现的`a, e, i, o, u, y, h, w`
W
wizardforcel 已提交
20
2.  如下将辅音替换为数字(在第一个字母之后):
W
wizardforcel 已提交
21 22 23 24 25 26 27 28 29 30 31 32 33 34

    `b, f, p, v → 1`

    `c, g, j, k, q, s, x, z → 2`

    `d, t → 3`

    `l → 4`

    `m, n→5`

    `r → 6`

3.  如果两个或两个以上具有相同编号的字母在原始名称中相邻(在步骤 1 之前),则仅保留第一个字母;否则,将保留第一个字母。 同样,两个以“`h`”或“`w`”分隔的相同数字的字母也被编码为一个数字,而以元音分隔的此类字母被编码两次。 此规则也适用于首字母。
W
wizardforcel 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
4.  重复上一步,直到有一个字母和三个数字。 如果您的单词字母太少而无法分配三个数字,请在后面加上零,直到三个数字为止。 如果您的字母超过 3 个,则只需保留前 3 个数字即可。

## Java 的 Soundex 实现

Soundex 算法的一种实现如下:

```java
package com.howtodoinjava.examples;

public class Soundex 
{
	public static String getGode(String s) 
	{
		char[] x = s.toUpperCase().toCharArray();

		char firstLetter = x[0];

		//RULE [ 2 ]
		//Convert letters to numeric code
		for (int i = 0; i < x.length; i++) {
			switch (x[i]) {
			case 'B':
			case 'F':
			case 'P':
			case 'V': {
				x[i] = '1';
				break;
			}

			case 'C':
			case 'G':
			case 'J':
			case 'K':
			case 'Q':
			case 'S':
			case 'X':
			case 'Z': {
				x[i] = '2';
				break;
			}

			case 'D':
			case 'T': {
				x[i] = '3';
				break;
			}

			case 'L': {
				x[i] = '4';
				break;
			}

			case 'M':
			case 'N': {
				x[i] = '5';
				break;
			}

			case 'R': {
				x[i] = '6';
				break;
			}

			default: {
				x[i] = '0';
				break;
			}
			}
		}

		//Remove duplicates
		//RULE [ 1 ]
		String output = "" + firstLetter;

		//RULE [ 3 ]
		for (int i = 1; i < x.length; i++)
			if (x[i] != x[i - 1] && x[i] != '0')
				output += x[i];

		//RULE [ 4 ]
		//Pad with 0's or truncate
		output = output + "0000";
		return output.substring(0, 4);
	}
}

```

让我们看看如何使用上述算法。

```java
class Main {
	public static void main(String[] args) 
	{
		String name1 = "beer";
		String name2 = "bear";
		String name3 = "bearer";

		System.out.println(Soundex.getGode(name1));
		System.out.println(Soundex.getGode(name2));
		System.out.println(Soundex.getGode(name3));
	}
}

Output:

B600
B600
B660

```

W
wizardforcel 已提交
147
从上面的输出中很明显,单词“`bear`”和“`beer`”具有相同的代码; 所以他们是语音的 “`bearer`”一词具有不同的代码,因为它的语音不同。
W
wizardforcel 已提交
148

W
wizardforcel 已提交
149
您可以查看一些可用的 soundex 算法实现,例如 [**Apache Commons Soundex 实现**](https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Soundex.html)
W
wizardforcel 已提交
150 151 152 153

#### 参考文献

[https://zh.wikipedia.org/wiki/Soundex](https://en.wikipedia.org/wiki/Soundex)
W
wizardforcel 已提交
154

W
wizardforcel 已提交
155 156 157
[http://introcs.cs.princeton.edu/java/31datatype/Soundex.java.html](http://introcs.cs.princeton.edu/java/31datatype/Soundex.java.html)

**祝您学习愉快!**