# 使用 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`等

现在，它已成为流行的数据库软件（例如 *DB2，PostgreSQL，MySQL，Ingres，MS SQL Server 和 Oracle*）以及一些主要单词编辑器的标准功能。

## 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 代码的完整算法如下：

1.  保留名称的第一个字母，并删除所有其他出现的`a, e, i, o, u, y, h, w`。
2.  如下将辅音替换为数字（在第一个字母之后）：

    `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`”分隔的相同数字的字母也被编码为一个数字，而以元音分隔的此类字母被编码两次。 此规则也适用于首字母。
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

```

从上面的输出中很明显，单词“`bear`”和“`beer`”具有相同的代码； 所以他们是语音的 “`bearer`”一词具有不同的代码，因为它的语音不同。

您可以查看一些可用的 soundex 算法实现，例如 [**Apache Commons Soundex 实现**](https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/language/Soundex.html)。

#### 参考文献

[https://zh.wikipedia.org/wiki/Soundex](https://en.wikipedia.org/wiki/Soundex)

[http://introcs.cs.princeton.edu/java/31datatype/Soundex.java.html](http://introcs.cs.princeton.edu/java/31datatype/Soundex.java.html)

**祝您学习愉快！**