Author: ggregory
Date: Mon Aug  8 22:47:24 2011
New Revision: 1155135

URL: http://svn.apache.org/viewvc?rev=1155135&view=rev
Log:
[CODEC-125] Implement a Beider-Morse phonetic matching codec. Applied patch 
https://issues.apache.org/jira/secure/attachment/12489755/fightingMemoryChurn.patch

Modified:
    
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Lang.java
    
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Languages.java
    
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/NameType.java
    
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
    
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Rule.java
    
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/BeiderMorseEncoderTest.java
    
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/RuleTest.java

Modified: 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Lang.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Lang.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Lang.java
 (original)
+++ 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Lang.java
 Mon Aug  8 22:47:24 2011
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.EnumMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Scanner;
 import java.util.Set;
@@ -71,7 +72,7 @@ import java.util.regex.Pattern;
  */
 public class Lang {
 
-    private static class LangRule {
+    private static final class LangRule {
         private final boolean acceptOnMatch;
         private final Set<String> languages;
         private final Pattern pattern;
@@ -199,7 +200,7 @@ public class Lang {
      */
     public String guessLanguage(String text) {
         Languages.LanguageSet ls = guessLanguages(text);
-        return ls.isSingleton() ? ls.getAny() : Languages.ANY; 
+        return ls.isSingleton() ? ls.getAny() : Languages.ANY;
     }
 
     /**
@@ -210,7 +211,7 @@ public class Lang {
      * @return a Set of Strings of language names that are potential matches 
for the input word
      */
     public Languages.LanguageSet guessLanguages(String input) {
-        String text = input.toLowerCase(); // todo: locale?
+        String text = input.toLowerCase(Locale.ENGLISH);
         // System.out.println("Testing text: '" + text + "'");
 
         Set<String> langs = new HashSet<String>(this.languages.getLanguages());

Modified: 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Languages.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Languages.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Languages.java
 (original)
+++ 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Languages.java
 Mon Aug  8 22:47:24 2011
@@ -58,9 +58,9 @@ public class Languages {
      * A set of languages.
      */
     public static abstract class LanguageSet {
-        
+
         public static LanguageSet from(Set<String> langs) {
-            return langs.isEmpty() ? NO_LANGUAGES : new SomeLanguages(langs);  
+            return langs.isEmpty() ? NO_LANGUAGES : new SomeLanguages(langs);
         }
 
         public abstract boolean contains(String language);
@@ -77,7 +77,7 @@ public class Languages {
     /**
      * Some languages, explicitly enumerated.
      */
-    public static class SomeLanguages extends LanguageSet {
+    public static final class SomeLanguages extends LanguageSet {
         private final Set<String> languages;
 
         private SomeLanguages(Set<String> languages) {
@@ -116,9 +116,13 @@ public class Languages {
                 return this;
             } else {
                 SomeLanguages sl = (SomeLanguages) other;
-                Set<String> ls = new HashSet<String>(this.languages);
-                ls.retainAll(sl.languages);
-                return from(ls);
+                if (sl.languages.containsAll(languages)) {
+                    return this;
+                } else {
+                    Set<String> ls = new HashSet<String>(this.languages);
+                    ls.retainAll(sl.languages);
+                    return from(ls);
+                }
             }
         }
 

Modified: 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/NameType.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/NameType.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/NameType.java
 (original)
+++ 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/NameType.java
 Mon Aug  8 22:47:24 2011
@@ -24,13 +24,13 @@ package org.apache.commons.codec.languag
  * @since 2.0
  */
 public enum NameType {
-    
+
     /** Ashkenazi family names */
     ASHKENAZI("ash"),
-    
+
     /** Generic names and words */
     GENERIC("gen"),
-    
+
     /** Sephardic family names */
     SEPHARDIC("sep");
 

Modified: 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/PhoneticEngine.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
 (original)
+++ 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
 Mon Aug  8 22:47:24 2011
@@ -51,7 +51,7 @@ import java.util.TreeSet;
  */
 public class PhoneticEngine {
 
-    static class PhonemeBuilder {
+    static final class PhonemeBuilder {
 
         public static PhonemeBuilder empty(Languages.LanguageSet languages) {
             return new PhonemeBuilder(Collections.singleton(new 
Rule.Phoneme("", languages)));
@@ -108,7 +108,7 @@ public class PhoneticEngine {
         }
     }
 
-    private static class RulesApplication {
+    private static final class RulesApplication {
         private final List<Rule> finalRules;
         private final CharSequence input;
 
@@ -176,6 +176,32 @@ public class PhoneticEngine {
                 "de la", "della", "des", "di", "do", "dos", "du", "van", 
"von"))));
     }
 
+    private static CharSequence cacheSubSequence(final CharSequence cached) {
+        // return cached;
+        final CharSequence[][] cache = new 
CharSequence[cached.length()][cached.length()];
+        return new CharSequence() {
+            public char charAt(int index) {
+                return cached.charAt(index);
+            }
+
+            public int length() {
+                return cached.length();
+            }
+
+            public CharSequence subSequence(int start, int end) {
+                if (start == end)
+                    return "";
+
+                CharSequence res = cache[start][end - 1];
+                if (res == null) {
+                    res = cached.subSequence(start, end);
+                    cache[start][end - 1] = res;
+                }
+                return res;
+            }
+        };
+    }
+
     private static String join(Iterable<String> strings, String sep) {
         StringBuilder sb = new StringBuilder();
         Iterator<String> si = strings.iterator();
@@ -229,7 +255,7 @@ public class PhoneticEngine {
 
         for (Rule.Phoneme phoneme : phonemeBuilder.getPhonemes()) {
             PhonemeBuilder subBuilder = 
PhonemeBuilder.empty(phoneme.getLanguages());
-            CharSequence phonemeText = phoneme.getPhonemeText();
+            CharSequence phonemeText = 
cacheSubSequence(phoneme.getPhonemeText());
             // System.err.println("Expanding: " + phonemeText);
 
             for (int i = 0; i < phonemeText.length();) {
@@ -248,7 +274,7 @@ public class PhoneticEngine {
             }
 
             // System.err.println("Expanded to: " + subBuilder.makeString());
-
+            // System.err.println("phenomes in collection of type: " + 
subBuilder.getPhonemes().getClass());
             phonemes.addAll(subBuilder.getPhonemes());
         }
 
@@ -345,8 +371,9 @@ public class PhoneticEngine {
         PhonemeBuilder phonemeBuilder = PhonemeBuilder.empty(languageSet);
 
         // loop over each char in the input - we will handle the increment 
manually
-        for (int i = 0; i < input.length();) {
-            RulesApplication rulesApplication = new RulesApplication(rules, 
input, phonemeBuilder, i).invoke();
+        CharSequence inputCache = cacheSubSequence(input);
+        for (int i = 0; i < inputCache.length();) {
+            RulesApplication rulesApplication = new RulesApplication(rules, 
inputCache, phonemeBuilder, i).invoke();
             i = rulesApplication.getI();
             phonemeBuilder = rulesApplication.getPhonemeBuilder();
             // System.err.println(input + " " + i + ": " + 
phonemeBuilder.makeString());

Modified: 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Rule.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Rule.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Rule.java
 (original)
+++ 
commons/proper/codec/trunk/src/java/org/apache/commons/codec/language/bm/Rule.java
 Mon Aug  8 22:47:24 2011
@@ -80,68 +80,7 @@ import java.util.regex.Pattern;
  */
 public class Rule {
 
-    private static class AppendableCharSeqeuence implements CharSequence {
-
-        private final CharSequence left;
-        private final CharSequence right;
-        private final int length;
-        private String contentCache = null;
-
-        private AppendableCharSeqeuence(CharSequence left, CharSequence right) 
{
-            this.left = left;
-            this.right = right;
-            this.length = left.length() + right.length();
-        }
-
-        public void buildString(StringBuilder sb) {
-            if (left instanceof AppendableCharSeqeuence) {
-                ((AppendableCharSeqeuence) left).buildString(sb);
-            } else {
-                sb.append(left);
-            }
-            if (right instanceof AppendableCharSeqeuence) {
-                ((AppendableCharSeqeuence) right).buildString(sb);
-            } else {
-                sb.append(right);
-            }
-        }
-
-        public char charAt(int index) {
-            // int lLength = left.length();
-            // if(index < lLength) return left.charAt(index);
-            // else return right.charAt(index - lLength);
-            return toString().charAt(index);
-        }
-
-        public int length() {
-            return length;
-        }
-
-        public CharSequence subSequence(int start, int end) {
-            // int lLength = left.length();
-            // if(start > lLength) return right.subSequence(start - lLength, 
end - lLength);
-            // else if(end <= lLength) return left.subSequence(start, end);
-            // else {
-            // CharSequence newLeft = left.subSequence(start, lLength);
-            // CharSequence newRight = right.subSequence(0, end - lLength);
-            // return new AppendableCharSeqeuence(newLeft, newRight);
-            // }
-            return toString().subSequence(start, end);
-        }
-
-        @Override
-        public String toString() {
-            if (contentCache == null) {
-                StringBuilder sb = new StringBuilder();
-                buildString(sb);
-                contentCache = sb.toString();
-                // System.err.println("Materialized string: " + contentCache);
-            }
-            return contentCache;
-        }
-    }
-
-    public static class Phoneme implements PhonemeExpr, Comparable<Phoneme> {
+    public static final class Phoneme implements PhonemeExpr, 
Comparable<Phoneme> {
 
         private final CharSequence phonemeText;
         private final Languages.LanguageSet languages;
@@ -152,7 +91,7 @@ public class Rule {
         }
 
         public Phoneme append(CharSequence str) {
-            return new Phoneme(new AppendableCharSeqeuence(this.phonemeText, 
str), this.languages);
+            return new Phoneme(this.phonemeText.toString() + str.toString(), 
this.languages);
         }
 
         public int compareTo(Phoneme o) {
@@ -186,7 +125,7 @@ public class Rule {
         }
 
         public Phoneme join(Phoneme right) {
-            return new Phoneme(new AppendableCharSeqeuence(this.phonemeText, 
right.phonemeText), this.languages.restrictTo(right.languages));
+            return new Phoneme(this.phonemeText.toString() + 
right.phonemeText.toString(), this.languages.restrictTo(right.languages));
         }
     }
 
@@ -194,7 +133,7 @@ public class Rule {
         Iterable<Phoneme> getPhonemes();
     }
 
-    public static class PhonemeList implements PhonemeExpr {
+    public static final class PhonemeList implements PhonemeExpr {
         private final List<Phoneme> phonemes;
 
         public PhonemeList(List<Phoneme> phonemes) {
@@ -207,44 +146,17 @@ public class Rule {
     }
 
     /**
-     * A minimal wrapper around the functionality of Matcher that we use, to 
allow for alternate implementations.
+     * A minimal wrapper around the functionality of Pattern that we use, to 
allow for alternate implementations.
      */
-    public static interface RMatcher {
-        boolean find();
+    public static interface RPattern {
+        boolean isMatch(CharSequence input);
     }
 
-    /**
-     * Always returns true.
-     */
-    private static class TrueRMatcher implements RMatcher {
-
-        private static TrueRMatcher INSTANCE = new TrueRMatcher();
-
-        /**
-         * Always returns true.
-         */
-        public boolean find() {
+    public static final RPattern ALL_STRINGS_RMATCHER = new RPattern() {
+        public boolean isMatch(CharSequence input) {
             return true;
         }
-
-    }
-
-    private static class AllStringsRMatcher implements RPattern {
-
-        private static AllStringsRMatcher INSTANCE = new AllStringsRMatcher();
-
-        public RMatcher matcher(CharSequence input) {
-            return TrueRMatcher.INSTANCE;
-        }
-
-    }
-
-    /**
-     * A minimal wrapper around the functionality of Pattern that we use, to 
allow for alternate implementations.
-     */
-    public static interface RPattern {
-        RMatcher matcher(CharSequence input);
-    }
+    };
 
     public static final String ALL = "ALL";
 
@@ -500,48 +412,32 @@ public class Rule {
                 if (content.length() == 0) {
                     // empty
                     return new RPattern() {
-                        public RMatcher matcher(final CharSequence input) {
-                            return new RMatcher() {
-                                public boolean find() {
-                                    return input.length() == 0;
-                                }
-                            };
+                        public boolean isMatch(CharSequence input) {
+                            return input.length() == 0;
                         }
                     };
                 } else {
                     return new RPattern() {
-                        public RMatcher matcher(final CharSequence input) {
-                            return new RMatcher() {
-                                public boolean find() {
-                                    return input.equals(content);
-                                }
-                            };
+                        public boolean isMatch(CharSequence input) {
+                            return input.equals(content);
                         }
                     };
                 }
             } else if ((startsWith || endsWith) && content.length() == 0) {
                 // matches every string
-                return AllStringsRMatcher.INSTANCE;
+                return ALL_STRINGS_RMATCHER;
             } else if (startsWith) {
                 // matches from start
                 return new RPattern() {
-                    public RMatcher matcher(final CharSequence input) {
-                        return new RMatcher() {
-                            public boolean find() {
-                                return startsWith(input, content);
-                            }
-                        };
+                    public boolean isMatch(CharSequence input) {
+                        return startsWith(input, content);
                     }
                 };
             } else if (endsWith) {
                 // matches from start
                 return new RPattern() {
-                    public RMatcher matcher(final CharSequence input) {
-                        return new RMatcher() {
-                            public boolean find() {
-                                return endsWith(input, content);
-                            }
-                        };
+                    public boolean isMatch(CharSequence input) {
+                        return endsWith(input, content);
                     }
                 };
             }
@@ -563,34 +459,22 @@ public class Rule {
                     if (startsWith && endsWith) {
                         // exact match
                         return new RPattern() {
-                            public RMatcher matcher(final CharSequence input) {
-                                return new RMatcher() {
-                                    public boolean find() {
-                                        return input.length() == 1 && 
(contains(bContent, input.charAt(0)) == shouldMatch);
-                                    }
-                                };
+                            public boolean isMatch(CharSequence input) {
+                                return input.length() == 1 && 
(contains(bContent, input.charAt(0)) == shouldMatch);
                             }
                         };
                     } else if (startsWith) {
                         // first char
                         return new RPattern() {
-                            public RMatcher matcher(final CharSequence input) {
-                                return new RMatcher() {
-                                    public boolean find() {
-                                        return input.length() > 0 && 
(contains(bContent, input.charAt(0)) == shouldMatch);
-                                    }
-                                };
+                            public boolean isMatch(CharSequence input) {
+                                return input.length() > 0 && 
(contains(bContent, input.charAt(0)) == shouldMatch);
                             }
                         };
                     } else if (endsWith) {
                         // last char
                         return new RPattern() {
-                            public RMatcher matcher(final CharSequence input) {
-                                return new RMatcher() {
-                                    public boolean find() {
-                                        return input.length() > 0 && 
(contains(bContent, input.charAt(input.length() - 1)) == shouldMatch);
-                                    }
-                                };
+                            public boolean isMatch(CharSequence input) {
+                                return input.length() > 0 && 
(contains(bContent, input.charAt(input.length() - 1)) == shouldMatch);
                             }
                         };
                     }
@@ -602,13 +486,9 @@ public class Rule {
         return new RPattern() {
             Pattern pattern = Pattern.compile(regex);
 
-            public RMatcher matcher(CharSequence input) {
-                final Matcher matcher = pattern.matcher(input);
-                return new RMatcher() {
-                    public boolean find() {
-                        return matcher.find();
-                    }
-                };
+            public boolean isMatch(CharSequence input) {
+                Matcher matcher = pattern.matcher(input);
+                return matcher.find();
             }
         };
     }
@@ -723,8 +603,8 @@ public class Rule {
         }
 
         boolean patternMatches = input.subSequence(i, 
ipl).equals(this.pattern);
-        boolean rContextMatches = this.rContext.matcher(input.subSequence(ipl, 
input.length())).find();
-        boolean lContextMatches = this.lContext.matcher(input.subSequence(0, 
i)).find();
+        boolean rContextMatches = this.rContext.isMatch(input.subSequence(ipl, 
input.length()));
+        boolean lContextMatches = this.lContext.isMatch(input.subSequence(0, 
i));
 
         return patternMatches && rContextMatches && lContextMatches;
     }

Modified: 
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/BeiderMorseEncoderTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/BeiderMorseEncoderTest.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/BeiderMorseEncoderTest.java
 (original)
+++ 
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/BeiderMorseEncoderTest.java
 Mon Aug  8 22:47:24 2011
@@ -19,8 +19,6 @@ package org.apache.commons.codec.languag
 
 import static org.junit.Assert.assertEquals;
 
-import java.util.Random;
-
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.StringEncoder;
 import org.apache.commons.codec.StringEncoderAbstractTest;
@@ -165,7 +163,7 @@ public class BeiderMorseEncoderTest exte
     }
 
     /**
-     * (Un)luckily, the worse performing test because of the data in {@link 
TEST_CHARS}
+     * (Un)luckily, the worse performing test because of the data in {@link 
#TEST_CHARS}
      * 
      * @throws EncoderException
      */
@@ -183,34 +181,23 @@ public class BeiderMorseEncoderTest exte
         }
     }
 
-    /**
-     * Another odd performance edge case.
-     * 
-     * @throws EncoderException
-     */
-    @Test(/* timeout = 20000L */)
-    public void testSpeedCheckAZ() throws EncoderException {
+    @Test
+    public void testSpeedCheck2() throws EncoderException {
         BeiderMorseEncoder bmpm = this.createGenericApproxEncoder();
-        String phrase = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
+        String phrase = "ItstheendoftheworldasweknowitandIfeelfine";
+
         for (int i = 1; i <= phrase.length(); i++) {
             bmpm.encode(phrase.subSequence(0, i));
         }
     }
 
-    /**
-     * Runs between 1.6 and 13 seconds at length 40 for me (Gary Gregory, 
2011/08/06)
-     * 
-     * @throws EncoderException
-     */
-    @Test(/* timeout = 20000L */)
-    public void testSpeedCheckRandom() throws EncoderException {
+    @Test
+    public void testSpeedCheck3() throws EncoderException {
         BeiderMorseEncoder bmpm = this.createGenericApproxEncoder();
-        StringBuffer stringBuffer = new StringBuffer();
-        Random rand = new Random();
-        stringBuffer.append(TEST_CHARS[rand.nextInt(TEST_CHARS.length)]);
-        for (int i = 0; i < 40; i++) {
-            bmpm.encode(stringBuffer.toString());
-            stringBuffer.append(TEST_CHARS[rand.nextInt(TEST_CHARS.length)]);
+        String phrase = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
+
+        for (int i = 1; i <= phrase.length(); i++) {
+            bmpm.encode(phrase.subSequence(0, i));
         }
     }
 }

Modified: 
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/RuleTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/RuleTest.java?rev=1155135&r1=1155134&r2=1155135&view=diff
==============================================================================
--- 
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/RuleTest.java
 (original)
+++ 
commons/proper/codec/trunk/src/test/org/apache/commons/codec/language/bm/RuleTest.java
 Mon Aug  8 22:47:24 2011
@@ -80,4 +80,68 @@ public class RuleTest {
             }
         }
     }
+
+    @Test
+    public void subSequenceWorks() {
+        // AppendableCharSequence is private to Rule. We can only make it 
through a Phoneme.
+
+        Rule.Phoneme a = new Rule.Phoneme("a", null);
+        Rule.Phoneme b = new Rule.Phoneme("b", null);
+        Rule.Phoneme cd = new Rule.Phoneme("cd", null);
+        Rule.Phoneme ef = new Rule.Phoneme("ef", null);
+        Rule.Phoneme ghi = new Rule.Phoneme("ghi", null);
+        Rule.Phoneme jkl = new Rule.Phoneme("jkl", null);
+
+        assertEquals('a', a.getPhonemeText().charAt(0));
+        assertEquals('b', b.getPhonemeText().charAt(0));
+        assertEquals('c', cd.getPhonemeText().charAt(0));
+        assertEquals('d', cd.getPhonemeText().charAt(1));
+        assertEquals('e', ef.getPhonemeText().charAt(0));
+        assertEquals('f', ef.getPhonemeText().charAt(1));
+        assertEquals('g', ghi.getPhonemeText().charAt(0));
+        assertEquals('h', ghi.getPhonemeText().charAt(1));
+        assertEquals('i', ghi.getPhonemeText().charAt(2));
+        assertEquals('j', jkl.getPhonemeText().charAt(0));
+        assertEquals('k', jkl.getPhonemeText().charAt(1));
+        assertEquals('l', jkl.getPhonemeText().charAt(2));
+
+        Rule.Phoneme a_b = a.append(b.getPhonemeText());
+        assertEquals('a', a_b.getPhonemeText().charAt(0));
+        assertEquals('b', a_b.getPhonemeText().charAt(1));
+        assertEquals("ab", a_b.getPhonemeText().subSequence(0, 2).toString());
+        assertEquals("a", a_b.getPhonemeText().subSequence(0, 1).toString());
+        assertEquals("b", a_b.getPhonemeText().subSequence(1, 2).toString());
+
+        Rule.Phoneme cd_ef = cd.append(ef.getPhonemeText());
+        assertEquals('c', cd_ef.getPhonemeText().charAt(0));
+        assertEquals('d', cd_ef.getPhonemeText().charAt(1));
+        assertEquals('e', cd_ef.getPhonemeText().charAt(2));
+        assertEquals('f', cd_ef.getPhonemeText().charAt(3));
+        assertEquals("c", cd_ef.getPhonemeText().subSequence(0, 1).toString());
+        assertEquals("d", cd_ef.getPhonemeText().subSequence(1, 2).toString());
+        assertEquals("e", cd_ef.getPhonemeText().subSequence(2, 3).toString());
+        assertEquals("f", cd_ef.getPhonemeText().subSequence(3, 4).toString());
+        assertEquals("cd", cd_ef.getPhonemeText().subSequence(0, 
2).toString());
+        assertEquals("de", cd_ef.getPhonemeText().subSequence(1, 
3).toString());
+        assertEquals("ef", cd_ef.getPhonemeText().subSequence(2, 
4).toString());
+        assertEquals("cde", cd_ef.getPhonemeText().subSequence(0, 
3).toString());
+        assertEquals("def", cd_ef.getPhonemeText().subSequence(1, 
4).toString());
+        assertEquals("cdef", cd_ef.getPhonemeText().subSequence(0, 
4).toString());
+
+        Rule.Phoneme a_b_cd = 
a.append(b.getPhonemeText()).append(cd.getPhonemeText());
+        assertEquals('a', a_b_cd.getPhonemeText().charAt(0));
+        assertEquals('b', a_b_cd.getPhonemeText().charAt(1));
+        assertEquals('c', a_b_cd.getPhonemeText().charAt(2));
+        assertEquals('d', a_b_cd.getPhonemeText().charAt(3));
+        assertEquals("a", a_b_cd.getPhonemeText().subSequence(0, 
1).toString());
+        assertEquals("b", a_b_cd.getPhonemeText().subSequence(1, 
2).toString());
+        assertEquals("c", a_b_cd.getPhonemeText().subSequence(2, 
3).toString());
+        assertEquals("d", a_b_cd.getPhonemeText().subSequence(3, 
4).toString());
+        assertEquals("ab", a_b_cd.getPhonemeText().subSequence(0, 
2).toString());
+        assertEquals("bc", a_b_cd.getPhonemeText().subSequence(1, 
3).toString());
+        assertEquals("cd", a_b_cd.getPhonemeText().subSequence(2, 
4).toString());
+        assertEquals("abc", a_b_cd.getPhonemeText().subSequence(0, 
3).toString());
+        assertEquals("bcd", a_b_cd.getPhonemeText().subSequence(1, 
4).toString());
+        assertEquals("abcd", a_b_cd.getPhonemeText().subSequence(0, 
4).toString());
+    }
 }


Reply via email to