Skip to content

Commit af5537c

Browse files
committed
Added an implementation of the Soundex DIFFERENCE algorithm, a feature requested in http://nagoya.apache.org/bugzilla/show_bug.cgi?id=25243.
Note that this commit only covers adding the difference API to the Soundex class. See the ticket for comments. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/codec/trunk@130267 13f79535-47bb-0310-9956-ffa450edef68
1 parent 5117837 commit af5537c

4 files changed

Lines changed: 172 additions & 93 deletions

File tree

RELEASE-NOTES.txt

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,23 @@
1-
$Id: RELEASE-NOTES.txt,v 1.12 2003/11/25 05:03:29 tobrien Exp $
1+
$Id: RELEASE-NOTES.txt,v 1.13 2003/12/10 00:04:46 ggregory Exp $
22

33
Commons Codec Package
4-
Version 1.2
4+
Version 1.3-dev
55
Release Notes
66

77

88
INTRODUCTION:
99

1010
This document contains the release notes for this version of the Commons
1111
Codec package, and highlights changes since the previous version. Version
12-
1.2 contains bug fixes for the 1.1 release.
12+
1.3 contains bug fixes for the 1.2 release.
1313

1414
NEW FEATURES:
1515

16-
* URLCodec - Implements the 'www-form-urlencoded' encoding scheme
16+
* Soundex - Implemented the DIFFERENCE algorithm.
1717

18-
* DigestUtils - Simple utility class that provides static convenience
19-
methods for calculating md5 and hex digests.
18+
BUG FIXES:
2019

20+
* Fix for Bug XXXX: ZZZZ
2121

22-
BUG FIXES:
22+
* Fixes for missing tags in Javadoc comments.
2323

24-
* Fix for Bug 19860: Modified Base64 to remedy non-compliance with RFC
25-
2045. Non-Base64 characters were not being discarded during the
26-
decode. RFC 2045 explicitly states that all characters outside of the
27-
base64 alphabet are to be ignored.
28-
29-
* Fix for Bug 24360: Hex.decode(Object) throws a ClassCastException
30-
when a String argument is passed in.
31-
32-
* Fix for Bug 24471: Soundex: The HW rule is not applied; hyphens and
33-
apostrophes are not ignored.
34-
35-
* Fix for Bug 24484: Soundex.setMaxLength causes bugs and is not needed.
36-
Calling Soundex.setMaxLength() with a value of 2 or less causes the wrong
37-
answer to be returned. Since the encoding returned by Soundex is always
38-
of length 4 by definition (we do not use the '-' in as a letter-nnn
39-
separator) the need for a maxLength attribute is not needed. Deprecate
40-
the field and accessor methods.
41-
42-
* Fix in Metaphone relating to the handling of the maximum code length.

default.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#$Id: default.properties,v 1.8 2003/11/26 03:18:28 ggregory Exp $
1+
#$Id: default.properties,v 1.9 2003/12/10 00:04:46 ggregory Exp $
22

33
# The pathname of the "junit.jar" JAR file
44
junit.jar = ${junit.home}/junit-3.7.jar
@@ -13,7 +13,7 @@ component.package = org.apache.commons.codec
1313
component.title = Encode/Decode Utilities
1414

1515
# The current version number of this component
16-
component.version = 1.2
16+
component.version = 1.3-dev
1717

1818
# The name that is used to create the jar file
1919
final.name = ${component.name}-${component.version}

src/java/org/apache/commons/codec/language/Soundex.java

Lines changed: 136 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,45 @@
22
* ====================================================================
33
*
44
* The Apache Software License, Version 1.1
5-
*
6-
* Copyright (c) 2001-2003 The Apache Software Foundation. All rights
7-
* reserved.
8-
*
5+
*
6+
* Copyright (c) 2001-2003 The Apache Software Foundation. All rights reserved.
7+
*
98
* Redistribution and use in source and binary forms, with or without
10-
* modification, are permitted provided that the following conditions
11-
* are met:
12-
*
13-
* 1. Redistributions of source code must retain the above copyright
14-
* notice, this list of conditions and the following disclaimer.
15-
*
16-
* 2. Redistributions in binary form must reproduce the above copyright
17-
* notice, this list of conditions and the following disclaimer in
18-
* the documentation and/or other materials provided with the
19-
* distribution.
20-
*
21-
* 3. The end-user documentation included with the redistribution,
22-
* if any, must include the following acknowledgement:
23-
* "This product includes software developed by the
24-
* Apache Software Foundation (http://www.apache.org/)."
25-
* Alternately, this acknowledgement may appear in the software itself,
26-
* if and wherever such third-party acknowledgements normally appear.
27-
*
28-
* 4. The names "Apache", "The Jakarta Project", "Commons", and "Apache Software
29-
* Foundation" must not be used to endorse or promote products derived
30-
* from this software without prior written permission. For written
31-
* permission, please contact apache@apache.org.
32-
*
33-
* 5. Products derived from this software may not be called "Apache",
34-
* "Apache" nor may "Apache" appear in their name without prior
35-
* written permission of the Apache Software Foundation.
36-
*
37-
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38-
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39-
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40-
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41-
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42-
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43-
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44-
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45-
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46-
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47-
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48-
* SUCH DAMAGE.
9+
* modification, are permitted provided that the following conditions are met: 1.
10+
* Redistributions of source code must retain the above copyright notice, this
11+
* list of conditions and the following disclaimer. 2. Redistributions in
12+
* binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other
14+
* materials provided with the distribution. 3. The end-user documentation
15+
* included with the redistribution, if any, must include the following
16+
* acknowledgement: "This product includes software developed by the Apache
17+
* Software Foundation (http://www.apache.org/)." Alternately, this
18+
* acknowledgement may appear in the software itself, if and wherever such
19+
* third-party acknowledgements normally appear. 4. The names "Apache", "The
20+
* Jakarta Project", "Commons", and "Apache Software Foundation" must not be
21+
* used to endorse or promote products derived from this software without prior
22+
* written permission. For written permission, please contact
23+
* apache@apache.org. 5. Products derived from this software may not be called
24+
* "Apache", "Apache" nor may "Apache" appear in their name without prior
25+
* written permission of the Apache Software Foundation.
26+
*
27+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
28+
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29+
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30+
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
31+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4937
* ====================================================================
50-
*
51-
* This software consists of voluntary contributions made by many
52-
* individuals on behalf of the Apache Software Foundation. For more
53-
* information on the Apache Software Foundation, please see
54-
* <http://www.apache.org/>.
55-
*
56-
*/
38+
*
39+
* This software consists of voluntary contributions made by many individuals
40+
* on behalf of the Apache Software Foundation. For more information on the
41+
* Apache Software Foundation, please see <http://www.apache.org/> .
42+
*
43+
*/
5744

5845
package org.apache.commons.codec.language;
5946

@@ -68,7 +55,7 @@
6855
* @author bayard@generationjava.com
6956
* @author Tim O'Brien
7057
* @author Gary Gregory
71-
* @version $Id: Soundex.java,v 1.13 2003/11/12 19:02:57 ggregory Exp $
58+
* @version $Id: Soundex.java,v 1.14 2003/12/10 00:04:46 ggregory Exp $
7259
*/
7360
public class Soundex implements StringEncoder {
7461

@@ -84,11 +71,93 @@ public class Soundex implements StringEncoder {
8471
*/
8572
public static final char[] US_ENGLISH_MAPPING = "01230120022455012623010202".toCharArray();
8673

74+
/**
75+
* Returns the difference between the Soundex values of two Strings. For
76+
* Soundex, this return value ranges from 0 through 4: 0 indicates little or
77+
* no similarity, and 4 indicates strong similarity or identical values.
78+
*
79+
* @param s1
80+
* A String.
81+
* @param s2
82+
* A String.
83+
* @return The return value ranges from 0 through 4: 0 indicates little or
84+
* no similarity, and 4 indicates strong similarity or identical
85+
* values.
86+
*
87+
* @see #difference(StringEncoder,String,String)
88+
* @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp">
89+
* MS T-SQL DIFFERENCE</a>
90+
*
91+
* @throws EncoderException
92+
* if an error occurs encoding one of the strings
93+
*/
94+
public int difference(String s1, String s2) throws EncoderException {
95+
return difference(this, s1, s2);
96+
}
97+
98+
/**
99+
* Returns the difference between the encoded values of two Strings. The
100+
* higher the difference factor, the more similar the strings. For Soundex,
101+
* this return value ranges from 0 through 4: 0 indicates little or no
102+
* similarity, and 4 indicates strong similarity or identical values.
103+
*
104+
* @param encoder
105+
* The encoder to use to encode the String parameters with.
106+
* @param s1
107+
* A String.
108+
* @param s2
109+
* A String.
110+
* @return an integer from 0 to the length of the shorter string. The
111+
* smaller the number, the more different the strings are.
112+
*
113+
* @see #differenceEncoded(String,String)
114+
* @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp">
115+
* MS T-SQL DIFFERENCE</a>
116+
*
117+
* @throws EncoderException
118+
* if an error occurs encoding one of the strings
119+
*/
120+
public static int difference(StringEncoder encoder, String s1, String s2) throws EncoderException {
121+
return differenceEncoded(encoder.encode(s1), encoder.encode(s2));
122+
}
123+
124+
/**
125+
* Returns the difference between the values of two encoded Strings. The
126+
* higher the difference factor, the more similar the strings. For Soundex,
127+
* this return value ranges from 0 through 4: 0 indicates little or no
128+
* similarity, and 4 indicates strong similarity or identical values.
129+
*
130+
* @param es1
131+
* An encoded String.
132+
* @param es2
133+
* An encoded String.
134+
* @return an integer from 0 to the length of the shorter string. The
135+
* smaller the number, the more different the strings are.
136+
*
137+
* @see <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp">
138+
* MS T-SQL DIFFERENCE</a>
139+
*/
140+
public static int differenceEncoded(String es1, String es2) {
141+
142+
if (es1 == null || es2 == null) {
143+
return 0;
144+
}
145+
int lengthToMatch = Math.min(es1.length(), es2.length());
146+
int diff = 0;
147+
for (int i = 0; i < lengthToMatch; i++) {
148+
if (es1.charAt(i) == es2.charAt(i)) {
149+
diff++;
150+
}
151+
}
152+
return diff;
153+
}
154+
87155
/**
88156
* The maximum length of a Soundex code - Soundex codes are only four
89157
* characters by definition.
90-
*
91-
* @deprecated This feature is not needed since the encoding size must be constant.
158+
*
159+
* @deprecated This feature is not needed since the encoding size must be
160+
* constant.
92161
*/
93162
private int maxLength = 4;
94163

@@ -123,6 +192,10 @@ public Soundex(char[] mapping) {
123192
/**
124193
* Cleans up the input string before Soundex processing by only returning
125194
* upper case letters.
195+
*
196+
* @param str
197+
* The String to clean
198+
* @return a clean String.
126199
*/
127200
private String clean(String str) {
128201
if (str == null || str.length() == 0) {
@@ -211,7 +284,8 @@ private char getMappingCode(String str, int index) {
211284
/**
212285
* Returns the maxLength. Standard Soundex
213286
*
214-
* @deprecated This feature is not needed since the encoding size must be constant.
287+
* @deprecated This feature is not needed since the encoding size must be
288+
* constant.
215289
* @return int
216290
*/
217291
public int getMaxLength() {
@@ -227,6 +301,10 @@ private char[] getSoundexMapping() {
227301

228302
/**
229303
* Maps the given upper-case character to it's Soudex code.
304+
*
305+
* @param c
306+
* An upper-case character.
307+
* @return A Soundex code.
230308
*/
231309
private char map(char c) {
232310
return this.getSoundexMapping()[c - 'A'];
@@ -235,7 +313,8 @@ private char map(char c) {
235313
/**
236314
* Sets the maxLength.
237315
*
238-
* @deprecated This feature is not needed since the encoding size must be constant.
316+
* @deprecated This feature is not needed since the encoding size must be
317+
* constant.
239318
* @param maxLength
240319
* The maxLength to set
241320
*/
@@ -266,7 +345,7 @@ public String soundex(String str) {
266345
if (str.length() == 0) {
267346
return str;
268347
}
269-
char out[] = { '0', '0', '0', '0' };
348+
char out[] = {'0', '0', '0', '0'};
270349
char last, mapped;
271350
int incount = 1, count = 1;
272351
out[0] = str.charAt(0);
@@ -283,4 +362,4 @@ public String soundex(String str) {
283362
return new String(out);
284363
}
285364

286-
}
365+
}

src/test/org/apache/commons/codec/language/SoundexTest.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,14 @@
6060

6161
import junit.framework.Test;
6262
import junit.framework.TestSuite;
63+
import org.apache.commons.codec.EncoderException;
6364
import org.apache.commons.codec.StringEncoder;
6465
import org.apache.commons.codec.StringEncoderAbstractTest;
6566

6667
/**
6768
* Tests {@link Soundex}
6869
*
69-
* @version $Revision: 1.9 $ $Date: 2003/12/04 23:32:39 $
70+
* @version $Revision: 1.10 $ $Date: 2003/12/10 00:04:46 $
7071
* @author Rodney Waldhoff
7172
* @author Gary Gregory
7273
*/
@@ -81,6 +82,12 @@ public static Test suite() {
8182
public SoundexTest(String name) {
8283
super(name);
8384
}
85+
86+
void encodeAll(String[] strings, String expectedEncoding) {
87+
for (int i = 0; i < strings.length; i++) {
88+
assertEquals(expectedEncoding, this.getEncoder().encode(strings[i]));
89+
}
90+
}
8491

8592
/**
8693
* @return Returns the _encoder.
@@ -111,12 +118,6 @@ public void tearDown() throws Exception {
111118
this.setEncoder(null);
112119
}
113120

114-
void encodeAll(String[] strings, String expectedEncoding) {
115-
for (int i = 0; i < strings.length; i++) {
116-
assertEquals(expectedEncoding, this.getEncoder().encode(strings[i]));
117-
}
118-
}
119-
120121
public void testB650() {
121122
this.encodeAll(
122123
new String[] {
@@ -163,6 +164,25 @@ public void testB650() {
163164
"B650");
164165
}
165166

167+
public void testDifference() throws EncoderException {
168+
// Edge cases
169+
assertEquals(this.getEncoder().difference(null, null), 0);
170+
assertEquals(this.getEncoder().difference("", ""), 0);
171+
assertEquals(this.getEncoder().difference(" ", " "), 0);
172+
// Normal cases
173+
assertEquals(this.getEncoder().difference("Smith", "Smythe"), 4);
174+
assertEquals(this.getEncoder().difference("Ann", "Andrew"), 2);
175+
assertEquals(this.getEncoder().difference("Margaret", "Andrew"), 1);
176+
assertEquals(this.getEncoder().difference("Janet", "Margaret"), 0);
177+
// Examples from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp
178+
assertEquals(this.getEncoder().difference("Green", "Greene"), 4);
179+
assertEquals(this.getEncoder().difference("Blotchet-Halls", "Greene"), 0);
180+
// Examples from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_setu-sus_3o6w.asp
181+
assertEquals(this.getEncoder().difference("Smith", "Smythe"), 4);
182+
assertEquals(this.getEncoder().difference("Smithers", "Smythers"), 4);
183+
assertEquals(this.getEncoder().difference("Anothers", "Brothers"), 2);
184+
}
185+
166186
public void testEncodeBasic() {
167187
assertEquals("T235", this.getEncoder().encode("testing"));
168188
assertEquals("T000", this.getEncoder().encode("The"));
@@ -342,7 +362,6 @@ public void testMsSqlServer1() {
342362
public void testMsSqlServer2() {
343363
this.encodeAll(new String[]{"Erickson", "Erickson", "Erikson", "Ericson", "Ericksen", "Ericsen"}, "E625");
344364
}
345-
346365
/**
347366
* Examples for MS SQLServer from
348367
* http://databases.about.com/library/weekly/aa042901a.htm

0 commit comments

Comments
 (0)