You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ch...@apache.org on 2017/03/04 00:59:26 UTC

[01/50] [abbrv] [text] Spelling

Repository: commons-text
Updated Branches:
  refs/heads/release 65e4314fb -> 2d522713c


Spelling

Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/7a96b500
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/7a96b500
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/7a96b500

Branch: refs/heads/release
Commit: 7a96b500028a7b63dac49c0449b52454b75f0e59
Parents: 13e5051
Author: Sebb <se...@apache.org>
Authored: Tue Feb 7 11:22:19 2017 +0000
Committer: Sebb <se...@apache.org>
Committed: Tue Feb 7 11:22:19 2017 +0000

----------------------------------------------------------------------
 RELEASE-NOTES.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/7a96b500/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 9dad4ee..56769a8 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -58,7 +58,7 @@ o TEXT-9:    Incorporate String algorithms from Commons Lang Thanks to britter.
 FIXED BUGS
 ==========
 
-Note. We recognize the curoisity of a new component having "fixed bugs," but a
+Note. We recognize the curiosity of a new component having "fixed bugs," but a
 considerable number of files were migrated over from Commons Lang, some of which
 needed fixes.
 


[31/50] [abbrv] [text] TEXT-65: 120 checkstyle errors now

Posted by ch...@apache.org.
TEXT-65: 120 checkstyle errors now


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/df0658f0
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/df0658f0
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/df0658f0

Branch: refs/heads/release
Commit: df0658f05b3113675d28dbe967d3326682f95dfe
Parents: 1035cd6
Author: Rob Tompkins <ch...@apache.org>
Authored: Mon Feb 13 07:53:54 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Mon Feb 13 07:53:54 2017 -0500

----------------------------------------------------------------------
 .../org/apache/commons/text/StrTokenizer.java   | 44 ++++++++++++--------
 .../text/translate/AggregateTranslator.java     | 17 ++++----
 .../text/translate/CharSequenceTranslator.java  | 32 ++++++++------
 3 files changed, 56 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/df0658f0/src/main/java/org/apache/commons/text/StrTokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrTokenizer.java b/src/main/java/org/apache/commons/text/StrTokenizer.java
index 8186f37..66126ec 100644
--- a/src/main/java/org/apache/commons/text/StrTokenizer.java
+++ b/src/main/java/org/apache/commons/text/StrTokenizer.java
@@ -83,7 +83,9 @@ import java.util.NoSuchElementException;
  */
 public class StrTokenizer implements ListIterator<String>, Cloneable {
 
+    /** Comma separated values tokenizer internal variable. */
     private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE;
+    /** Tab separated values tokenizer internal variable. */
     private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE;
     static {
         CSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
@@ -104,24 +106,24 @@ public class StrTokenizer implements ListIterator<String>, Cloneable {
     }
 
     /** The text to work on. */
-    private char chars[];
-    /** The parsed tokens */
-    private String tokens[];
-    /** The current iteration position */
+    private char[] chars;
+    /** The parsed tokens. */
+    private String[] tokens;
+    /** The current iteration position. */
     private int tokenPos;
 
-    /** The delimiter matcher */
+    /** The delimiter matcher. */
     private StrMatcher delimMatcher = StrMatcher.splitMatcher();
-    /** The quote matcher */
+    /** The quote matcher. */
     private StrMatcher quoteMatcher = StrMatcher.noneMatcher();
-    /** The ignored matcher */
+    /** The ignored matcher. */
     private StrMatcher ignoredMatcher = StrMatcher.noneMatcher();
-    /** The trimmer matcher */
+    /** The trimmer matcher. */
     private StrMatcher trimmerMatcher = StrMatcher.noneMatcher();
 
-    /** Whether to return empty tokens as null */
+    /** Whether to return empty tokens as null. */
     private boolean emptyAsNull = false;
-    /** Whether to ignore empty tokens */
+    /** Whether to ignore empty tokens. */
     private boolean ignoreEmptyTokens = true;
 
     //-----------------------------------------------------------------------
@@ -686,16 +688,20 @@ public class StrTokenizer implements ListIterator<String>, Cloneable {
      * @return the starting position of the next field (the character
      *  immediately after the delimiter), or -1 if end of string found
      */
-    private int readNextToken(final char[] srcChars, int start, final int len, final StrBuilder workArea, final List<String> tokenList) {
+    private int readNextToken(final char[] srcChars,
+                              int start,
+                              final int len,
+                              final StrBuilder workArea,
+                              final List<String> tokenList) {
         // skip all leading whitespace, unless it is the
         // field delimiter or the quote character
         while (start < len) {
             final int removeLen = Math.max(
                     getIgnoredMatcher().isMatch(srcChars, start, start, len),
                     getTrimmerMatcher().isMatch(srcChars, start, start, len));
-            if (removeLen == 0 ||
-                getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0 ||
-                getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) {
+            if (removeLen == 0
+                    || getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0
+                    || getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) {
                 break;
             }
             start += removeLen;
@@ -832,7 +838,11 @@ public class StrTokenizer implements ListIterator<String>, Cloneable {
      * @param quoteLen  the length of the matched quote, 0 if no quoting
      * @return true if a quote is matched
      */
-    private boolean isQuote(final char[] srcChars, final int pos, final int len, final int quoteStart, final int quoteLen) {
+    private boolean isQuote(final char[] srcChars,
+                            final int pos,
+                            final int len,
+                            final int quoteStart,
+                            final int quoteLen) {
         for (int i = 0; i < quoteLen; i++) {
             if (pos + i >= len || srcChars[pos + i] != srcChars[quoteStart + i]) {
                 return false;
@@ -1072,7 +1082,7 @@ public class StrTokenizer implements ListIterator<String>, Cloneable {
      * Creates a new instance of this Tokenizer. The new instance is reset so
      * that it will be at the start of the token list.
      * If a {@link CloneNotSupportedException} is caught, return <code>null</code>.
-     * 
+     *
      * @return a new instance of this Tokenizer which has been reset.
      */
     @Override
@@ -1087,7 +1097,7 @@ public class StrTokenizer implements ListIterator<String>, Cloneable {
     /**
      * Creates a new instance of this Tokenizer. The new instance is reset so that
      * it will be at the start of the token list.
-     * 
+     *
      * @return a new instance of this Tokenizer which has been reset.
      * @throws CloneNotSupportedException if there is a problem cloning
      */

http://git-wip-us.apache.org/repos/asf/commons-text/blob/df0658f0/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java b/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
index 010ab2a..788f8c5 100644
--- a/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,17 +22,20 @@ import java.util.ArrayList;
 import java.util.List;
 
 /**
- * Executes a sequence of translators one after the other. Execution ends whenever 
+ * Executes a sequence of translators one after the other. Execution ends whenever
  * the first translator consumes codepoints from the input.
  *
  * @since 1.0
  */
 public class AggregateTranslator extends CharSequenceTranslator {
 
+    /**
+     * Translator list.
+     */
     private final List<CharSequenceTranslator> translators = new ArrayList<>();
 
     /**
-     * Specify the translators to be used at creation time. 
+     * Specify the translators to be used at creation time.
      *
      * @param translators CharSequenceTranslator array to aggregate
      */
@@ -47,15 +50,15 @@ public class AggregateTranslator extends CharSequenceTranslator {
     }
 
     /**
-     * The first translator to consume codepoints from the input is the 'winner'. 
-     * Execution stops with the number of consumed codepoints being returned. 
+     * The first translator to consume codepoints from the input is the 'winner'.
+     * Execution stops with the number of consumed codepoints being returned.
      * {@inheritDoc}
      */
     @Override
     public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
         for (final CharSequenceTranslator translator : translators) {
             final int consumed = translator.translate(input, index, out);
-            if(consumed != 0) {
+            if (consumed != 0) {
                 return consumed;
             }
         }

http://git-wip-us.apache.org/repos/asf/commons-text/blob/df0658f0/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java b/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
index baec844..4a27472 100644
--- a/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,21 +22,27 @@ import java.io.Writer;
 import java.util.Locale;
 
 /**
- * An API for translating text. 
- * Its core use is to escape and unescape text. Because escaping and unescaping 
+ * An API for translating text.
+ * Its core use is to escape and unescape text. Because escaping and unescaping
  * is completely contextual, the API does not present two separate signatures.
  *
  * @since 1.0
  */
 public abstract class CharSequenceTranslator {
 
-    static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+    /**
+     * Array containing the hexadecimal alphabet.
+     */
+    static final char[] HEX_DIGITS = new char[] {'0', '1', '2', '3',
+                                                 '4', '5', '6', '7',
+                                                 '8', '9', 'A', 'B',
+                                                 'C', 'D', 'E', 'F'};
 
     /**
-     * Translate a set of codepoints, represented by an int index into a CharSequence, 
-     * into another set of codepoints. The number of codepoints consumed must be returned, 
-     * and the only IOExceptions thrown must be from interacting with the Writer so that 
-     * the top level API may reliably ignore StringWriter IOExceptions. 
+     * Translate a set of codepoints, represented by an int index into a CharSequence,
+     * into another set of codepoints. The number of codepoints consumed must be returned,
+     * and the only IOExceptions thrown must be from interacting with the Writer so that
+     * the top level API may reliably ignore StringWriter IOExceptions.
      *
      * @param input CharSequence that is being translated
      * @param index int representing the current point of translation
@@ -47,7 +53,7 @@ public abstract class CharSequenceTranslator {
     public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
 
     /**
-     * Helper for non-Writer usage. 
+     * Helper for non-Writer usage.
      * @param input CharSequence to be translated
      * @return String output of translation
      */
@@ -66,8 +72,8 @@ public abstract class CharSequenceTranslator {
     }
 
     /**
-     * Translate an input onto a Writer. This is intentionally final as its algorithm is 
-     * tightly coupled with the abstract method of this class. 
+     * Translate an input onto a Writer. This is intentionally final as its algorithm is
+     * tightly coupled with the abstract method of this class.
      *
      * @param input CharSequence that is being translated
      * @param out Writer to translate the text to
@@ -108,7 +114,7 @@ public abstract class CharSequenceTranslator {
     }
 
     /**
-     * Helper method to create a merger of this translator with another set of 
+     * Helper method to create a merger of this translator with another set of
      * translators. Useful in customizing the standard functionality.
      *
      * @param translators CharSequenceTranslator array of translators to merge with this one


[41/50] [abbrv] [text] TEXT-40 - Escape HTML characters only once

Posted by ch...@apache.org.
TEXT-40 - Escape HTML characters only once

revert as per the issue comments

Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/e9273cd4
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/e9273cd4
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/e9273cd4

Branch: refs/heads/release
Commit: e9273cd4bb3da622ed761c998a6fb6e731538e18
Parents: 40061c7
Author: Sebb <se...@apache.org>
Authored: Wed Feb 22 16:14:46 2017 +0000
Committer: Sebb <se...@apache.org>
Committed: Wed Feb 22 16:14:46 2017 +0000

----------------------------------------------------------------------
 src/changes/changes.xml                         |   9 +-
 .../apache/commons/text/StringEscapeUtils.java  |  93 +----------
 .../text/translate/SingleLookupTranslator.java  | 153 -------------------
 .../commons/text/StringEscapeUtilsTest.java     |  50 ------
 4 files changed, 9 insertions(+), 296 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/e9273cd4/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 94db412..155d6f8 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -45,7 +45,14 @@ The <action> type attribute can be add,update,fix,remove.
   </properties>
   <body>
 
-  <release version="TBA" date="TBA" description="TBA">
+  <release version="TBA" date="TBA" description="
+  
+   Incompatible changes
+   ====================
+   Methods StringEscapeUtils#escapeHtml3Once and StringEscapeUtils#escapeHtml4Once
+   have been removed; see TEXT-40
+  ">
+    <action issue="TEXT-40" type="remove" dev="sebb">Escape HTML characters only once: revert</action>
     <action issue="TEXT-65" type="fix" dev="chtompki">Fixing the 200 checkstyle errors present in 1.0-beta-1</action>
     <action issue="TEXT-63" type="fix" dev="sebb">Mutable fields should be private</action>
   </release>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/e9273cd4/src/main/java/org/apache/commons/text/StringEscapeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StringEscapeUtils.java b/src/main/java/org/apache/commons/text/StringEscapeUtils.java
index f98f116..05d2348 100644
--- a/src/main/java/org/apache/commons/text/StringEscapeUtils.java
+++ b/src/main/java/org/apache/commons/text/StringEscapeUtils.java
@@ -26,7 +26,6 @@ import org.apache.commons.text.translate.LookupTranslator;
 import org.apache.commons.text.translate.NumericEntityEscaper;
 import org.apache.commons.text.translate.NumericEntityUnescaper;
 import org.apache.commons.text.translate.OctalUnescaper;
-import org.apache.commons.text.translate.SingleLookupTranslator;
 import org.apache.commons.text.translate.UnicodeUnescaper;
 import org.apache.commons.text.translate.UnicodeUnpairedSurrogateRemover;
 
@@ -205,25 +204,6 @@ public class StringEscapeUtils {
             );
 
     /**
-     * The improved translator object for escaping HTML version 3.0.
-     * The 'improved' part of this translator is that it checks if the html is already translated.
-     * This check prevents double, triple, or recursive translations.
-     *
-     * While {@link #escapeHtml3Once(String)} is the expected method of use, this
-     * object allows the HTML escaping functionality to be used
-     * as the foundation for a custom translator.
-     *
-     * Note that, multiple lookup tables should be passed to this translator
-     * instead of passing multiple instances of this translator to the
-     * AggregateTranslator. Because, a SingleLookupTranslator only checks the values of the
-     * lookup table passed to that instance while deciding whether a value is
-     * already translated or not.
-     */
-    public static final CharSequenceTranslator ESCAPE_HTML3_ONCE =
-            new SingleLookupTranslator(EntityArrays.BASIC_ESCAPE, EntityArrays.ISO8859_1_ESCAPE);
-
-
-    /**
      * Translator object for escaping HTML version 4.0.
      *
      * While {@link #escapeHtml4(String)} is the expected method of use, this
@@ -238,28 +218,6 @@ public class StringEscapeUtils {
             );
 
     /**
-     * The improved translator object for escaping HTML version 4.0.
-     * The 'improved' part of this translator is that it checks if the html is already translated.
-     * This check prevents double, triple, or recursive translations.
-     *
-     * While {@link #escapeHtml4Once(String)} is the expected method of use, this
-     * object allows the HTML escaping functionality to be used
-     * as the foundation for a custom translator.
-     *
-     * Note that, multiple lookup tables should be passed to this translator
-     * instead of passing multiple instances of this translator to the
-     * AggregateTranslator. Because, a SingleLookupTranslator only checks the values of the
-     * lookup table passed to that instance while deciding whether a value is
-     * already translated or not.
-     */
-    public static final CharSequenceTranslator ESCAPE_HTML4_ONCE =
-            new SingleLookupTranslator(
-                    EntityArrays.BASIC_ESCAPE,
-                    EntityArrays.ISO8859_1_ESCAPE,
-                    EntityArrays.HTML40_EXTENDED_ESCAPE
-            );
-
-    /**
      * Translator object for escaping individual Comma Separated Values.
      *
      * While {@link #escapeCsv(String)} is the expected method of use, this
@@ -702,43 +660,6 @@ public class StringEscapeUtils {
     }
 
     /**
-     * <p>Escapes the characters in a {@code String} using HTML entities.
-     * But escapes them only once. i.e. does not escape already escaped characters.</p>
-     *
-     * <p>
-     * For example:
-     * </p>
-     * <p><code>"bread" &amp; "butter"</code></p>
-     * becomes:
-     * <p>
-     * <code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code>.
-     * </p>
-     *
-     * <p>
-     * But:
-     * </p>
-     * <p><code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code></p>
-     * remains unaffected.
-     *
-     * <p>Supports all known HTML 4.0 entities, including funky accents.
-     * Note that the commonly used apostrophe escape character (&amp;apos;)
-     * is not a legal entity and so is not supported). </p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     *
-     * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
-     * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
-     * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
-     * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
-     * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
-     */
-    public static final String escapeHtml4Once(final String input) {
-        return ESCAPE_HTML4_ONCE.translate(input);
-    }
-
-
-    /**
      * <p>Escapes the characters in a {@code String} using HTML entities.</p>
      * <p>Supports only the HTML 3.0 entities. </p>
      *
@@ -749,18 +670,6 @@ public class StringEscapeUtils {
         return ESCAPE_HTML3.translate(input);
     }
 
-    /**
-     * <p>Escapes the characters in a {@code String} using HTML entities.
-     * But escapes them only once. i.e. does not escape already escaped characters.</p>
-     * <p>Supports only the HTML 3.0 entities. </p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     */
-    public static final String escapeHtml3Once(final String input) {
-        return ESCAPE_HTML3_ONCE.translate(input);
-    }
-
     //-----------------------------------------------------------------------
     /**
      * <p>Unescapes a string containing entity escapes to a string
@@ -768,7 +677,7 @@ public class StringEscapeUtils {
      * escapes. Supports HTML 4.0 entities.</p>
      *
      * <p>For example, the string {@code "&lt;Fran&ccedil;ais&gt;"}
-     * will become {@code "<Fran\ufffdais>"}</p>
+     * will become {@code "<Fran\ufffdais>"}</p>
      *
      * <p>If an entity is unrecognized, it is left alone, and inserted
      * verbatim into the result string. e.g. {@code "&gt;&zzzz;x"} will

http://git-wip-us.apache.org/repos/asf/commons-text/blob/e9273cd4/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java b/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
deleted file mode 100644
index 8fafab8..0000000
--- a/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Translates a value using a lookup table.
- * But doesn't translate if that value is already translated.
- *
- * @since 1.0
- */
-public class SingleLookupTranslator extends CharSequenceTranslator {
-
-    /** The lookupMap to be used for translation. */
-    private final Map<String, String> lookupMap;
-    /** The first character of each key in the lookupMap. */
-    private final HashSet<Character> prefixSet;
-    /** The length of the shortest key in the lookupMap. */
-    private final int shortest;
-    /** The length of the longest key in the lookupMap. */
-    private final int longest;
-    /** The length of the shortest value in the lookupMap. */
-    private final int shortestValue;
-    /** The length of the longest value in the lookupMap. */
-    private final int longestValue;
-
-    /**
-     * Define the look tables to be used in translation.
-     * <p>
-     * Note that, as of Lang 3.1, the key to the lookup table is converted to a
-     * java.lang.String. This is because we need the key to support hashCode and
-     * equals(Object), allowing it to be the key for a HashMap. See LANG-882.
-     * <p>
-     * Also note that, multiple lookup tables should be passed to this translator
-     * instead of passing multiple instances of this translator to the
-     * AggregateTranslator. Because, this translator only checks the values of the
-     * lookup table passed to this instance while deciding whether a value is
-     * already translated or not.
-     *
-     * @param inputMaps an array of Map&lt;CharSequence, CharSequence&gt;.
-     */
-    public SingleLookupTranslator(Map<CharSequence, CharSequence>... inputMaps) {
-        Map<CharSequence, CharSequence> lookup = new HashMap<>();
-        for (Map<CharSequence, CharSequence> input : inputMaps) {
-            Iterator<Map.Entry<CharSequence, CharSequence>> it = input.entrySet().iterator();
-            while (it.hasNext()) {
-                Map.Entry<CharSequence, CharSequence> pair = it.next();
-                lookup.put(pair.getKey(), pair.getValue());
-            }
-        }
-        lookupMap = new HashMap<String, String>();
-        prefixSet = new HashSet<Character>();
-        int _shortest = Integer.MAX_VALUE;
-        int _longest = 0;
-        int _shortestValue = Integer.MAX_VALUE;
-        int _longestValue = 0;
-        if (lookup != null) {
-            Iterator<Map.Entry<CharSequence, CharSequence>> it = lookup.entrySet().iterator();
-            while (it.hasNext()) {
-                Map.Entry<CharSequence, CharSequence> pair = it.next();
-                this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
-                this.prefixSet.add(pair.getKey().charAt(0));
-                final int sz = pair.getKey().length();
-                if (sz < _shortest) {
-                    _shortest = sz;
-                }
-                if (sz > _longest) {
-                    _longest = sz;
-                }
-                final int sizeOfValue = lookup.get(pair.getKey()).length();
-                if (sizeOfValue < _shortestValue) {
-                    _shortestValue = sizeOfValue;
-                }
-                if (sizeOfValue > _longestValue) {
-                    _longestValue = sizeOfValue;
-                }
-            }
-        }
-        shortest = _shortest;
-        longest = _longest;
-        shortestValue = _shortestValue;
-        longestValue = _longestValue;
-    }
-
-    /**
-     * Translate a set of codepoints, represented by an int index into a CharSequence,
-     * into another set of codepoints. The number of codepoints consumed must be returned,
-     * and the only IOExceptions thrown must be from interacting with the Writer so that
-     * the top level API may reliably ignore StringWriter IOExceptions.
-     *
-     * @param input CharSequence that is being translated
-     * @param index int representing the current point of translation
-     * @param out   Writer to translate the text to
-     * @return int count of codepoints consumed
-     * @throws IOException if and only if the Writer produces an IOException
-     */
-    @Override
-    public int translate(CharSequence input, int index, Writer out) throws IOException {
-        // check if already translated
-        int maxValue = longestValue;
-        if (index + maxValue > input.length()) {
-            maxValue = input.length() - index;
-        }
-        // implement greedy algorithm to check all the possible 'value' matches
-        // for which we need to skip translation.
-        for (int i = maxValue; i >= shortestValue; i--) {
-            final CharSequence subSeq = input.subSequence(index, index + i);
-            // If the sub-string is already translated, return without translating.
-            if (lookupMap.containsValue(subSeq.toString())) {
-                return 0;
-            }
-        }
-
-        // check if translation exists for the input at position index
-        if (prefixSet.contains(input.charAt(index))) {
-            int max = longest;
-            if (index + longest > input.length()) {
-                max = input.length() - index;
-            }
-            // implement greedy algorithm by trying maximum match first
-            for (int i = max; i >= shortest; i--) {
-                final CharSequence subSeq = input.subSequence(index, index + i);
-                final String result = lookupMap.get(subSeq.toString());
-
-                if (result != null) {
-                    out.write(result);
-                    return i;
-                }
-            }
-        }
-        return 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/e9273cd4/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
index f716763..ef9d8ab 100644
--- a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
@@ -241,56 +241,6 @@ public class StringEscapeUtilsTest {
     }
 
     @Test
-    public void testEscapeHtml4Once() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml4Once(original));
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml4Once(expected));
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML4_ONCE.translate(original, sw);
-            } catch (final IOException e) {
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(message, expected, actual);
-            final StringWriter sw2 = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML4_ONCE.translate(expected, sw2);
-            } catch (final IOException e) {
-            }
-            final String actual2 = original == null ? null : sw2.toString();
-            assertEquals(message, expected, actual2);
-        }
-    }
-
-    @Test
-    public void testEscapeHtml3Once() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml3Once(original));
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml3Once(expected));
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML3_ONCE.translate(original, sw);
-            } catch (final IOException e) {
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(message, expected, actual);
-            final StringWriter sw2 = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML3_ONCE.translate(expected, sw2);
-            } catch (final IOException e) {
-            }
-            final String actual2 = original == null ? null : sw2.toString();
-            assertEquals(message, expected, actual2);
-        }
-    }
-
-    @Test
     public void testUnescapeHtml4() {
         for (final String[] element : HTML_ESCAPES) {
             final String message = element[0];


[42/50] [abbrv] [text] HTML3 tests

Posted by ch...@apache.org.
HTML3 tests

Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/a0077dd3
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/a0077dd3
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/a0077dd3

Branch: refs/heads/release
Commit: a0077dd37dc112a83cb24eccab702202c2bc8a13
Parents: e9273cd
Author: Sebb <se...@apache.org>
Authored: Wed Feb 22 16:33:37 2017 +0000
Committer: Sebb <se...@apache.org>
Committed: Wed Feb 22 16:33:37 2017 +0000

----------------------------------------------------------------------
 .../commons/text/StringEscapeUtilsTest.java     | 46 +++++++++++++++++++-
 1 file changed, 45 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/a0077dd3/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
index ef9d8ab..4de4fea 100644
--- a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
@@ -224,7 +224,51 @@ public class StringEscapeUtilsTest {
     };
 
     @Test
-    public void testEscapeHtml() {
+    public void testEscapeHtml3() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[1];
+            final String original = element[2];
+            assertEquals(message, expected, StringEscapeUtils.escapeHtml4(original));
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML3.translate(original, sw);
+            } catch (final IOException e) {
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(message, expected, actual);
+        }
+    }
+
+    @Test
+    public void testUnescapeHtml3() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[2];
+            final String original = element[1];
+            assertEquals(message, expected, StringEscapeUtils.unescapeHtml3(original));
+
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.UNESCAPE_HTML3.translate(original, sw);
+            } catch (final IOException e) {
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(message, expected, actual);
+        }
+        // \u00E7 is a cedilla (c with wiggle under)
+        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
+        // on some locales        
+        assertEquals("funny chars pass through OK", "Fran\u00E7ais", StringEscapeUtils.unescapeHtml3("Fran\u00E7ais"));
+
+        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml3("Hello&;World"));
+        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml3("Hello&#;World"));
+        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml3("Hello&# ;World"));
+        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml3("Hello&##;World"));
+    }
+
+@Test
+    public void testEscapeHtml4() {
         for (final String[] element : HTML_ESCAPES) {
             final String message = element[0];
             final String expected = element[1];


[46/50] [abbrv] [text] TEXT-69: changes.xml note

Posted by ch...@apache.org.
TEXT-69: changes.xml note


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/1911d427
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/1911d427
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/1911d427

Branch: refs/heads/release
Commit: 1911d427952c079d86a6daebf5ffeaf74cd0ba9f
Parents: 4bc5159
Author: Rob Tompkins <ch...@apache.org>
Authored: Thu Feb 23 15:17:27 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Thu Feb 23 15:17:27 2017 -0500

----------------------------------------------------------------------
 src/changes/changes.xml | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/1911d427/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 155d6f8..6b943bd 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -52,6 +52,7 @@ The <action> type attribute can be add,update,fix,remove.
    Methods StringEscapeUtils#escapeHtml3Once and StringEscapeUtils#escapeHtml4Once
    have been removed; see TEXT-40
   ">
+    <action issue="TEXT-69" type="fix" dev="chtompki">Resolve PMD/CMD Violations</action>
     <action issue="TEXT-40" type="remove" dev="sebb">Escape HTML characters only once: revert</action>
     <action issue="TEXT-65" type="fix" dev="chtompki">Fixing the 200 checkstyle errors present in 1.0-beta-1</action>
     <action issue="TEXT-63" type="fix" dev="sebb">Mutable fields should be private</action>


[02/50] [abbrv] [text] TEXT-63 Mutable fields should be private

Posted by ch...@apache.org.
TEXT-63 Mutable fields should be private

Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/5066ac6f
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/5066ac6f
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/5066ac6f

Branch: refs/heads/release
Commit: 5066ac6f1ce5dfd729e8269d10680f23103e404a
Parents: 7a96b50
Author: Sebb <se...@apache.org>
Authored: Wed Feb 8 10:40:43 2017 +0000
Committer: Sebb <se...@apache.org>
Committed: Wed Feb 8 10:40:43 2017 +0000

----------------------------------------------------------------------
 src/changes/changes.xml                                    | 4 ++++
 src/main/java/org/apache/commons/text/beta/StrBuilder.java | 4 ++--
 2 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/5066ac6f/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 88e9c52..6a567ec 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -45,6 +45,10 @@ The <action> type attribute can be add,update,fix,remove.
   </properties>
   <body>
 
+  <release version="TBA" date="TBA" description="TBA">
+  <action issue="TEXT-63" type="fix" dev="sebb">Mutable fields should be private</action>
+  </release>
+
   <release version="1.0-beta-1" date="2017-01-30" description="First release (beta) of Commons Text">
     <action issue="TEXT-62" type="fix" dev="chtompki">Incorporate suggestions from RC2 into 1.0 release</action>
     <action issue="TEXT-61" type="update" dev="chtompki" due-to="Lee Adcock">Naming packages org.apache.commons.text.beta</action>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/5066ac6f/src/main/java/org/apache/commons/text/beta/StrBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StrBuilder.java b/src/main/java/org/apache/commons/text/beta/StrBuilder.java
index 260055a..5043fd6 100644
--- a/src/main/java/org/apache/commons/text/beta/StrBuilder.java
+++ b/src/main/java/org/apache/commons/text/beta/StrBuilder.java
@@ -82,9 +82,9 @@ public class StrBuilder implements CharSequence, Appendable, Serializable, Build
     private static final long serialVersionUID = 7628716375283629643L;
 
     /** Internal data storage. */
-    protected char[] buffer; // TODO make private?
+    char[] buffer; // package-protected for test code use only
     /** Current size of the buffer. */
-    protected int size; // TODO make private?
+    private int size;
     /** The new line. */
     private String newLine;
     /** The null text. */


[50/50] [abbrv] [text] TEXT-64 add changelog entry

Posted by ch...@apache.org.
TEXT-64 add changelog entry


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/2d522713
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/2d522713
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/2d522713

Branch: refs/heads/release
Commit: 2d522713c477246a9243593e3010169edba22741
Parents: 61a0be4
Author: Bruno P. Kinoshita <br...@yahoo.com.br>
Authored: Thu Mar 2 14:49:50 2017 +1300
Committer: Bruno P. Kinoshita <br...@yahoo.com.br>
Committed: Thu Mar 2 14:49:50 2017 +1300

----------------------------------------------------------------------
 src/changes/changes.xml | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/2d522713/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6b943bd..42ff818 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -52,6 +52,7 @@ The <action> type attribute can be add,update,fix,remove.
    Methods StringEscapeUtils#escapeHtml3Once and StringEscapeUtils#escapeHtml4Once
    have been removed; see TEXT-40
   ">
+    <action issue="TEXT-64" type="fix" dev="kinow" due-to="chtompki">Investigate locale issue in ExtendedMessageFormatTest</action>
     <action issue="TEXT-69" type="fix" dev="chtompki">Resolve PMD/CMD Violations</action>
     <action issue="TEXT-40" type="remove" dev="sebb">Escape HTML characters only once: revert</action>
     <action issue="TEXT-65" type="fix" dev="chtompki">Fixing the 200 checkstyle errors present in 1.0-beta-1</action>


[48/50] [abbrv] [text] Use Category.FORMAT for Locale.getDefault() to fix test failures when locale not set to en

Posted by ch...@apache.org.
Use Category.FORMAT for Locale.getDefault() to fix test failures when locale not set to en


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/3a641403
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/3a641403
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/3a641403

Branch: refs/heads/release
Commit: 3a641403fc496591f60c68d68cc28784a617e2c9
Parents: dc10b4c
Author: Bruno P. Kinoshita <br...@yahoo.com.br>
Authored: Wed Mar 1 10:32:27 2017 +1300
Committer: Bruno P. Kinoshita <br...@yahoo.com.br>
Committed: Wed Mar 1 10:32:27 2017 +1300

----------------------------------------------------------------------
 .../java/org/apache/commons/text/ExtendedMessageFormat.java     | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/3a641403/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java b/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
index 2a08bbf..372ae34 100644
--- a/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
+++ b/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.Locale.Category;
 import java.util.Map;
 import java.util.Objects;
 
@@ -117,7 +118,7 @@ public class ExtendedMessageFormat extends MessageFormat {
      * @throws IllegalArgumentException in case of a bad pattern.
      */
     public ExtendedMessageFormat(final String pattern) {
-        this(pattern, Locale.getDefault());
+        this(pattern, Locale.getDefault(Category.FORMAT));
     }
 
     /**
@@ -140,7 +141,7 @@ public class ExtendedMessageFormat extends MessageFormat {
      */
     public ExtendedMessageFormat(final String pattern,
                                  final Map<String, ? extends FormatFactory> registry) {
-        this(pattern, Locale.getDefault(), registry);
+        this(pattern, Locale.getDefault(Category.FORMAT), registry);
     }
 
     /**


[36/50] [abbrv] [text] TEXT-65: created TEXT-66 removing TODO

Posted by ch...@apache.org.
TEXT-65: created TEXT-66 removing TODO


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/b2b4c21e
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/b2b4c21e
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/b2b4c21e

Branch: refs/heads/release
Commit: b2b4c21ede2d80272dc73ea1d53c3c12463a9d5d
Parents: 0900a4c
Author: Rob Tompkins <ch...@apache.org>
Authored: Fri Feb 17 08:24:26 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Fri Feb 17 08:24:26 2017 -0500

----------------------------------------------------------------------
 src/main/java/org/apache/commons/text/StringEscapeUtils.java | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/b2b4c21e/src/main/java/org/apache/commons/text/StringEscapeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StringEscapeUtils.java b/src/main/java/org/apache/commons/text/StringEscapeUtils.java
index aa6b071..f98f116 100644
--- a/src/main/java/org/apache/commons/text/StringEscapeUtils.java
+++ b/src/main/java/org/apache/commons/text/StringEscapeUtils.java
@@ -313,7 +313,6 @@ public class StringEscapeUtils {
      * object allows the Java unescaping functionality to be used
      * as the foundation for a custom translator.
      */
-    // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the Java (as per the compiler)?
     public static final CharSequenceTranslator UNESCAPE_JAVA;
     static {
         Map<CharSequence, CharSequence> unescapeJavaMap = new HashMap<>();


[18/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/EditScript.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/EditScript.java b/src/main/java/org/apache/commons/text/diff/EditScript.java
new file mode 100644
index 0000000..bf4b185
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/EditScript.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class gathers all the {@link EditCommand commands} needed to transform
+ * one objects sequence into another objects sequence.
+ * <p>
+ * An edit script is the most general view of the differences between two
+ * sequences. It is built as the result of the comparison between two sequences
+ * by the {@link StringsComparator StringsComparator} class. The user can
+ * walk through it using the <em>visitor</em> design pattern.
+ * <p>
+ * It is guaranteed that the objects embedded in the {@link InsertCommand insert
+ * commands} come from the second sequence and that the objects embedded in
+ * either the {@link DeleteCommand delete commands} or {@link KeepCommand keep
+ * commands} come from the first sequence. This can be important if subclassing
+ * is used for some elements in the first sequence and the <code>equals</code>
+ * method is specialized.
+ *
+ * @see StringsComparator
+ * @see EditCommand
+ * @see CommandVisitor
+ * @see ReplacementsHandler
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public class EditScript<T> {
+
+    /** Container for the commands. */
+    private final List<EditCommand<T>> commands;
+
+    /** Length of the longest common subsequence. */
+    private int lcsLength;
+
+    /** Number of modifications. */
+    private int modifications;
+
+    /**
+     * Simple constructor. Creates a new empty script.
+     */
+    public EditScript() {
+        commands = new ArrayList<>();
+        lcsLength = 0;
+        modifications = 0;
+    }
+
+    /**
+     * Add a keep command to the script.
+     *
+     * @param command  command to add
+     */
+    public void append(final KeepCommand<T> command) {
+        commands.add(command);
+        ++lcsLength;
+    }
+
+    /**
+     * Add an insert command to the script.
+     *
+     * @param command  command to add
+     */
+    public void append(final InsertCommand<T> command) {
+        commands.add(command);
+        ++modifications;
+    }
+
+    /**
+     * Add a delete command to the script.
+     *
+     * @param command  command to add
+     */
+    public void append(final DeleteCommand<T> command) {
+        commands.add(command);
+        ++modifications;
+    }
+
+    /**
+     * Visit the script. The script implements the <em>visitor</em> design
+     * pattern, this method is the entry point to which the user supplies its
+     * own visitor, the script will be responsible to drive it through the
+     * commands in order and call the appropriate method as each command is
+     * encountered.
+     *
+     * @param visitor  the visitor that will visit all commands in turn
+     */
+    public void visit(final CommandVisitor<T> visitor) {
+        for (final EditCommand<T> command : commands) {
+            command.accept(visitor);
+        }
+    }
+
+    /**
+     * Get the length of the Longest Common Subsequence (LCS). The length of the
+     * longest common subsequence is the number of {@link KeepCommand keep
+     * commands} in the script.
+     *
+     * @return length of the Longest Common Subsequence
+     */
+    public int getLCSLength() {
+        return lcsLength;
+    }
+
+    /**
+     * Get the number of effective modifications. The number of effective
+     * modification is the number of {@link DeleteCommand delete} and
+     * {@link InsertCommand insert} commands in the script.
+     *
+     * @return number of effective modifications
+     */
+    public int getModifications() {
+        return modifications;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/InsertCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/InsertCommand.java b/src/main/java/org/apache/commons/text/diff/InsertCommand.java
new file mode 100644
index 0000000..f0337dc
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/InsertCommand.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+/**
+ * Command representing the insertion of one object of the second sequence.
+ * <p>
+ * When one object of the second sequence has no corresponding object in the
+ * first sequence at the right place, the {@link EditScript edit script}
+ * transforming the first sequence into the second sequence uses an instance of
+ * this class to represent the insertion of this object. The objects embedded in
+ * these type of commands always come from the second sequence.
+ * </p>
+ *
+ * @see StringsComparator
+ * @see EditScript
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public class InsertCommand<T> extends EditCommand<T> {
+
+    /**
+     * Simple constructor. Creates a new instance of InsertCommand
+     *
+     * @param object  the object of the second sequence that should be inserted
+     */
+    public InsertCommand(final T object) {
+        super(object);
+    }
+
+    /**
+     * Accept a visitor. When an <code>InsertCommand</code> accepts a visitor,
+     * it calls its {@link CommandVisitor#visitInsertCommand visitInsertCommand}
+     * method.
+     *
+     * @param visitor  the visitor to be accepted
+     */
+    @Override
+    public void accept(final CommandVisitor<T> visitor) {
+        visitor.visitInsertCommand(getObject());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/KeepCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/KeepCommand.java b/src/main/java/org/apache/commons/text/diff/KeepCommand.java
new file mode 100644
index 0000000..34c6fe7
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/KeepCommand.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+/**
+ * Command representing the keeping of one object present in both sequences.
+ * <p>
+ * When one object of the first sequence <code>equals</code> another objects in
+ * the second sequence at the right place, the {@link EditScript edit script}
+ * transforming the first sequence into the second sequence uses an instance of
+ * this class to represent the keeping of this object. The objects embedded in
+ * these type of commands always come from the first sequence.
+ * </p>
+ *
+ * @see StringsComparator
+ * @see EditScript
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public class KeepCommand<T> extends EditCommand<T> {
+
+    /**
+     * Simple constructor. Creates a new instance of KeepCommand
+     *
+     * @param object  the object belonging to both sequences (the object is a
+     *   reference to the instance in the first sequence which is known
+     *   to be equal to an instance in the second sequence)
+     */
+    public KeepCommand(final T object) {
+        super(object);
+    }
+
+    /**
+     * Accept a visitor. When a <code>KeepCommand</code> accepts a visitor, it
+     * calls its {@link CommandVisitor#visitKeepCommand visitKeepCommand} method.
+     *
+     * @param visitor  the visitor to be accepted
+     */
+    @Override
+    public void accept(final CommandVisitor<T> visitor) {
+        visitor.visitKeepCommand(getObject());
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/ReplacementsFinder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/ReplacementsFinder.java b/src/main/java/org/apache/commons/text/diff/ReplacementsFinder.java
new file mode 100644
index 0000000..46f1b88
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/ReplacementsFinder.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class handles sequences of replacements resulting from a comparison.
+ * <p>
+ * The comparison of two objects sequences leads to the identification of common
+ * parts and parts which only belong to the first or to the second sequence. The
+ * common parts appear in the edit script in the form of <em>keep</em> commands,
+ * they can be considered as synchronization objects between the two sequences.
+ * These synchronization objects split the two sequences in synchronized
+ * sub-sequences. The first sequence can be transformed into the second one by
+ * replacing each synchronized sub-sequence of the first sequence by the
+ * corresponding sub-sequence of the second sequence. This is a synthetic way to
+ * see an {@link EditScript edit script}, replacing individual
+ * {@link DeleteCommand delete}, {@link KeepCommand keep} and
+ * {@link InsertCommand insert} commands by fewer replacements acting on
+ * complete sub-sequences.
+ * </p>
+ * <p>
+ * This class is devoted to perform this interpretation. It visits an
+ * {@link EditScript edit script} (because it implements the
+ * {@link CommandVisitor CommandVisitor} interface) and calls a user-supplied
+ * handler implementing the {@link ReplacementsHandler ReplacementsHandler}
+ * interface to process the sub-sequences.
+ * </p>
+ *
+ * @see ReplacementsHandler
+ * @see EditScript
+ * @see StringsComparator
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public class ReplacementsFinder<T> implements CommandVisitor<T> {
+
+    /**
+     * List of pending insertions.
+     */
+    private final List<T> pendingInsertions;
+    /**
+     * List of pending deletions.
+     */
+    private final List<T> pendingDeletions;
+    /**
+     * Count of elements skipped.
+     */
+    private int skipped;
+
+    /** Handler to call when synchronized sequences are found. */
+    private final ReplacementsHandler<T> handler;
+
+    /**
+     * Simple constructor. Creates a new instance of {@link ReplacementsFinder}.
+     *
+     * @param handler  handler to call when synchronized sequences are found
+     */
+    public ReplacementsFinder(final ReplacementsHandler<T> handler) {
+        pendingInsertions = new ArrayList<>();
+        pendingDeletions  = new ArrayList<>();
+        skipped           = 0;
+        this.handler      = handler;
+    }
+
+    /**
+     * Add an object to the pending insertions set.
+     *
+     * @param object  object to insert
+     */
+    @Override
+    public void visitInsertCommand(final T object) {
+        pendingInsertions.add(object);
+    }
+
+    /**
+     * Handle a synchronization object.
+     * <p>
+     * When a synchronization object is identified, the pending insertions and
+     * pending deletions sets are provided to the user handler as subsequences.
+     * </p>
+     *
+     * @param object  synchronization object detected
+     */
+    @Override
+    public void visitKeepCommand(final T object) {
+        if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) {
+            ++skipped;
+        } else {
+            handler.handleReplacement(skipped, pendingDeletions, pendingInsertions);
+            pendingDeletions.clear();
+            pendingInsertions.clear();
+            skipped = 1;
+        }
+    }
+
+    /**
+     * Add an object to the pending deletions set.
+     *
+     * @param object  object to delete
+     */
+    @Override
+    public void visitDeleteCommand(final T object) {
+        pendingDeletions.add(object);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/ReplacementsHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/ReplacementsHandler.java b/src/main/java/org/apache/commons/text/diff/ReplacementsHandler.java
new file mode 100644
index 0000000..3beb716
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/ReplacementsHandler.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+import java.util.List;
+
+/**
+ * This interface is devoted to handle synchronized replacement sequences.
+ *
+ * @param <T> object type
+ * @see ReplacementsFinder
+ * @since 1.0
+ */
+public interface ReplacementsHandler<T> {
+
+    /**
+     * Handle two synchronized sequences.
+     * <p>
+     * This method is called by a {@link ReplacementsFinder ReplacementsFinder}
+     * instance when it has synchronized two sub-sequences of object arrays
+     * being compared, and at least one of the sequences is non-empty. Since the
+     * sequences are synchronized, the objects before the two sub-sequences are
+     * equals (if they exist). This property also holds for the objects after
+     * the two sub-sequences.
+     * <p>
+     * The replacement is defined as replacing the <code>from</code>
+     * sub-sequence into the <code>to</code> sub-sequence.
+     *
+     * @param skipped  number of tokens skipped since the last call (i.e. number of
+     *   tokens that were in both sequences), this number should be strictly positive
+     *   except on the very first call where it can be zero (if the first object of
+     *   the two sequences are different)
+     * @param from  sub-sequence of objects coming from the first sequence
+     * @param to  sub-sequence of objects coming from the second sequence
+     */
+    void handleReplacement(int skipped, List<T> from, List<T> to);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/StringsComparator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/StringsComparator.java b/src/main/java/org/apache/commons/text/diff/StringsComparator.java
new file mode 100644
index 0000000..a286c4a
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/StringsComparator.java
@@ -0,0 +1,331 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+/**
+ * <p>
+ * It is guaranteed that the comparisons will always be done as
+ * <code>o1.equals(o2)</code> where <code>o1</code> belongs to the first
+ * sequence and <code>o2</code> belongs to the second sequence. This can
+ * be important if subclassing is used for some elements in the first
+ * sequence and the <code>equals</code> method is specialized.
+ * </p>
+ * <p>
+ * Comparison can be seen from two points of view: either as giving the smallest
+ * modification allowing to transform the first sequence into the second one, or
+ * as giving the longest sequence which is a subsequence of both initial
+ * sequences. The <code>equals</code> method is used to compare objects, so any
+ * object can be put into sequences. Modifications include deleting, inserting
+ * or keeping one object, starting from the beginning of the first sequence.
+ * </p>
+ * <p>
+ * This class implements the comparison algorithm, which is the very efficient
+ * algorithm from Eugene W. Myers
+ * <a href="http://www.cis.upenn.edu/~bcpierce/courses/dd/papers/diff.ps">
+ * An O(ND) Difference Algorithm and Its Variations</a>. This algorithm produces
+ * the shortest possible {@link EditScript edit script} containing all the
+ * {@link EditCommand commands} needed to transform the first sequence into
+ * the second one.
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Collections 4.0.
+ * </p>
+ *
+ * @see EditScript
+ * @see EditCommand
+ * @see CommandVisitor
+ * @since 1.0
+ */
+public class StringsComparator {
+
+    /**
+     * First character sequence.
+     */
+    private final String left;
+    /**
+     * Second character sequence.
+     */
+    private final String right;
+    /**
+     * Temporary array.
+     */
+    private final int[] vDown;
+    /**
+     * Temporary array.
+     */
+    private final int[] vUp;
+
+    /**
+     * Simple constructor.
+     * <p>
+     * Creates a new instance of StringsComparator.
+     * </p>
+     * <p>
+     * It is <em>guaranteed</em> that the comparisons will always be done as
+     * <code>o1.equals(o2)</code> where <code>o1</code> belongs to the first
+     * sequence and <code>o2</code> belongs to the second sequence. This can be
+     * important if subclassing is used for some elements in the first sequence
+     * and the <code>equals</code> method is specialized.
+     * </p>
+     *
+     * @param left first character sequence to be compared
+     * @param right second character sequence to be compared
+     */
+    public StringsComparator(final String left, final String right) {
+        this.left = left;
+        this.right = right;
+
+        final int size = left.length() + right.length() + 2;
+        vDown = new int[size];
+        vUp   = new int[size];
+    }
+
+    /**
+     * Get the {@link EditScript} object.
+     * <p>
+     * It is guaranteed that the objects embedded in the {@link InsertCommand
+     * insert commands} come from the second sequence and that the objects
+     * embedded in either the {@link DeleteCommand delete commands} or
+     * {@link KeepCommand keep commands} come from the first sequence. This can
+     * be important if subclassing is used for some elements in the first
+     * sequence and the <code>equals</code> method is specialized.
+     * </p>
+     *
+     * @return the edit script resulting from the comparison of the two
+     *         sequences
+     */
+    public EditScript<Character> getScript() {
+        final EditScript<Character> script = new EditScript<>();
+        buildScript(0, left.length(), 0, right.length(), script);
+        return script;
+    }
+
+    /**
+     * Build an edit script.
+     *
+     * @param start1  the begin of the first sequence to be compared
+     * @param end1  the end of the first sequence to be compared
+     * @param start2  the begin of the second sequence to be compared
+     * @param end2  the end of the second sequence to be compared
+     * @param script the edited script
+     */
+    private void buildScript(final int start1, final int end1, final int start2, final int end2,
+            final EditScript<Character> script) {
+        final Snake middle = getMiddleSnake(start1, end1, start2, end2);
+
+        if (middle == null
+                || middle.getStart() == end1 && middle.getDiag() == end1 - end2
+                || middle.getEnd() == start1 && middle.getDiag() == start1 - start2) {
+
+            int i = start1;
+            int j = start2;
+            while (i < end1 || j < end2) {
+                if (i < end1 && j < end2 && left.charAt(i) == right.charAt(j)) {
+                    script.append(new KeepCommand<>(left.charAt(i)));
+                    ++i;
+                    ++j;
+                } else {
+                    if (end1 - start1 > end2 - start2) {
+                        script.append(new DeleteCommand<>(left.charAt(i)));
+                        ++i;
+                    } else {
+                        script.append(new InsertCommand<>(right.charAt(j)));
+                        ++j;
+                    }
+                }
+            }
+
+        } else {
+
+            buildScript(start1, middle.getStart(),
+                        start2, middle.getStart() - middle.getDiag(),
+                        script);
+            for (int i = middle.getStart(); i < middle.getEnd(); ++i) {
+                script.append(new KeepCommand<>(left.charAt(i)));
+            }
+            buildScript(middle.getEnd(), end1,
+                        middle.getEnd() - middle.getDiag(), end2,
+                        script);
+        }
+    }
+
+    /**
+     * Get the middle snake corresponding to two subsequences of the
+     * main sequences.
+     * <p>
+     * The snake is found using the MYERS Algorithm (this algorithms has
+     * also been implemented in the GNU diff program). This algorithm is
+     * explained in Eugene Myers article:
+     * <a href="http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps">
+     * An O(ND) Difference Algorithm and Its Variations</a>.
+     * </p>
+     *
+     * @param start1  the begin of the first sequence to be compared
+     * @param end1  the end of the first sequence to be compared
+     * @param start2  the begin of the second sequence to be compared
+     * @param end2  the end of the second sequence to be compared
+     * @return the middle snake
+     */
+    private Snake getMiddleSnake(final int start1, final int end1, final int start2, final int end2) {
+        // Myers Algorithm
+        // Initialisations
+        final int m = end1 - start1;
+        final int n = end2 - start2;
+        if (m == 0 || n == 0) {
+            return null;
+        }
+
+        final int delta  = m - n;
+        final int sum    = n + m;
+        final int offset = (sum % 2 == 0 ? sum : sum + 1) / 2;
+        vDown[1 + offset] = start1;
+        vUp[1 + offset]   = end1 + 1;
+
+        for (int d = 0; d <= offset; ++d) {
+            // Down
+            for (int k = -d; k <= d; k += 2) {
+                // First step
+
+                final int i = k + offset;
+                if (k == -d || k != d && vDown[i - 1] < vDown[i + 1]) {
+                    vDown[i] = vDown[i + 1];
+                } else {
+                    vDown[i] = vDown[i - 1] + 1;
+                }
+
+                int x = vDown[i];
+                int y = x - start1 + start2 - k;
+
+                while (x < end1 && y < end2 && left.charAt(x) == right.charAt(y)) {
+                    vDown[i] = ++x;
+                    ++y;
+                }
+                // Second step
+                if (delta % 2 != 0 && delta - d <= k && k <= delta + d) {
+                    if (vUp[i - delta] <= vDown[i]) { // NOPMD
+                        return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
+                    }
+                }
+            }
+
+            // Up
+            for (int k = delta - d; k <= delta + d; k += 2) {
+                // First step
+                final int i = k + offset - delta;
+                if (k == delta - d
+                        || k != delta + d && vUp[i + 1] <= vUp[i - 1]) {
+                    vUp[i] = vUp[i + 1] - 1;
+                } else {
+                    vUp[i] = vUp[i - 1];
+                }
+
+                int x = vUp[i] - 1;
+                int y = x - start1 + start2 - k;
+                while (x >= start1 && y >= start2
+                        && left.charAt(x) == right.charAt(y)) {
+                    vUp[i] = x--;
+                    y--;
+                }
+                // Second step
+                if (delta % 2 == 0 && -d <= k && k <= d) {
+                    if (vUp[i] <= vDown[i + delta]) { // NOPMD
+                        return buildSnake(vUp[i], k + start1 - start2, end1, end2);
+                    }
+                }
+            }
+        }
+
+        // this should not happen
+        throw new RuntimeException("Internal Error");
+    }
+
+    /**
+     * Build a snake.
+     *
+     * @param start  the value of the start of the snake
+     * @param diag  the value of the diagonal of the snake
+     * @param end1  the value of the end of the first sequence to be compared
+     * @param end2  the value of the end of the second sequence to be compared
+     * @return the snake built
+     */
+    private Snake buildSnake(final int start, final int diag, final int end1, final int end2) {
+        int end = start;
+        while (end - diag < end2
+                && end < end1
+                && left.charAt(end) == right.charAt(end - diag)) {
+            ++end;
+        }
+        return new Snake(start, end, diag);
+    }
+
+    /**
+     * This class is a simple placeholder to hold the end part of a path
+     * under construction in a {@link StringsComparator StringsComparator}.
+     */
+    private static class Snake {
+
+        /** Start index. */
+        private final int start;
+
+        /** End index. */
+        private final int end;
+
+        /** Diagonal number. */
+        private final int diag;
+
+        /**
+         * Simple constructor. Creates a new instance of Snake with specified indices.
+         *
+         * @param start  start index of the snake
+         * @param end  end index of the snake
+         * @param diag  diagonal number
+         */
+        public Snake(final int start, final int end, final int diag) {
+            this.start = start;
+            this.end   = end;
+            this.diag  = diag;
+        }
+
+        /**
+         * Get the start index of the snake.
+         *
+         * @return start index of the snake
+         */
+        public int getStart() {
+            return start;
+        }
+
+        /**
+         * Get the end index of the snake.
+         *
+         * @return end index of the snake
+         */
+        public int getEnd() {
+            return end;
+        }
+
+        /**
+         * Get the diagonal number of the snake.
+         *
+         * @return diagonal number of the snake
+         */
+        public int getDiag() {
+            return diag;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/package-info.java b/src/main/java/org/apache/commons/text/diff/package-info.java
new file mode 100644
index 0000000..92fde86
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * <p>Provides algorithms for diff between strings.</p>
+ *
+ * <p>The initial implementation of the Myers algorithm was adapted from the
+ * commons-collections sequence package.</p>
+ *
+ * @since 1.0
+ */
+package org.apache.commons.text.diff;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/package-info.java b/src/main/java/org/apache/commons/text/package-info.java
new file mode 100644
index 0000000..f36b6dc
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * <p>Basic classes for text handling.</p>
+ *
+ * @since 1.0
+ */
+package org.apache.commons.text;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/CosineDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/CosineDistance.java b/src/main/java/org/apache/commons/text/similarity/CosineDistance.java
new file mode 100644
index 0000000..516c215
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/CosineDistance.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.Map;
+
+/**
+ * Measures the cosine distance between two character sequences.
+ *
+ * <p>It utilizes the {@link CosineSimilarity} to compute the distance. Character sequences
+ * are converted into vectors through a simple tokenizer that works with a regular expression
+ * to split words in a sentence.</p>
+ *
+ * <p>
+ * For further explanation about Cosine Similarity and Cosine Distance, refer to
+ * http://en.wikipedia.org/wiki/Cosine_similarity.
+ * </p>
+ *
+ * @since 1.0
+ * @see CosineSimilarity
+ */
+public class CosineDistance implements EditDistance<Double> {
+    /**
+     * Tokenizer used to convert the character sequence into a vector.
+     */
+    private final Tokenizer<CharSequence> tokenizer = new RegexTokenizer();
+    /**
+     * Cosine similarity.
+     */
+    private final CosineSimilarity cosineSimilarity = new CosineSimilarity();
+
+    @Override
+    public Double apply(final CharSequence left, final CharSequence right) {
+        final CharSequence[] leftTokens = tokenizer.tokenize(left);
+        final CharSequence[] rightTokens = tokenizer.tokenize(right);
+
+        final Map<CharSequence, Integer> leftVector = Counter.of(leftTokens);
+        final Map<CharSequence, Integer> rightVector = Counter.of(rightTokens);
+        final double similarity = cosineSimilarity.cosineSimilarity(leftVector, rightVector);
+        return 1.0 - similarity;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java b/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java
new file mode 100644
index 0000000..50790c1
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Measures the Cosine similarity of two vectors of an inner product space and
+ * compares the angle between them.
+ *
+ * <p>
+ * For further explanation about the Cosine Similarity, refer to
+ * http://en.wikipedia.org/wiki/Cosine_similarity.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class CosineSimilarity {
+
+    /**
+     * Calculates the cosine similarity for two given vectors.
+     *
+     * @param leftVector left vector
+     * @param rightVector right vector
+     * @return cosine similarity between the two vectors
+     */
+    public Double cosineSimilarity(final Map<CharSequence, Integer> leftVector,
+                                   final Map<CharSequence, Integer> rightVector) {
+        if (leftVector == null || rightVector == null) {
+            throw new IllegalArgumentException("Vectors must not be null");
+        }
+
+        final Set<CharSequence> intersection = getIntersection(leftVector, rightVector);
+
+        final double dotProduct = dot(leftVector, rightVector, intersection);
+        double d1 = 0.0d;
+        for (final Integer value : leftVector.values()) {
+            d1 += Math.pow(value, 2);
+        }
+        double d2 = 0.0d;
+        for (final Integer value : rightVector.values()) {
+            d2 += Math.pow(value, 2);
+        }
+        double cosineSimilarity;
+        if (d1 <= 0.0 || d2 <= 0.0) {
+            cosineSimilarity = 0.0;
+        } else {
+            cosineSimilarity = (double) (dotProduct / (double) (Math.sqrt(d1) * Math.sqrt(d2)));
+        }
+        return cosineSimilarity;
+    }
+
+    /**
+     * Returns a set with strings common to the two given maps.
+     *
+     * @param leftVector left vector map
+     * @param rightVector right vector map
+     * @return common strings
+     */
+    private Set<CharSequence> getIntersection(final Map<CharSequence, Integer> leftVector,
+            final Map<CharSequence, Integer> rightVector) {
+        final Set<CharSequence> intersection = new HashSet<>(leftVector.keySet());
+        intersection.retainAll(rightVector.keySet());
+        return intersection;
+    }
+
+    /**
+     * Computes the dot product of two vectors. It ignores remaining elements. It means
+     * that if a vector is longer than other, then a smaller part of it will be used to compute
+     * the dot product.
+     *
+     * @param leftVector left vector
+     * @param rightVector right vector
+     * @param intersection common elements
+     * @return the dot product
+     */
+    private double dot(final Map<CharSequence, Integer> leftVector, final Map<CharSequence, Integer> rightVector,
+            final Set<CharSequence> intersection) {
+        long dotProduct = 0;
+        for (final CharSequence key : intersection) {
+            dotProduct += leftVector.get(key) * rightVector.get(key);
+        }
+        return dotProduct;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/Counter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/Counter.java b/src/main/java/org/apache/commons/text/similarity/Counter.java
new file mode 100644
index 0000000..d259d6b
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/Counter.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Java implementation of Python's collections Counter module.
+ *
+ * <p>It counts how many times each element provided occurred in an array and
+ * returns a dict with the element as key and the count as value.</p>
+ *
+ * @see <a href="https://docs.python.org/dev/library/collections.html#collections.Counter">
+ * https://docs.python.org/dev/library/collections.html#collections.Counter</a>
+ *
+ * @since 1.0
+ */
+final class Counter {
+
+    /**
+     * Hidden constructor.
+     */
+    private Counter() {
+        super();
+    }
+
+    /**
+     * It counts how many times each element provided occurred in an array and
+     * returns a dict with the element as key and the count as value.
+     *
+     * @param tokens array of tokens
+     * @return dict, where the elements are key, and the count the value
+     */
+    public static Map<CharSequence, Integer> of(final CharSequence[] tokens) {
+        final Map<CharSequence, Integer> innerCounter = new HashMap<>();
+        for (final CharSequence token : tokens) {
+            if (innerCounter.containsKey(token)) {
+                int value = innerCounter.get(token);
+                innerCounter.put(token, ++value);
+            } else {
+                innerCounter.put(token, 1);
+            }
+        }
+        return innerCounter;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/EditDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/EditDistance.java b/src/main/java/org/apache/commons/text/similarity/EditDistance.java
new file mode 100644
index 0000000..cf4e2c0
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/EditDistance.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * Interface for <a href="http://en.wikipedia.org/wiki/Edit_distance">Edit Distances</a>.
+ *
+ * <p>
+ * An edit distance is a formal metric on the Kleene closure (<code>X<sup>*</sup></code>) over an
+ * alphabet (<code>X</code>). Note, that a <a href="https://en.wikipedia.org/wiki/Metric_(mathematics)">metric</a>
+ * on a set <code>S</code> is a function <code>d: [S * S] -&gt; [0, INFINITY)</code> such
+ * that the following hold for <code>x,y,z</code> in
+ * the set <code>S</code>:
+ * </p>
+ * <ul>
+ *     <li><code>d(x,y) &gt;= 0</code>, non-negativity or separation axiom</li>
+ *     <li><code>d(x,y) == 0</code>, if and only if, <code>x == y</code></li>
+ *     <li><code>d(x,y) == d(y,x)</code>, symmetry, and</li>
+ *     <li><code>d(x,z) &lt;=  d(x,y) + d(y,z)</code>, the triangle inequality</li>
+ * </ul>
+ *
+ *
+ * <p>
+ * This is a BiFunction&lt;CharSequence, CharSequence, R&gt;.
+ * The <code>apply</code> method
+ * accepts a pair of {@link CharSequence} parameters
+ * and returns an <code>R</code> type similarity score.
+ * </p>
+ *
+ * @param <R> The type of similarity score unit used by this EditDistance.
+ * @since 1.0
+ */
+public interface EditDistance<R> extends SimilarityScore<R> {
+
+    /**
+     * Compares two CharSequences.
+     *
+     * @param left the first CharSequence
+     * @param right the second CharSequence
+     * @return the similarity score between two CharSequences
+     */
+    @Override
+    R apply(CharSequence left, CharSequence right);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/EditDistanceFrom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/EditDistanceFrom.java b/src/main/java/org/apache/commons/text/similarity/EditDistanceFrom.java
new file mode 100644
index 0000000..b67a41f
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/EditDistanceFrom.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * <p>
+ * This stores a {@link EditDistance} implementation and a {@link CharSequence} "left" string.
+ * The {@link #apply(CharSequence right)} method accepts the "right" string and invokes the
+ * comparison function for the pair of strings.
+ * </p>
+ *
+ * <p>
+ * The following is an example which finds the most similar string:
+ * </p>
+ * <pre>
+ * EditDistance&lt;Integer&gt; editDistance = new LevenshteinDistance();
+ * String target = "Apache";
+ * EditDistanceFrom&lt;Integer&gt; editDistanceFrom =
+ *     new EditDistanceFrom&lt;Integer&gt;(editDistance, target);
+ * String mostSimilar = null;
+ * Integer shortestDistance = null;
+ *
+ * for (String test : new String[] { "Appaloosa", "a patchy", "apple" }) {
+ *     Integer distance = editDistanceFrom.apply(test);
+ *     if (shortestDistance == null || distance &lt; shortestDistance) {
+ *         shortestDistance = distance;
+ *         mostSimilar = test;
+ *     }
+ * }
+ *
+ * System.out.println("The string most similar to \"" + target + "\" "
+ *     + "is \"" + mostSimilar + "\" because "
+ *     + "its distance is only " + shortestDistance + ".");
+ * </pre>
+ *
+ * @param <R> This is the type of similarity score used by the EditDistance function.
+ * @since 1.0
+ */
+public class EditDistanceFrom<R> {
+
+    /**
+     * Edit distance.
+     */
+    private final EditDistance<R> editDistance;
+    /**
+     * Left parameter used in distance function.
+     */
+    private final CharSequence left;
+
+    /**
+     * <p>This accepts the edit distance implementation and the "left" string.</p>
+     *
+     * @param editDistance This may not be null.
+     * @param left This may be null here,
+     *             but the EditDistance#compare(CharSequence left, CharSequence right)
+     *             implementation may not accept nulls.
+     */
+    public EditDistanceFrom(final EditDistance<R> editDistance, final CharSequence left) {
+        if (editDistance == null) {
+            throw new IllegalArgumentException("The edit distance may not be null.");
+        }
+
+        this.editDistance = editDistance;
+        this.left = left;
+    }
+
+    /**
+     * <p>
+     * This compares "left" field against the "right" parameter
+     * using the "edit distance" implementation.
+     * </p>
+     *
+     * @param right the second CharSequence
+     * @return the similarity score between two CharSequences
+     */
+    public R apply(final CharSequence right) {
+        return editDistance.apply(left, right);
+    }
+
+    /**
+     * Gets the left parameter.
+     *
+     * @return the left parameter
+     */
+    public CharSequence getLeft() {
+        return left;
+    }
+
+    /**
+     * Gets the edit distance.
+     *
+     * @return the edit distance
+     */
+    public EditDistance<R> getEditDistance() {
+        return editDistance;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/FuzzyScore.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/FuzzyScore.java b/src/main/java/org/apache/commons/text/similarity/FuzzyScore.java
new file mode 100644
index 0000000..8356960
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/FuzzyScore.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.Locale;
+
+/**
+ * A matching algorithm that is similar to the searching algorithms implemented in editors such
+ * as Sublime Text, TextMate, Atom and others.
+ *
+ * <p>
+ * One point is given for every matched character. Subsequent matches yield two bonus points. A higher score
+ * indicates a higher similarity.
+ * </p>
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Lang 3.3.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class FuzzyScore {
+
+    /**
+     * Locale used to change the case of text.
+     */
+    private final Locale locale;
+
+
+    /**
+     * <p>This returns a {@link Locale}-specific {@link FuzzyScore}.</p>
+     *
+     * @param locale The string matching logic is case insensitive.
+                     A {@link Locale} is necessary to normalize both Strings to lower case.
+     * @throws IllegalArgumentException
+     *         This is thrown if the {@link Locale} parameter is {@code null}.
+     */
+    public FuzzyScore(final Locale locale) {
+        if (locale == null) {
+            throw new IllegalArgumentException("Locale must not be null");
+        }
+        this.locale = locale;
+    }
+
+    /**
+     * <p>
+     * Find the Fuzzy Score which indicates the similarity score between two
+     * Strings.
+     * </p>
+     *
+     * <pre>
+     * score.fuzzyScore(null, null, null)                                    = IllegalArgumentException
+     * score.fuzzyScore("", "", Locale.ENGLISH)                              = 0
+     * score.fuzzyScore("Workshop", "b", Locale.ENGLISH)                     = 0
+     * score.fuzzyScore("Room", "o", Locale.ENGLISH)                         = 1
+     * score.fuzzyScore("Workshop", "w", Locale.ENGLISH)                     = 1
+     * score.fuzzyScore("Workshop", "ws", Locale.ENGLISH)                    = 2
+     * score.fuzzyScore("Workshop", "wo", Locale.ENGLISH)                    = 4
+     * score.fuzzyScore("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
+     * </pre>
+     *
+     * @param term a full term that should be matched against, must not be null
+     * @param query the query that will be matched against a term, must not be
+     *            null
+     * @return result score
+     * @throws IllegalArgumentException if either String input {@code null} or
+     *             Locale input {@code null}
+     */
+    public Integer fuzzyScore(final CharSequence term, final CharSequence query) {
+        if (term == null || query == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+
+        // fuzzy logic is case insensitive. We normalize the Strings to lower
+        // case right from the start. Turning characters to lower case
+        // via Character.toLowerCase(char) is unfortunately insufficient
+        // as it does not accept a locale.
+        final String termLowerCase = term.toString().toLowerCase(locale);
+        final String queryLowerCase = query.toString().toLowerCase(locale);
+
+        // the resulting score
+        int score = 0;
+
+        // the position in the term which will be scanned next for potential
+        // query character matches
+        int termIndex = 0;
+
+        // index of the previously matched character in the term
+        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
+
+        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
+            final char queryChar = queryLowerCase.charAt(queryIndex);
+
+            boolean termCharacterMatchFound = false;
+            for (; termIndex < termLowerCase.length()
+                    && !termCharacterMatchFound; termIndex++) {
+                final char termChar = termLowerCase.charAt(termIndex);
+
+                if (queryChar == termChar) {
+                    // simple character matches result in one point
+                    score++;
+
+                    // subsequent character matches further improve
+                    // the score.
+                    if (previousMatchingCharacterIndex + 1 == termIndex) {
+                        score += 2;
+                    }
+
+                    previousMatchingCharacterIndex = termIndex;
+
+                    // we can leave the nested loop. Every character in the
+                    // query can match at most one character in the term.
+                    termCharacterMatchFound = true;
+                }
+            }
+        }
+
+        return score;
+    }
+
+    /**
+     * Gets the locale.
+     *
+     * @return the locale
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/HammingDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/HammingDistance.java b/src/main/java/org/apache/commons/text/similarity/HammingDistance.java
new file mode 100644
index 0000000..8d88fe8
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/HammingDistance.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * The hamming distance between two strings of equal length is the number of
+ * positions at which the corresponding symbols are different.
+ *
+ * <p>
+ * For further explanation about the Hamming Distance, take a look at its
+ * Wikipedia page at http://en.wikipedia.org/wiki/Hamming_distance.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class HammingDistance implements EditDistance<Integer> {
+
+    /**
+     * Find the Hamming Distance between two strings with the same
+     * length.
+     *
+     * <p>The distance starts with zero, and for each occurrence of a
+     * different character in either String, it increments the distance
+     * by 1, and finally return its value.</p>
+     *
+     * <p>Since the Hamming Distance can only be calculated between strings of equal length, input of different lengths
+     * will throw IllegalArgumentException</p>
+     *
+     * <pre>
+     * distance.apply("", "")               = 0
+     * distance.apply("pappa", "pappa")     = 0
+     * distance.apply("1011101", "1011111") = 1
+     * distance.apply("ATCG", "ACCC")       = 2
+     * distance.apply("karolin", "kerstin"  = 3
+     * </pre>
+     *
+     * @param left the first CharSequence, must not be null
+     * @param right the second CharSequence, must not be null
+     * @return distance
+     * @throws IllegalArgumentException if either input is {@code null} or
+     *             if they do not have the same length
+     */
+    @Override
+    public Integer apply(final CharSequence left, final CharSequence right) {
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+
+        if (left.length() != right.length()) {
+            throw new IllegalArgumentException("Strings must have the same length");
+        }
+
+        int distance = 0;
+
+        for (int i = 0; i < left.length(); i++) {
+            if (left.charAt(i) != right.charAt(i)) {
+                distance++;
+            }
+        }
+
+        return distance;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/JaccardDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/JaccardDistance.java b/src/main/java/org/apache/commons/text/similarity/JaccardDistance.java
new file mode 100644
index 0000000..1e30b07
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/JaccardDistance.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * Measures the Jaccard distance of two sets of character sequence. Jaccard
+ * distance is the dissimilarity between two sets. Its the complementary of
+ * Jaccard similarity.
+ *
+ * <p>
+ * For further explanation about Jaccard Distance, refer
+ * https://en.wikipedia.org/wiki/Jaccard_index
+ * </p>
+ *
+ * @since 1.0
+ */
+public class JaccardDistance implements EditDistance<Double> {
+
+    /**
+     * We normalize the jaccardSimilarity for the purpose of computing the distance.
+     */
+    private final JaccardSimilarity jaccardSimilarity = new JaccardSimilarity();
+
+    /**
+     * Calculates Jaccard distance of two set character sequence passed as
+     * input. Calculates Jaccard similarity and returns the complement of it.
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return index
+     * @throws IllegalArgumentException
+     *             if either String input {@code null}
+     */
+    @Override
+    public Double apply(CharSequence left, CharSequence right) {
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Input cannot be null");
+        }
+        return Math.round((1 - jaccardSimilarity.apply(left, right)) * 100d) / 100d;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/JaccardSimilarity.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/JaccardSimilarity.java b/src/main/java/org/apache/commons/text/similarity/JaccardSimilarity.java
new file mode 100644
index 0000000..af7ce71
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/JaccardSimilarity.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Measures the Jaccard similarity (aka Jaccard index) of two sets of character
+ * sequence. Jaccard similarity is the size of the intersection divided by the
+ * size of the union of the two sets.
+ *
+ * <p>
+ * For further explanation about Jaccard Similarity, refer
+ * https://en.wikipedia.org/wiki/Jaccard_index
+ * </p>
+ *
+ * @since 1.0
+ */
+public class JaccardSimilarity implements SimilarityScore<Double> {
+
+    /**
+     * Calculates Jaccard Similarity of two set character sequence passed as
+     * input.
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return index
+     * @throws IllegalArgumentException
+     *             if either String input {@code null}
+     */
+    @Override
+    public Double apply(CharSequence left, CharSequence right) {
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Input cannot be null");
+        }
+        return Math.round(calculateJaccardSimilarity(left, right) * 100d) / 100d;
+    }
+
+    /**
+     * Calculates Jaccard Similarity of two character sequences passed as
+     * input. Does the calculation by identifying the union (characters in at
+     * least one of the two sets) of the two sets and intersection (characters
+     * which are present in set one which are present in set two)
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return index
+     */
+    private Double calculateJaccardSimilarity(CharSequence left, CharSequence right) {
+        Set<String> intersectionSet = new HashSet<String>();
+        Set<String> unionSet = new HashSet<String>();
+        boolean unionFilled = false;
+        int leftLength = left.length();
+        int rightLength = right.length();
+        if (leftLength == 0 || rightLength == 0) {
+            return 0d;
+        }
+
+        for (int leftIndex = 0; leftIndex < leftLength; leftIndex++) {
+            unionSet.add(String.valueOf(left.charAt(leftIndex)));
+            for (int rightIndex = 0; rightIndex < rightLength; rightIndex++) {
+                if (!unionFilled) {
+                    unionSet.add(String.valueOf(right.charAt(rightIndex)));
+                }
+                if (left.charAt(leftIndex) == right.charAt(rightIndex)) {
+                    intersectionSet.add(String.valueOf(left.charAt(leftIndex)));
+                }
+            }
+            unionFilled = true;
+        }
+        return Double.valueOf(intersectionSet.size()) / Double.valueOf(unionSet.size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/JaroWinklerDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/JaroWinklerDistance.java b/src/main/java/org/apache/commons/text/similarity/JaroWinklerDistance.java
new file mode 100644
index 0000000..0190c7b
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/JaroWinklerDistance.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.Arrays;
+
+/**
+ * A similarity algorithm indicating the percentage of matched characters between two character sequences.
+ *
+ * <p>
+ * The Jaro measure is the weighted sum of percentage of matched characters
+ * from each file and transposed characters. Winkler increased this measure
+ * for matching initial characters.
+ * </p>
+ *
+ * <p>
+ * This implementation is based on the Jaro Winkler similarity algorithm
+ * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">
+ * http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
+ * </p>
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Lang 3.3.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class JaroWinklerDistance implements SimilarityScore<Double> {
+
+    /**
+     * Represents a failed index search.
+     */
+    public static final int INDEX_NOT_FOUND = -1;
+
+    /**
+     * Find the Jaro Winkler Distance which indicates the similarity score
+     * between two CharSequences.
+     *
+     * <pre>
+     * distance.apply(null, null)          = IllegalArgumentException
+     * distance.apply("","")               = 0.0
+     * distance.apply("","a")              = 0.0
+     * distance.apply("aaapppp", "")       = 0.0
+     * distance.apply("frog", "fog")       = 0.93
+     * distance.apply("fly", "ant")        = 0.0
+     * distance.apply("elephant", "hippo") = 0.44
+     * distance.apply("hippo", "elephant") = 0.44
+     * distance.apply("hippo", "zzzzzzzz") = 0.0
+     * distance.apply("hello", "hallo")    = 0.88
+     * distance.apply("ABC Corporation", "ABC Corp") = 0.93
+     * distance.apply("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
+     * distance.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
+     * distance.apply("PENNSYLVANIA", "PENNCISYLVNIA")    = 0.88
+     * </pre>
+     *
+     * @param left the first String, must not be null
+     * @param right the second String, must not be null
+     * @return result distance
+     * @throws IllegalArgumentException if either String input {@code null}
+     */
+    @Override
+    public Double apply(final CharSequence left, final CharSequence right) {
+        final double defaultScalingFactor = 0.1;
+        final double percentageRoundValue = 100.0;
+
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+
+        int[] mtp = matches(left, right);
+        double m = mtp[0];
+        if (m == 0) {
+            return 0D;
+        }
+        double j = ((m / left.length() + m / right.length() + (m - mtp[1]) / m)) / 3;
+        double jw = j < 0.7D ? j : j + Math.min(defaultScalingFactor, 1D / mtp[3]) * mtp[2] * (1D - j);
+        return Math.round(jw * percentageRoundValue) / percentageRoundValue;
+    }
+
+    /**
+     * This method returns the Jaro-Winkler string matches, transpositions, prefix, max array.
+     *
+     * @param first the first string to be matched
+     * @param second the second string to be machted
+     * @return mtp array containing: matches, transpositions, prefix, and max length
+     */
+    protected static int[] matches(final CharSequence first, final CharSequence second) {
+        CharSequence max, min;
+        if (first.length() > second.length()) {
+            max = first;
+            min = second;
+        } else {
+            max = second;
+            min = first;
+        }
+        int range = Math.max(max.length() / 2 - 1, 0);
+        int[] matchIndexes = new int[min.length()];
+        Arrays.fill(matchIndexes, -1);
+        boolean[] matchFlags = new boolean[max.length()];
+        int matches = 0;
+        for (int mi = 0; mi < min.length(); mi++) {
+            char c1 = min.charAt(mi);
+            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
+                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
+                    matchIndexes[mi] = xi;
+                    matchFlags[xi] = true;
+                    matches++;
+                    break;
+                }
+            }
+        }
+        char[] ms1 = new char[matches];
+        char[] ms2 = new char[matches];
+        for (int i = 0, si = 0; i < min.length(); i++) {
+            if (matchIndexes[i] != -1) {
+                ms1[si] = min.charAt(i);
+                si++;
+            }
+        }
+        for (int i = 0, si = 0; i < max.length(); i++) {
+            if (matchFlags[i]) {
+                ms2[si] = max.charAt(i);
+                si++;
+            }
+        }
+        int transpositions = 0;
+        for (int mi = 0; mi < ms1.length; mi++) {
+            if (ms1[mi] != ms2[mi]) {
+                transpositions++;
+            }
+        }
+        int prefix = 0;
+        for (int mi = 0; mi < min.length(); mi++) {
+            if (first.charAt(mi) == second.charAt(mi)) {
+                prefix++;
+            } else {
+                break;
+            }
+        }
+        return new int[] { matches, transpositions / 2, prefix, max.length() };
+    }
+
+}


[21/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/EditCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/EditCommand.java b/src/main/java/org/apache/commons/text/beta/diff/EditCommand.java
deleted file mode 100644
index a98a719..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/EditCommand.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-/**
- * Abstract base class for all commands used to transform an objects sequence
- * into another one.
- * <p>
- * When two objects sequences are compared through the
- * {@link StringsComparator#getScript StringsComparator.getScript} method,
- * the result is provided has a {@link EditScript script} containing the commands
- * that progressively transform the first sequence into the second one.
- * </p>
- * <p>
- * There are only three types of commands, all of which are subclasses of this
- * abstract class. Each command is associated with one object belonging to at
- * least one of the sequences. These commands are {@link InsertCommand
- * InsertCommand} which correspond to an object of the second sequence being
- * inserted into the first sequence, {@link DeleteCommand DeleteCommand} which
- * correspond to an object of the first sequence being removed and
- * {@link KeepCommand KeepCommand} which correspond to an object of the first
- * sequence which <code>equals</code> an object in the second sequence. It is
- * guaranteed that comparison is always performed this way (i.e. the
- * <code>equals</code> method of the object from the first sequence is used and
- * the object passed as an argument comes from the second sequence) ; this can
- * be important if subclassing is used for some elements in the first sequence
- * and the <code>equals</code> method is specialized.
- * </p>
- *
- * <p>
- * This code has been adapted from Apache Commons Collections 4.0.
- * </p>
- *
- * @see StringsComparator
- * @see EditScript
- *
- * @param <T> object type
- * @since 1.0
- */
-public abstract class EditCommand<T> {
-
-    /** Object on which the command should be applied. */
-    private final T object;
-
-    /**
-     * Simple constructor. Creates a new instance of EditCommand
-     *
-     * @param object  reference to the object associated with this command, this
-     *   refers to an element of one of the sequences being compared
-     */
-    protected EditCommand(final T object) {
-        this.object = object;
-    }
-
-    /**
-     * Returns the object associated with this command.
-     *
-     * @return the object on which the command is applied
-     */
-    protected T getObject() {
-        return object;
-    }
-
-    /**
-     * Accept a visitor.
-     * <p>
-     * This method is invoked for each commands belonging to
-     * an {@link EditScript EditScript}, in order to implement the visitor design pattern
-     *
-     * @param visitor  the visitor to be accepted
-     */
-    public abstract void accept(CommandVisitor<T> visitor);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/EditScript.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/EditScript.java b/src/main/java/org/apache/commons/text/beta/diff/EditScript.java
deleted file mode 100644
index ed18438..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/EditScript.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class gathers all the {@link EditCommand commands} needed to transform
- * one objects sequence into another objects sequence.
- * <p>
- * An edit script is the most general view of the differences between two
- * sequences. It is built as the result of the comparison between two sequences
- * by the {@link StringsComparator StringsComparator} class. The user can
- * walk through it using the <em>visitor</em> design pattern.
- * <p>
- * It is guaranteed that the objects embedded in the {@link InsertCommand insert
- * commands} come from the second sequence and that the objects embedded in
- * either the {@link DeleteCommand delete commands} or {@link KeepCommand keep
- * commands} come from the first sequence. This can be important if subclassing
- * is used for some elements in the first sequence and the <code>equals</code>
- * method is specialized.
- *
- * @see StringsComparator
- * @see EditCommand
- * @see CommandVisitor
- * @see ReplacementsHandler
- *
- * @param <T> object type
- * @since 1.0
- */
-public class EditScript<T> {
-
-    /** Container for the commands. */
-    private final List<EditCommand<T>> commands;
-
-    /** Length of the longest common subsequence. */
-    private int lcsLength;
-
-    /** Number of modifications. */
-    private int modifications;
-
-    /**
-     * Simple constructor. Creates a new empty script.
-     */
-    public EditScript() {
-        commands = new ArrayList<>();
-        lcsLength = 0;
-        modifications = 0;
-    }
-
-    /**
-     * Add a keep command to the script.
-     *
-     * @param command  command to add
-     */
-    public void append(final KeepCommand<T> command) {
-        commands.add(command);
-        ++lcsLength;
-    }
-
-    /**
-     * Add an insert command to the script.
-     *
-     * @param command  command to add
-     */
-    public void append(final InsertCommand<T> command) {
-        commands.add(command);
-        ++modifications;
-    }
-
-    /**
-     * Add a delete command to the script.
-     *
-     * @param command  command to add
-     */
-    public void append(final DeleteCommand<T> command) {
-        commands.add(command);
-        ++modifications;
-    }
-
-    /**
-     * Visit the script. The script implements the <em>visitor</em> design
-     * pattern, this method is the entry point to which the user supplies its
-     * own visitor, the script will be responsible to drive it through the
-     * commands in order and call the appropriate method as each command is
-     * encountered.
-     *
-     * @param visitor  the visitor that will visit all commands in turn
-     */
-    public void visit(final CommandVisitor<T> visitor) {
-        for (final EditCommand<T> command : commands) {
-            command.accept(visitor);
-        }
-    }
-
-    /**
-     * Get the length of the Longest Common Subsequence (LCS). The length of the
-     * longest common subsequence is the number of {@link KeepCommand keep
-     * commands} in the script.
-     *
-     * @return length of the Longest Common Subsequence
-     */
-    public int getLCSLength() {
-        return lcsLength;
-    }
-
-    /**
-     * Get the number of effective modifications. The number of effective
-     * modification is the number of {@link DeleteCommand delete} and
-     * {@link InsertCommand insert} commands in the script.
-     *
-     * @return number of effective modifications
-     */
-    public int getModifications() {
-        return modifications;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/InsertCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/InsertCommand.java b/src/main/java/org/apache/commons/text/beta/diff/InsertCommand.java
deleted file mode 100644
index ecdde02..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/InsertCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-/**
- * Command representing the insertion of one object of the second sequence.
- * <p>
- * When one object of the second sequence has no corresponding object in the
- * first sequence at the right place, the {@link EditScript edit script}
- * transforming the first sequence into the second sequence uses an instance of
- * this class to represent the insertion of this object. The objects embedded in
- * these type of commands always come from the second sequence.
- * </p>
- *
- * @see StringsComparator
- * @see EditScript
- *
- * @param <T> object type
- * @since 1.0
- */
-public class InsertCommand<T> extends EditCommand<T> {
-
-    /**
-     * Simple constructor. Creates a new instance of InsertCommand
-     *
-     * @param object  the object of the second sequence that should be inserted
-     */
-    public InsertCommand(final T object) {
-        super(object);
-    }
-
-    /**
-     * Accept a visitor. When an <code>InsertCommand</code> accepts a visitor,
-     * it calls its {@link CommandVisitor#visitInsertCommand visitInsertCommand}
-     * method.
-     *
-     * @param visitor  the visitor to be accepted
-     */
-    @Override
-    public void accept(final CommandVisitor<T> visitor) {
-        visitor.visitInsertCommand(getObject());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/KeepCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/KeepCommand.java b/src/main/java/org/apache/commons/text/beta/diff/KeepCommand.java
deleted file mode 100644
index 7f03ade..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/KeepCommand.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-/**
- * Command representing the keeping of one object present in both sequences.
- * <p>
- * When one object of the first sequence <code>equals</code> another objects in
- * the second sequence at the right place, the {@link EditScript edit script}
- * transforming the first sequence into the second sequence uses an instance of
- * this class to represent the keeping of this object. The objects embedded in
- * these type of commands always come from the first sequence.
- * </p>
- *
- * @see StringsComparator
- * @see EditScript
- *
- * @param <T> object type
- * @since 1.0
- */
-public class KeepCommand<T> extends EditCommand<T> {
-
-    /**
-     * Simple constructor. Creates a new instance of KeepCommand
-     *
-     * @param object  the object belonging to both sequences (the object is a
-     *   reference to the instance in the first sequence which is known
-     *   to be equal to an instance in the second sequence)
-     */
-    public KeepCommand(final T object) {
-        super(object);
-    }
-
-    /**
-     * Accept a visitor. When a <code>KeepCommand</code> accepts a visitor, it
-     * calls its {@link CommandVisitor#visitKeepCommand visitKeepCommand} method.
-     *
-     * @param visitor  the visitor to be accepted
-     */
-    @Override
-    public void accept(final CommandVisitor<T> visitor) {
-        visitor.visitKeepCommand(getObject());
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/ReplacementsFinder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/ReplacementsFinder.java b/src/main/java/org/apache/commons/text/beta/diff/ReplacementsFinder.java
deleted file mode 100644
index a09c015..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/ReplacementsFinder.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class handles sequences of replacements resulting from a comparison.
- * <p>
- * The comparison of two objects sequences leads to the identification of common
- * parts and parts which only belong to the first or to the second sequence. The
- * common parts appear in the edit script in the form of <em>keep</em> commands,
- * they can be considered as synchronization objects between the two sequences.
- * These synchronization objects split the two sequences in synchronized
- * sub-sequences. The first sequence can be transformed into the second one by
- * replacing each synchronized sub-sequence of the first sequence by the
- * corresponding sub-sequence of the second sequence. This is a synthetic way to
- * see an {@link EditScript edit script}, replacing individual
- * {@link DeleteCommand delete}, {@link KeepCommand keep} and
- * {@link InsertCommand insert} commands by fewer replacements acting on
- * complete sub-sequences.
- * </p>
- * <p>
- * This class is devoted to perform this interpretation. It visits an
- * {@link EditScript edit script} (because it implements the
- * {@link CommandVisitor CommandVisitor} interface) and calls a user-supplied
- * handler implementing the {@link ReplacementsHandler ReplacementsHandler}
- * interface to process the sub-sequences.
- * </p>
- *
- * @see ReplacementsHandler
- * @see EditScript
- * @see StringsComparator
- *
- * @param <T> object type
- * @since 1.0
- */
-public class ReplacementsFinder<T> implements CommandVisitor<T> {
-
-    /**
-     * List of pending insertions.
-     */
-    private final List<T> pendingInsertions;
-    /**
-     * List of pending deletions.
-     */
-    private final List<T> pendingDeletions;
-    /**
-     * Count of elements skipped.
-     */
-    private int skipped;
-
-    /** Handler to call when synchronized sequences are found. */
-    private final ReplacementsHandler<T> handler;
-
-    /**
-     * Simple constructor. Creates a new instance of {@link ReplacementsFinder}.
-     *
-     * @param handler  handler to call when synchronized sequences are found
-     */
-    public ReplacementsFinder(final ReplacementsHandler<T> handler) {
-        pendingInsertions = new ArrayList<>();
-        pendingDeletions  = new ArrayList<>();
-        skipped           = 0;
-        this.handler      = handler;
-    }
-
-    /**
-     * Add an object to the pending insertions set.
-     *
-     * @param object  object to insert
-     */
-    @Override
-    public void visitInsertCommand(final T object) {
-        pendingInsertions.add(object);
-    }
-
-    /**
-     * Handle a synchronization object.
-     * <p>
-     * When a synchronization object is identified, the pending insertions and
-     * pending deletions sets are provided to the user handler as subsequences.
-     * </p>
-     *
-     * @param object  synchronization object detected
-     */
-    @Override
-    public void visitKeepCommand(final T object) {
-        if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) {
-            ++skipped;
-        } else {
-            handler.handleReplacement(skipped, pendingDeletions, pendingInsertions);
-            pendingDeletions.clear();
-            pendingInsertions.clear();
-            skipped = 1;
-        }
-    }
-
-    /**
-     * Add an object to the pending deletions set.
-     *
-     * @param object  object to delete
-     */
-    @Override
-    public void visitDeleteCommand(final T object) {
-        pendingDeletions.add(object);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/ReplacementsHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/ReplacementsHandler.java b/src/main/java/org/apache/commons/text/beta/diff/ReplacementsHandler.java
deleted file mode 100644
index 8744081..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/ReplacementsHandler.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-import java.util.List;
-
-/**
- * This interface is devoted to handle synchronized replacement sequences.
- *
- * @param <T> object type
- * @see ReplacementsFinder
- * @since 1.0
- */
-public interface ReplacementsHandler<T> {
-
-    /**
-     * Handle two synchronized sequences.
-     * <p>
-     * This method is called by a {@link ReplacementsFinder ReplacementsFinder}
-     * instance when it has synchronized two sub-sequences of object arrays
-     * being compared, and at least one of the sequences is non-empty. Since the
-     * sequences are synchronized, the objects before the two sub-sequences are
-     * equals (if they exist). This property also holds for the objects after
-     * the two sub-sequences.
-     * <p>
-     * The replacement is defined as replacing the <code>from</code>
-     * sub-sequence into the <code>to</code> sub-sequence.
-     *
-     * @param skipped  number of tokens skipped since the last call (i.e. number of
-     *   tokens that were in both sequences), this number should be strictly positive
-     *   except on the very first call where it can be zero (if the first object of
-     *   the two sequences are different)
-     * @param from  sub-sequence of objects coming from the first sequence
-     * @param to  sub-sequence of objects coming from the second sequence
-     */
-    void handleReplacement(int skipped, List<T> from, List<T> to);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/StringsComparator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/StringsComparator.java b/src/main/java/org/apache/commons/text/beta/diff/StringsComparator.java
deleted file mode 100644
index 3d39433..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/StringsComparator.java
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-/**
- * <p>
- * It is guaranteed that the comparisons will always be done as
- * <code>o1.equals(o2)</code> where <code>o1</code> belongs to the first
- * sequence and <code>o2</code> belongs to the second sequence. This can
- * be important if subclassing is used for some elements in the first
- * sequence and the <code>equals</code> method is specialized.
- * </p>
- * <p>
- * Comparison can be seen from two points of view: either as giving the smallest
- * modification allowing to transform the first sequence into the second one, or
- * as giving the longest sequence which is a subsequence of both initial
- * sequences. The <code>equals</code> method is used to compare objects, so any
- * object can be put into sequences. Modifications include deleting, inserting
- * or keeping one object, starting from the beginning of the first sequence.
- * </p>
- * <p>
- * This class implements the comparison algorithm, which is the very efficient
- * algorithm from Eugene W. Myers
- * <a href="http://www.cis.upenn.edu/~bcpierce/courses/dd/papers/diff.ps">
- * An O(ND) Difference Algorithm and Its Variations</a>. This algorithm produces
- * the shortest possible {@link EditScript edit script} containing all the
- * {@link EditCommand commands} needed to transform the first sequence into
- * the second one.
- *
- * <p>
- * This code has been adapted from Apache Commons Collections 4.0.
- * </p>
- *
- * @see EditScript
- * @see EditCommand
- * @see CommandVisitor
- * @since 1.0
- */
-public class StringsComparator {
-
-    /**
-     * First character sequence.
-     */
-    private final String left;
-    /**
-     * Second character sequence.
-     */
-    private final String right;
-    /**
-     * Temporary array.
-     */
-    private final int[] vDown;
-    /**
-     * Temporary array.
-     */
-    private final int[] vUp;
-
-    /**
-     * Simple constructor.
-     * <p>
-     * Creates a new instance of StringsComparator.
-     * </p>
-     * <p>
-     * It is <em>guaranteed</em> that the comparisons will always be done as
-     * <code>o1.equals(o2)</code> where <code>o1</code> belongs to the first
-     * sequence and <code>o2</code> belongs to the second sequence. This can be
-     * important if subclassing is used for some elements in the first sequence
-     * and the <code>equals</code> method is specialized.
-     * </p>
-     *
-     * @param left first character sequence to be compared
-     * @param right second character sequence to be compared
-     */
-    public StringsComparator(final String left, final String right) {
-        this.left = left;
-        this.right = right;
-
-        final int size = left.length() + right.length() + 2;
-        vDown = new int[size];
-        vUp   = new int[size];
-    }
-
-    /**
-     * Get the {@link EditScript} object.
-     * <p>
-     * It is guaranteed that the objects embedded in the {@link InsertCommand
-     * insert commands} come from the second sequence and that the objects
-     * embedded in either the {@link DeleteCommand delete commands} or
-     * {@link KeepCommand keep commands} come from the first sequence. This can
-     * be important if subclassing is used for some elements in the first
-     * sequence and the <code>equals</code> method is specialized.
-     * </p>
-     *
-     * @return the edit script resulting from the comparison of the two
-     *         sequences
-     */
-    public EditScript<Character> getScript() {
-        final EditScript<Character> script = new EditScript<>();
-        buildScript(0, left.length(), 0, right.length(), script);
-        return script;
-    }
-
-    /**
-     * Build an edit script.
-     *
-     * @param start1  the begin of the first sequence to be compared
-     * @param end1  the end of the first sequence to be compared
-     * @param start2  the begin of the second sequence to be compared
-     * @param end2  the end of the second sequence to be compared
-     * @param script the edited script
-     */
-    private void buildScript(final int start1, final int end1, final int start2, final int end2,
-            final EditScript<Character> script) {
-        final Snake middle = getMiddleSnake(start1, end1, start2, end2);
-
-        if (middle == null
-                || middle.getStart() == end1 && middle.getDiag() == end1 - end2
-                || middle.getEnd() == start1 && middle.getDiag() == start1 - start2) {
-
-            int i = start1;
-            int j = start2;
-            while (i < end1 || j < end2) {
-                if (i < end1 && j < end2 && left.charAt(i) == right.charAt(j)) {
-                    script.append(new KeepCommand<>(left.charAt(i)));
-                    ++i;
-                    ++j;
-                } else {
-                    if (end1 - start1 > end2 - start2) {
-                        script.append(new DeleteCommand<>(left.charAt(i)));
-                        ++i;
-                    } else {
-                        script.append(new InsertCommand<>(right.charAt(j)));
-                        ++j;
-                    }
-                }
-            }
-
-        } else {
-
-            buildScript(start1, middle.getStart(),
-                        start2, middle.getStart() - middle.getDiag(),
-                        script);
-            for (int i = middle.getStart(); i < middle.getEnd(); ++i) {
-                script.append(new KeepCommand<>(left.charAt(i)));
-            }
-            buildScript(middle.getEnd(), end1,
-                        middle.getEnd() - middle.getDiag(), end2,
-                        script);
-        }
-    }
-
-    /**
-     * Get the middle snake corresponding to two subsequences of the
-     * main sequences.
-     * <p>
-     * The snake is found using the MYERS Algorithm (this algorithms has
-     * also been implemented in the GNU diff program). This algorithm is
-     * explained in Eugene Myers article:
-     * <a href="http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps">
-     * An O(ND) Difference Algorithm and Its Variations</a>.
-     * </p>
-     *
-     * @param start1  the begin of the first sequence to be compared
-     * @param end1  the end of the first sequence to be compared
-     * @param start2  the begin of the second sequence to be compared
-     * @param end2  the end of the second sequence to be compared
-     * @return the middle snake
-     */
-    private Snake getMiddleSnake(final int start1, final int end1, final int start2, final int end2) {
-        // Myers Algorithm
-        // Initialisations
-        final int m = end1 - start1;
-        final int n = end2 - start2;
-        if (m == 0 || n == 0) {
-            return null;
-        }
-
-        final int delta  = m - n;
-        final int sum    = n + m;
-        final int offset = (sum % 2 == 0 ? sum : sum + 1) / 2;
-        vDown[1 + offset] = start1;
-        vUp[1 + offset]   = end1 + 1;
-
-        for (int d = 0; d <= offset; ++d) {
-            // Down
-            for (int k = -d; k <= d; k += 2) {
-                // First step
-
-                final int i = k + offset;
-                if (k == -d || k != d && vDown[i - 1] < vDown[i + 1]) {
-                    vDown[i] = vDown[i + 1];
-                } else {
-                    vDown[i] = vDown[i - 1] + 1;
-                }
-
-                int x = vDown[i];
-                int y = x - start1 + start2 - k;
-
-                while (x < end1 && y < end2 && left.charAt(x) == right.charAt(y)) {
-                    vDown[i] = ++x;
-                    ++y;
-                }
-                // Second step
-                if (delta % 2 != 0 && delta - d <= k && k <= delta + d) {
-                    if (vUp[i - delta] <= vDown[i]) { // NOPMD
-                        return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
-                    }
-                }
-            }
-
-            // Up
-            for (int k = delta - d; k <= delta + d; k += 2) {
-                // First step
-                final int i = k + offset - delta;
-                if (k == delta - d
-                        || k != delta + d && vUp[i + 1] <= vUp[i - 1]) {
-                    vUp[i] = vUp[i + 1] - 1;
-                } else {
-                    vUp[i] = vUp[i - 1];
-                }
-
-                int x = vUp[i] - 1;
-                int y = x - start1 + start2 - k;
-                while (x >= start1 && y >= start2
-                        && left.charAt(x) == right.charAt(y)) {
-                    vUp[i] = x--;
-                    y--;
-                }
-                // Second step
-                if (delta % 2 == 0 && -d <= k && k <= d) {
-                    if (vUp[i] <= vDown[i + delta]) { // NOPMD
-                        return buildSnake(vUp[i], k + start1 - start2, end1, end2);
-                    }
-                }
-            }
-        }
-
-        // this should not happen
-        throw new RuntimeException("Internal Error");
-    }
-
-    /**
-     * Build a snake.
-     *
-     * @param start  the value of the start of the snake
-     * @param diag  the value of the diagonal of the snake
-     * @param end1  the value of the end of the first sequence to be compared
-     * @param end2  the value of the end of the second sequence to be compared
-     * @return the snake built
-     */
-    private Snake buildSnake(final int start, final int diag, final int end1, final int end2) {
-        int end = start;
-        while (end - diag < end2
-                && end < end1
-                && left.charAt(end) == right.charAt(end - diag)) {
-            ++end;
-        }
-        return new Snake(start, end, diag);
-    }
-
-    /**
-     * This class is a simple placeholder to hold the end part of a path
-     * under construction in a {@link StringsComparator StringsComparator}.
-     */
-    private static class Snake {
-
-        /** Start index. */
-        private final int start;
-
-        /** End index. */
-        private final int end;
-
-        /** Diagonal number. */
-        private final int diag;
-
-        /**
-         * Simple constructor. Creates a new instance of Snake with specified indices.
-         *
-         * @param start  start index of the snake
-         * @param end  end index of the snake
-         * @param diag  diagonal number
-         */
-        public Snake(final int start, final int end, final int diag) {
-            this.start = start;
-            this.end   = end;
-            this.diag  = diag;
-        }
-
-        /**
-         * Get the start index of the snake.
-         *
-         * @return start index of the snake
-         */
-        public int getStart() {
-            return start;
-        }
-
-        /**
-         * Get the end index of the snake.
-         *
-         * @return end index of the snake
-         */
-        public int getEnd() {
-            return end;
-        }
-
-        /**
-         * Get the diagonal number of the snake.
-         *
-         * @return diagonal number of the snake
-         */
-        public int getDiag() {
-            return diag;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/package-info.java b/src/main/java/org/apache/commons/text/beta/diff/package-info.java
deleted file mode 100644
index 0d1323f..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/package-info.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * <p>Provides algorithms for diff between strings.</p>
- *
- * <p>The initial implementation of the Myers algorithm was adapted from the
- * commons-collections sequence package.</p>
- *
- * @since 1.0
- */
-package org.apache.commons.text.beta.diff;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/package-info.java b/src/main/java/org/apache/commons/text/beta/package-info.java
deleted file mode 100644
index dc58111..0000000
--- a/src/main/java/org/apache/commons/text/beta/package-info.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * <p>Basic classes for text handling.</p>
- *
- * @since 1.0
- */
-package org.apache.commons.text.beta;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/CosineDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/CosineDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/CosineDistance.java
deleted file mode 100644
index a51fbee..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/CosineDistance.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.Map;
-
-/**
- * Measures the cosine distance between two character sequences.
- *
- * <p>It utilizes the {@link CosineSimilarity} to compute the distance. Character sequences
- * are converted into vectors through a simple tokenizer that works with a regular expression
- * to split words in a sentence.</p>
- *
- * <p>
- * For further explanation about Cosine Similarity and Cosine Distance, refer to
- * http://en.wikipedia.org/wiki/Cosine_similarity.
- * </p>
- *
- * @since 1.0
- * @see CosineSimilarity
- */
-public class CosineDistance implements EditDistance<Double> {
-    /**
-     * Tokenizer used to convert the character sequence into a vector.
-     */
-    private final Tokenizer<CharSequence> tokenizer = new RegexTokenizer();
-    /**
-     * Cosine similarity.
-     */
-    private final CosineSimilarity cosineSimilarity = new CosineSimilarity();
-
-    @Override
-    public Double apply(final CharSequence left, final CharSequence right) {
-        final CharSequence[] leftTokens = tokenizer.tokenize(left);
-        final CharSequence[] rightTokens = tokenizer.tokenize(right);
-
-        final Map<CharSequence, Integer> leftVector = Counter.of(leftTokens);
-        final Map<CharSequence, Integer> rightVector = Counter.of(rightTokens);
-        final double similarity = cosineSimilarity.cosineSimilarity(leftVector, rightVector);
-        return 1.0 - similarity;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/CosineSimilarity.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/CosineSimilarity.java b/src/main/java/org/apache/commons/text/beta/similarity/CosineSimilarity.java
deleted file mode 100644
index d318dc3..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/CosineSimilarity.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Measures the Cosine similarity of two vectors of an inner product space and
- * compares the angle between them.
- *
- * <p>
- * For further explanation about the Cosine Similarity, refer to
- * http://en.wikipedia.org/wiki/Cosine_similarity.
- * </p>
- *
- * @since 1.0
- */
-public class CosineSimilarity {
-
-    /**
-     * Calculates the cosine similarity for two given vectors.
-     *
-     * @param leftVector left vector
-     * @param rightVector right vector
-     * @return cosine similarity between the two vectors
-     */
-    public Double cosineSimilarity(final Map<CharSequence, Integer> leftVector,
-                                   final Map<CharSequence, Integer> rightVector) {
-        if (leftVector == null || rightVector == null) {
-            throw new IllegalArgumentException("Vectors must not be null");
-        }
-
-        final Set<CharSequence> intersection = getIntersection(leftVector, rightVector);
-
-        final double dotProduct = dot(leftVector, rightVector, intersection);
-        double d1 = 0.0d;
-        for (final Integer value : leftVector.values()) {
-            d1 += Math.pow(value, 2);
-        }
-        double d2 = 0.0d;
-        for (final Integer value : rightVector.values()) {
-            d2 += Math.pow(value, 2);
-        }
-        double cosineSimilarity;
-        if (d1 <= 0.0 || d2 <= 0.0) {
-            cosineSimilarity = 0.0;
-        } else {
-            cosineSimilarity = (double) (dotProduct / (double) (Math.sqrt(d1) * Math.sqrt(d2)));
-        }
-        return cosineSimilarity;
-    }
-
-    /**
-     * Returns a set with strings common to the two given maps.
-     *
-     * @param leftVector left vector map
-     * @param rightVector right vector map
-     * @return common strings
-     */
-    private Set<CharSequence> getIntersection(final Map<CharSequence, Integer> leftVector,
-            final Map<CharSequence, Integer> rightVector) {
-        final Set<CharSequence> intersection = new HashSet<>(leftVector.keySet());
-        intersection.retainAll(rightVector.keySet());
-        return intersection;
-    }
-
-    /**
-     * Computes the dot product of two vectors. It ignores remaining elements. It means
-     * that if a vector is longer than other, then a smaller part of it will be used to compute
-     * the dot product.
-     *
-     * @param leftVector left vector
-     * @param rightVector right vector
-     * @param intersection common elements
-     * @return the dot product
-     */
-    private double dot(final Map<CharSequence, Integer> leftVector, final Map<CharSequence, Integer> rightVector,
-            final Set<CharSequence> intersection) {
-        long dotProduct = 0;
-        for (final CharSequence key : intersection) {
-            dotProduct += leftVector.get(key) * rightVector.get(key);
-        }
-        return dotProduct;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/Counter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/Counter.java b/src/main/java/org/apache/commons/text/beta/similarity/Counter.java
deleted file mode 100644
index 5093cbf..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/Counter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Java implementation of Python's collections Counter module.
- *
- * <p>It counts how many times each element provided occurred in an array and
- * returns a dict with the element as key and the count as value.</p>
- *
- * @see <a href="https://docs.python.org/dev/library/collections.html#collections.Counter">
- * https://docs.python.org/dev/library/collections.html#collections.Counter</a>
- *
- * @since 1.0
- */
-final class Counter {
-
-    /**
-     * Hidden constructor.
-     */
-    private Counter() {
-        super();
-    }
-
-    /**
-     * It counts how many times each element provided occurred in an array and
-     * returns a dict with the element as key and the count as value.
-     *
-     * @param tokens array of tokens
-     * @return dict, where the elements are key, and the count the value
-     */
-    public static Map<CharSequence, Integer> of(final CharSequence[] tokens) {
-        final Map<CharSequence, Integer> innerCounter = new HashMap<>();
-        for (final CharSequence token : tokens) {
-            if (innerCounter.containsKey(token)) {
-                int value = innerCounter.get(token);
-                innerCounter.put(token, ++value);
-            } else {
-                innerCounter.put(token, 1);
-            }
-        }
-        return innerCounter;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/EditDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/EditDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/EditDistance.java
deleted file mode 100644
index 4de96fb..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/EditDistance.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * Interface for <a href="http://en.wikipedia.org/wiki/Edit_distance">Edit Distances</a>.
- *
- * <p>
- * An edit distance is a formal metric on the Kleene closure (<code>X<sup>*</sup></code>) over an
- * alphabet (<code>X</code>). Note, that a <a href="https://en.wikipedia.org/wiki/Metric_(mathematics)">metric</a>
- * on a set <code>S</code> is a function <code>d: [S * S] -&gt; [0, INFINITY)</code> such
- * that the following hold for <code>x,y,z</code> in
- * the set <code>S</code>:
- * </p>
- * <ul>
- *     <li><code>d(x,y) &gt;= 0</code>, non-negativity or separation axiom</li>
- *     <li><code>d(x,y) == 0</code>, if and only if, <code>x == y</code></li>
- *     <li><code>d(x,y) == d(y,x)</code>, symmetry, and</li>
- *     <li><code>d(x,z) &lt;=  d(x,y) + d(y,z)</code>, the triangle inequality</li>
- * </ul>
- *
- *
- * <p>
- * This is a BiFunction&lt;CharSequence, CharSequence, R&gt;.
- * The <code>apply</code> method
- * accepts a pair of {@link CharSequence} parameters
- * and returns an <code>R</code> type similarity score.
- * </p>
- *
- * @param <R> The type of similarity score unit used by this EditDistance.
- * @since 1.0
- */
-public interface EditDistance<R> extends SimilarityScore<R> {
-
-    /**
-     * Compares two CharSequences.
-     *
-     * @param left the first CharSequence
-     * @param right the second CharSequence
-     * @return the similarity score between two CharSequences
-     */
-    @Override
-    R apply(CharSequence left, CharSequence right);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/EditDistanceFrom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/EditDistanceFrom.java b/src/main/java/org/apache/commons/text/beta/similarity/EditDistanceFrom.java
deleted file mode 100644
index 34452fb..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/EditDistanceFrom.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * <p>
- * This stores a {@link EditDistance} implementation and a {@link CharSequence} "left" string.
- * The {@link #apply(CharSequence right)} method accepts the "right" string and invokes the
- * comparison function for the pair of strings.
- * </p>
- *
- * <p>
- * The following is an example which finds the most similar string:
- * </p>
- * <pre>
- * EditDistance&lt;Integer&gt; editDistance = new LevenshteinDistance();
- * String target = "Apache";
- * EditDistanceFrom&lt;Integer&gt; editDistanceFrom =
- *     new EditDistanceFrom&lt;Integer&gt;(editDistance, target);
- * String mostSimilar = null;
- * Integer shortestDistance = null;
- *
- * for (String test : new String[] { "Appaloosa", "a patchy", "apple" }) {
- *     Integer distance = editDistanceFrom.apply(test);
- *     if (shortestDistance == null || distance &lt; shortestDistance) {
- *         shortestDistance = distance;
- *         mostSimilar = test;
- *     }
- * }
- *
- * System.out.println("The string most similar to \"" + target + "\" "
- *     + "is \"" + mostSimilar + "\" because "
- *     + "its distance is only " + shortestDistance + ".");
- * </pre>
- *
- * @param <R> This is the type of similarity score used by the EditDistance function.
- * @since 1.0
- */
-public class EditDistanceFrom<R> {
-
-    /**
-     * Edit distance.
-     */
-    private final EditDistance<R> editDistance;
-    /**
-     * Left parameter used in distance function.
-     */
-    private final CharSequence left;
-
-    /**
-     * <p>This accepts the edit distance implementation and the "left" string.</p>
-     *
-     * @param editDistance This may not be null.
-     * @param left This may be null here,
-     *             but the EditDistance#compare(CharSequence left, CharSequence right)
-     *             implementation may not accept nulls.
-     */
-    public EditDistanceFrom(final EditDistance<R> editDistance, final CharSequence left) {
-        if (editDistance == null) {
-            throw new IllegalArgumentException("The edit distance may not be null.");
-        }
-
-        this.editDistance = editDistance;
-        this.left = left;
-    }
-
-    /**
-     * <p>
-     * This compares "left" field against the "right" parameter
-     * using the "edit distance" implementation.
-     * </p>
-     *
-     * @param right the second CharSequence
-     * @return the similarity score between two CharSequences
-     */
-    public R apply(final CharSequence right) {
-        return editDistance.apply(left, right);
-    }
-
-    /**
-     * Gets the left parameter.
-     *
-     * @return the left parameter
-     */
-    public CharSequence getLeft() {
-        return left;
-    }
-
-    /**
-     * Gets the edit distance.
-     *
-     * @return the edit distance
-     */
-    public EditDistance<R> getEditDistance() {
-        return editDistance;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/FuzzyScore.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/FuzzyScore.java b/src/main/java/org/apache/commons/text/beta/similarity/FuzzyScore.java
deleted file mode 100644
index 3647a49..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/FuzzyScore.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.Locale;
-
-/**
- * A matching algorithm that is similar to the searching algorithms implemented in editors such
- * as Sublime Text, TextMate, Atom and others.
- *
- * <p>
- * One point is given for every matched character. Subsequent matches yield two bonus points. A higher score
- * indicates a higher similarity.
- * </p>
- *
- * <p>
- * This code has been adapted from Apache Commons Lang 3.3.
- * </p>
- *
- * @since 1.0
- */
-public class FuzzyScore {
-
-    /**
-     * Locale used to change the case of text.
-     */
-    private final Locale locale;
-
-
-    /**
-     * <p>This returns a {@link Locale}-specific {@link FuzzyScore}.</p>
-     *
-     * @param locale The string matching logic is case insensitive.
-                     A {@link Locale} is necessary to normalize both Strings to lower case.
-     * @throws IllegalArgumentException
-     *         This is thrown if the {@link Locale} parameter is {@code null}.
-     */
-    public FuzzyScore(final Locale locale) {
-        if (locale == null) {
-            throw new IllegalArgumentException("Locale must not be null");
-        }
-        this.locale = locale;
-    }
-
-    /**
-     * <p>
-     * Find the Fuzzy Score which indicates the similarity score between two
-     * Strings.
-     * </p>
-     *
-     * <pre>
-     * score.fuzzyScore(null, null, null)                                    = IllegalArgumentException
-     * score.fuzzyScore("", "", Locale.ENGLISH)                              = 0
-     * score.fuzzyScore("Workshop", "b", Locale.ENGLISH)                     = 0
-     * score.fuzzyScore("Room", "o", Locale.ENGLISH)                         = 1
-     * score.fuzzyScore("Workshop", "w", Locale.ENGLISH)                     = 1
-     * score.fuzzyScore("Workshop", "ws", Locale.ENGLISH)                    = 2
-     * score.fuzzyScore("Workshop", "wo", Locale.ENGLISH)                    = 4
-     * score.fuzzyScore("Apache Software Foundation", "asf", Locale.ENGLISH) = 3
-     * </pre>
-     *
-     * @param term a full term that should be matched against, must not be null
-     * @param query the query that will be matched against a term, must not be
-     *            null
-     * @return result score
-     * @throws IllegalArgumentException if either String input {@code null} or
-     *             Locale input {@code null}
-     */
-    public Integer fuzzyScore(final CharSequence term, final CharSequence query) {
-        if (term == null || query == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-
-        // fuzzy logic is case insensitive. We normalize the Strings to lower
-        // case right from the start. Turning characters to lower case
-        // via Character.toLowerCase(char) is unfortunately insufficient
-        // as it does not accept a locale.
-        final String termLowerCase = term.toString().toLowerCase(locale);
-        final String queryLowerCase = query.toString().toLowerCase(locale);
-
-        // the resulting score
-        int score = 0;
-
-        // the position in the term which will be scanned next for potential
-        // query character matches
-        int termIndex = 0;
-
-        // index of the previously matched character in the term
-        int previousMatchingCharacterIndex = Integer.MIN_VALUE;
-
-        for (int queryIndex = 0; queryIndex < queryLowerCase.length(); queryIndex++) {
-            final char queryChar = queryLowerCase.charAt(queryIndex);
-
-            boolean termCharacterMatchFound = false;
-            for (; termIndex < termLowerCase.length()
-                    && !termCharacterMatchFound; termIndex++) {
-                final char termChar = termLowerCase.charAt(termIndex);
-
-                if (queryChar == termChar) {
-                    // simple character matches result in one point
-                    score++;
-
-                    // subsequent character matches further improve
-                    // the score.
-                    if (previousMatchingCharacterIndex + 1 == termIndex) {
-                        score += 2;
-                    }
-
-                    previousMatchingCharacterIndex = termIndex;
-
-                    // we can leave the nested loop. Every character in the
-                    // query can match at most one character in the term.
-                    termCharacterMatchFound = true;
-                }
-            }
-        }
-
-        return score;
-    }
-
-    /**
-     * Gets the locale.
-     *
-     * @return the locale
-     */
-    public Locale getLocale() {
-        return locale;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/HammingDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/HammingDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/HammingDistance.java
deleted file mode 100644
index 2ab73ea..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/HammingDistance.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * The hamming distance between two strings of equal length is the number of
- * positions at which the corresponding symbols are different.
- *
- * <p>
- * For further explanation about the Hamming Distance, take a look at its
- * Wikipedia page at http://en.wikipedia.org/wiki/Hamming_distance.
- * </p>
- *
- * @since 1.0
- */
-public class HammingDistance implements EditDistance<Integer> {
-
-    /**
-     * Find the Hamming Distance between two strings with the same
-     * length.
-     *
-     * <p>The distance starts with zero, and for each occurrence of a
-     * different character in either String, it increments the distance
-     * by 1, and finally return its value.</p>
-     *
-     * <p>Since the Hamming Distance can only be calculated between strings of equal length, input of different lengths
-     * will throw IllegalArgumentException</p>
-     *
-     * <pre>
-     * distance.apply("", "")               = 0
-     * distance.apply("pappa", "pappa")     = 0
-     * distance.apply("1011101", "1011111") = 1
-     * distance.apply("ATCG", "ACCC")       = 2
-     * distance.apply("karolin", "kerstin"  = 3
-     * </pre>
-     *
-     * @param left the first CharSequence, must not be null
-     * @param right the second CharSequence, must not be null
-     * @return distance
-     * @throws IllegalArgumentException if either input is {@code null} or
-     *             if they do not have the same length
-     */
-    @Override
-    public Integer apply(final CharSequence left, final CharSequence right) {
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-
-        if (left.length() != right.length()) {
-            throw new IllegalArgumentException("Strings must have the same length");
-        }
-
-        int distance = 0;
-
-        for (int i = 0; i < left.length(); i++) {
-            if (left.charAt(i) != right.charAt(i)) {
-                distance++;
-            }
-        }
-
-        return distance;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/JaccardDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/JaccardDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/JaccardDistance.java
deleted file mode 100644
index 6dcfbd4..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/JaccardDistance.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * Measures the Jaccard distance of two sets of character sequence. Jaccard
- * distance is the dissimilarity between two sets. Its the complementary of
- * Jaccard similarity.
- *
- * <p>
- * For further explanation about Jaccard Distance, refer
- * https://en.wikipedia.org/wiki/Jaccard_index
- * </p>
- *
- * @since 1.0
- */
-public class JaccardDistance implements EditDistance<Double> {
-
-    /**
-     * We normalize the jaccardSimilarity for the purpose of computing the distance.
-     */
-    private final JaccardSimilarity jaccardSimilarity = new JaccardSimilarity();
-
-    /**
-     * Calculates Jaccard distance of two set character sequence passed as
-     * input. Calculates Jaccard similarity and returns the complement of it.
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return index
-     * @throws IllegalArgumentException
-     *             if either String input {@code null}
-     */
-    @Override
-    public Double apply(CharSequence left, CharSequence right) {
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Input cannot be null");
-        }
-        return Math.round((1 - jaccardSimilarity.apply(left, right)) * 100d) / 100d;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/JaccardSimilarity.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/JaccardSimilarity.java b/src/main/java/org/apache/commons/text/beta/similarity/JaccardSimilarity.java
deleted file mode 100644
index 42da85d..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/JaccardSimilarity.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Measures the Jaccard similarity (aka Jaccard index) of two sets of character
- * sequence. Jaccard similarity is the size of the intersection divided by the
- * size of the union of the two sets.
- *
- * <p>
- * For further explanation about Jaccard Similarity, refer
- * https://en.wikipedia.org/wiki/Jaccard_index
- * </p>
- *
- * @since 1.0
- */
-public class JaccardSimilarity implements SimilarityScore<Double> {
-
-    /**
-     * Calculates Jaccard Similarity of two set character sequence passed as
-     * input.
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return index
-     * @throws IllegalArgumentException
-     *             if either String input {@code null}
-     */
-    @Override
-    public Double apply(CharSequence left, CharSequence right) {
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Input cannot be null");
-        }
-        return Math.round(calculateJaccardSimilarity(left, right) * 100d) / 100d;
-    }
-
-    /**
-     * Calculates Jaccard Similarity of two character sequences passed as
-     * input. Does the calculation by identifying the union (characters in at
-     * least one of the two sets) of the two sets and intersection (characters
-     * which are present in set one which are present in set two)
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return index
-     */
-    private Double calculateJaccardSimilarity(CharSequence left, CharSequence right) {
-        Set<String> intersectionSet = new HashSet<String>();
-        Set<String> unionSet = new HashSet<String>();
-        boolean unionFilled = false;
-        int leftLength = left.length();
-        int rightLength = right.length();
-        if (leftLength == 0 || rightLength == 0) {
-            return 0d;
-        }
-
-        for (int leftIndex = 0; leftIndex < leftLength; leftIndex++) {
-            unionSet.add(String.valueOf(left.charAt(leftIndex)));
-            for (int rightIndex = 0; rightIndex < rightLength; rightIndex++) {
-                if (!unionFilled) {
-                    unionSet.add(String.valueOf(right.charAt(rightIndex)));
-                }
-                if (left.charAt(leftIndex) == right.charAt(rightIndex)) {
-                    intersectionSet.add(String.valueOf(left.charAt(leftIndex)));
-                }
-            }
-            unionFilled = true;
-        }
-        return Double.valueOf(intersectionSet.size()) / Double.valueOf(unionSet.size());
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/JaroWinklerDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/JaroWinklerDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/JaroWinklerDistance.java
deleted file mode 100644
index 7d1718b..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/JaroWinklerDistance.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.Arrays;
-
-/**
- * A similarity algorithm indicating the percentage of matched characters between two character sequences.
- *
- * <p>
- * The Jaro measure is the weighted sum of percentage of matched characters
- * from each file and transposed characters. Winkler increased this measure
- * for matching initial characters.
- * </p>
- *
- * <p>
- * This implementation is based on the Jaro Winkler similarity algorithm
- * from <a href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance">
- * http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance</a>.
- * </p>
- *
- * <p>
- * This code has been adapted from Apache Commons Lang 3.3.
- * </p>
- *
- * @since 1.0
- */
-public class JaroWinklerDistance implements SimilarityScore<Double> {
-
-    /**
-     * Represents a failed index search.
-     */
-    public static final int INDEX_NOT_FOUND = -1;
-
-    /**
-     * Find the Jaro Winkler Distance which indicates the similarity score
-     * between two CharSequences.
-     *
-     * <pre>
-     * distance.apply(null, null)          = IllegalArgumentException
-     * distance.apply("","")               = 0.0
-     * distance.apply("","a")              = 0.0
-     * distance.apply("aaapppp", "")       = 0.0
-     * distance.apply("frog", "fog")       = 0.93
-     * distance.apply("fly", "ant")        = 0.0
-     * distance.apply("elephant", "hippo") = 0.44
-     * distance.apply("hippo", "elephant") = 0.44
-     * distance.apply("hippo", "zzzzzzzz") = 0.0
-     * distance.apply("hello", "hallo")    = 0.88
-     * distance.apply("ABC Corporation", "ABC Corp") = 0.93
-     * distance.apply("D N H Enterprises Inc", "D &amp; H Enterprises, Inc.") = 0.95
-     * distance.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness") = 0.92
-     * distance.apply("PENNSYLVANIA", "PENNCISYLVNIA")    = 0.88
-     * </pre>
-     *
-     * @param left the first String, must not be null
-     * @param right the second String, must not be null
-     * @return result distance
-     * @throws IllegalArgumentException if either String input {@code null}
-     */
-    @Override
-    public Double apply(final CharSequence left, final CharSequence right) {
-        final double defaultScalingFactor = 0.1;
-        final double percentageRoundValue = 100.0;
-
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-
-        int[] mtp = matches(left, right);
-        double m = mtp[0];
-        if (m == 0) {
-            return 0D;
-        }
-        double j = ((m / left.length() + m / right.length() + (m - mtp[1]) / m)) / 3;
-        double jw = j < 0.7D ? j : j + Math.min(defaultScalingFactor, 1D / mtp[3]) * mtp[2] * (1D - j);
-        return Math.round(jw * percentageRoundValue) / percentageRoundValue;
-    }
-
-    /**
-     * This method returns the Jaro-Winkler string matches, transpositions, prefix, max array.
-     *
-     * @param first the first string to be matched
-     * @param second the second string to be machted
-     * @return mtp array containing: matches, transpositions, prefix, and max length
-     */
-    protected static int[] matches(final CharSequence first, final CharSequence second) {
-        CharSequence max, min;
-        if (first.length() > second.length()) {
-            max = first;
-            min = second;
-        } else {
-            max = second;
-            min = first;
-        }
-        int range = Math.max(max.length() / 2 - 1, 0);
-        int[] matchIndexes = new int[min.length()];
-        Arrays.fill(matchIndexes, -1);
-        boolean[] matchFlags = new boolean[max.length()];
-        int matches = 0;
-        for (int mi = 0; mi < min.length(); mi++) {
-            char c1 = min.charAt(mi);
-            for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
-                if (!matchFlags[xi] && c1 == max.charAt(xi)) {
-                    matchIndexes[mi] = xi;
-                    matchFlags[xi] = true;
-                    matches++;
-                    break;
-                }
-            }
-        }
-        char[] ms1 = new char[matches];
-        char[] ms2 = new char[matches];
-        for (int i = 0, si = 0; i < min.length(); i++) {
-            if (matchIndexes[i] != -1) {
-                ms1[si] = min.charAt(i);
-                si++;
-            }
-        }
-        for (int i = 0, si = 0; i < max.length(); i++) {
-            if (matchFlags[i]) {
-                ms2[si] = max.charAt(i);
-                si++;
-            }
-        }
-        int transpositions = 0;
-        for (int mi = 0; mi < ms1.length; mi++) {
-            if (ms1[mi] != ms2[mi]) {
-                transpositions++;
-            }
-        }
-        int prefix = 0;
-        for (int mi = 0; mi < min.length(); mi++) {
-            if (first.charAt(mi) == second.charAt(mi)) {
-                prefix++;
-            } else {
-                break;
-            }
-        }
-        return new int[] { matches, transpositions / 2, prefix, max.length() };
-    }
-
-}


[20/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistance.java
deleted file mode 100644
index ec69f1d..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistance.java
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.Arrays;
-
-/**
- * An algorithm for measuring the difference between two character sequences.
- *
- * <p>
- * This is the number of changes needed to change one sequence into another,
- * where each change is a single character modification (deletion, insertion
- * or substitution).
- * </p>
- *
- * @since 1.0
- */
-public class LevenshteinDetailedDistance implements EditDistance<LevenshteinResults> {
-
-    /**
-     * Default instance.
-     */
-    private static final LevenshteinDetailedDistance DEFAULT_INSTANCE = new LevenshteinDetailedDistance();
-    /**
-     * Threshold.
-     */
-    private final Integer threshold;
-
-    /**
-     * <p>
-     * This returns the default instance that uses a version
-     * of the algorithm that does not use a threshold parameter.
-     * </p>
-     *
-     * @see LevenshteinDetailedDistance#getDefaultInstance()
-     */
-    public LevenshteinDetailedDistance() {
-        this(null);
-    }
-
-    /**
-     * If the threshold is not null, distance calculations will be limited to a maximum length.
-     *
-     * <p>If the threshold is null, the unlimited version of the algorithm will be used.</p>
-     *
-     * @param threshold If this is null then distances calculations will not be limited. This may not be negative.
-     */
-    public LevenshteinDetailedDistance(final Integer threshold) {
-        if (threshold != null && threshold < 0) {
-            throw new IllegalArgumentException("Threshold must not be negative");
-        }
-        this.threshold = threshold;
-    }
-
-    /**
-     * <p>Find the Levenshtein distance between two Strings.</p>
-     *
-     * <p>A higher score indicates a greater distance.</p>
-     *
-     * <p>The previous implementation of the Levenshtein distance algorithm
-     * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
-     *
-     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
-     * which can occur when my Java implementation is used with very large strings.<br>
-     * This implementation of the Levenshtein distance algorithm
-     * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
-     *
-     * <pre>
-     * distance.apply(null, *)             = IllegalArgumentException
-     * distance.apply(*, null)             = IllegalArgumentException
-     * distance.apply("","")               = 0
-     * distance.apply("","a")              = 1
-     * distance.apply("aaapppp", "")       = 7
-     * distance.apply("frog", "fog")       = 1
-     * distance.apply("fly", "ant")        = 3
-     * distance.apply("elephant", "hippo") = 7
-     * distance.apply("hippo", "elephant") = 7
-     * distance.apply("hippo", "zzzzzzzz") = 8
-     * distance.apply("hello", "hallo")    = 1
-     * </pre>
-     *
-     * @param left the first string, must not be null
-     * @param right the second string, must not be null
-     * @return result distance, or -1
-     * @throws IllegalArgumentException if either String input {@code null}
-     */
-    @Override
-    public LevenshteinResults apply(final CharSequence left, final CharSequence right) {
-        if (threshold != null) {
-            return limitedCompare(left, right, threshold);
-        }
-        return unlimitedCompare(left, right);
-    }
-
-    /**
-     * Gets the default instance.
-     *
-     * @return the default instace
-     */
-    public static LevenshteinDetailedDistance getDefaultInstance() {
-        return DEFAULT_INSTANCE;
-    }
-
-    /**
-     * Gets the distance threshold.
-     *
-     * @return the distance threshold
-     */
-    public Integer getThreshold() {
-        return threshold;
-    }
-
-    /**
-     * Find the Levenshtein distance between two CharSequences if it's less than or
-     * equal to a given threshold.
-     *
-     * <p>
-     * This implementation follows from Algorithms on Strings, Trees and
-     * Sequences by Dan Gusfield and Chas Emerick's implementation of the
-     * Levenshtein distance algorithm from <a
-     * href="http://www.merriampark.com/ld.htm"
-     * >http://www.merriampark.com/ld.htm</a>
-     * </p>
-     *
-     * <pre>
-     * limitedCompare(null, *, *)             = IllegalArgumentException
-     * limitedCompare(*, null, *)             = IllegalArgumentException
-     * limitedCompare(*, *, -1)               = IllegalArgumentException
-     * limitedCompare("","", 0)               = 0
-     * limitedCompare("aaapppp", "", 8)       = 7
-     * limitedCompare("aaapppp", "", 7)       = 7
-     * limitedCompare("aaapppp", "", 6))      = -1
-     * limitedCompare("elephant", "hippo", 7) = 7
-     * limitedCompare("elephant", "hippo", 6) = -1
-     * limitedCompare("hippo", "elephant", 7) = 7
-     * limitedCompare("hippo", "elephant", 6) = -1
-     * </pre>
-     *
-     * @param left the first string, must not be null
-     * @param right the second string, must not be null
-     * @param threshold the target threshold, must not be negative
-     * @return result distance, or -1
-     */
-    private static LevenshteinResults limitedCompare(CharSequence left,
-                                                     CharSequence right,
-                                                     final int threshold) { //NOPMD
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-        if (threshold < 0) {
-            throw new IllegalArgumentException("Threshold must not be negative");
-        }
-
-        /*
-         * This implementation only computes the distance if it's less than or
-         * equal to the threshold value, returning -1 if it's greater. The
-         * advantage is performance: unbounded distance is O(nm), but a bound of
-         * k allows us to reduce it to O(km) time by only computing a diagonal
-         * stripe of width 2k + 1 of the cost table. It is also possible to use
-         * this to compute the unbounded Levenshtein distance by starting the
-         * threshold at 1 and doubling each time until the distance is found;
-         * this is O(dm), where d is the distance.
-         *
-         * One subtlety comes from needing to ignore entries on the border of
-         * our stripe eg. p[] = |#|#|#|* d[] = *|#|#|#| We must ignore the entry
-         * to the left of the leftmost member We must ignore the entry above the
-         * rightmost member
-         *
-         * Another subtlety comes from our stripe running off the matrix if the
-         * strings aren't of the same size. Since string s is always swapped to
-         * be the shorter of the two, the stripe will always run off to the
-         * upper right instead of the lower left of the matrix.
-         *
-         * As a concrete example, suppose s is of length 5, t is of length 7,
-         * and our threshold is 1. In this case we're going to walk a stripe of
-         * length 3. The matrix would look like so:
-         *
-         * <pre>
-         *    1 2 3 4 5
-         * 1 |#|#| | | |
-         * 2 |#|#|#| | |
-         * 3 | |#|#|#| |
-         * 4 | | |#|#|#|
-         * 5 | | | |#|#|
-         * 6 | | | | |#|
-         * 7 | | | | | |
-         * </pre>
-         *
-         * Note how the stripe leads off the table as there is no possible way
-         * to turn a string of length 5 into one of length 7 in edit distance of
-         * 1.
-         *
-         * Additionally, this implementation decreases memory usage by using two
-         * single-dimensional arrays and swapping them back and forth instead of
-         * allocating an entire n by m matrix. This requires a few minor
-         * changes, such as immediately returning when it's detected that the
-         * stripe has run off the matrix and initially filling the arrays with
-         * large values so that entries we don't compute are ignored.
-         *
-         * See Algorithms on Strings, Trees and Sequences by Dan Gusfield for
-         * some discussion.
-         */
-
-        int n = left.length(); // length of left
-        int m = right.length(); // length of right
-
-        // if one string is empty, the edit distance is necessarily the length of the other
-        if (n == 0) {
-            return m <= threshold ? new LevenshteinResults(m, m, 0, 0) : new LevenshteinResults(-1, 0, 0, 0);
-        } else if (m == 0) {
-            return n <= threshold ? new LevenshteinResults(n, 0, n, 0) : new LevenshteinResults(-1, 0, 0, 0);
-        }
-
-        boolean swapped = false;
-        if (n > m) {
-            // swap the two strings to consume less memory
-            final CharSequence tmp = left;
-            left = right;
-            right = tmp;
-            n = m;
-            m = right.length();
-            swapped = true;
-        }
-
-        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
-        int[] d = new int[n + 1]; // cost array, horizontally
-        int[] tempD; // placeholder to assist in swapping p and d
-        final int[][] matrix = new int[m + 1][n + 1];
-
-        //filling the first row and first column values in the matrix
-        for (int index = 0; index <= n; index++) {
-            matrix[0][index] = index;
-        }
-        for (int index = 0; index <= m; index++) {
-            matrix[index][0] = index;
-        }
-
-        // fill in starting table values
-        final int boundary = Math.min(n, threshold) + 1;
-        for (int i = 0; i < boundary; i++) {
-            p[i] = i;
-        }
-        // these fills ensure that the value above the rightmost entry of our
-        // stripe will be ignored in following loop iterations
-        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
-        Arrays.fill(d, Integer.MAX_VALUE);
-
-        // iterates through t
-        for (int j = 1; j <= m; j++) {
-            final char rightJ = right.charAt(j - 1); // jth character of right
-            d[0] = j;
-
-            // compute stripe indices, constrain to array size
-            final int min = Math.max(1, j - threshold);
-            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(
-                    n, j + threshold);
-
-            // the stripe may lead off of the table if s and t are of different sizes
-            if (min > max) {
-                return new LevenshteinResults(-1, 0, 0, 0);
-            }
-
-            // ignore entry left of leftmost
-            if (min > 1) {
-                d[min - 1] = Integer.MAX_VALUE;
-            }
-
-            // iterates through [min, max] in s
-            for (int i = min; i <= max; i++) {
-                if (left.charAt(i - 1) == rightJ) {
-                    // diagonally left and up
-                    d[i] = p[i - 1];
-                } else {
-                    // 1 + minimum of cell to the left, to the top, diagonally left and up
-                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
-                }
-                matrix[j][i] = d[i];
-            }
-
-            // copy current distance counts to 'previous row' distance counts
-            tempD = p;
-            p = d;
-            d = tempD;
-        }
-
-        // if p[n] is greater than the threshold, there's no guarantee on it being the correct distance
-        if (p[n] <= threshold) {
-            return findDetailedResults(left, right, matrix, swapped);
-        }
-        return new LevenshteinResults(-1, 0, 0, 0);
-    }
-
-    /**
-     * <p>Find the Levenshtein distance between two Strings.</p>
-     *
-     * <p>A higher score indicates a greater distance.</p>
-     *
-     * <p>The previous implementation of the Levenshtein distance algorithm
-     * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
-     *
-     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
-     * which can occur when my Java implementation is used with very large strings.<br>
-     * This implementation of the Levenshtein distance algorithm
-     * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
-     *
-     * <pre>
-     * unlimitedCompare(null, *)             = IllegalArgumentException
-     * unlimitedCompare(*, null)             = IllegalArgumentException
-     * unlimitedCompare("","")               = 0
-     * unlimitedCompare("","a")              = 1
-     * unlimitedCompare("aaapppp", "")       = 7
-     * unlimitedCompare("frog", "fog")       = 1
-     * unlimitedCompare("fly", "ant")        = 3
-     * unlimitedCompare("elephant", "hippo") = 7
-     * unlimitedCompare("hippo", "elephant") = 7
-     * unlimitedCompare("hippo", "zzzzzzzz") = 8
-     * unlimitedCompare("hello", "hallo")    = 1
-     * </pre>
-     *
-     * @param left the first String, must not be null
-     * @param right the second String, must not be null
-     * @return result distance, or -1
-     * @throws IllegalArgumentException if either String input {@code null}
-     */
-    private static LevenshteinResults unlimitedCompare(CharSequence left, CharSequence right) {
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-
-        /*
-           The difference between this impl. and the previous is that, rather
-           than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
-           we maintain two single-dimensional arrays of length s.length() + 1.  The first, d,
-           is the 'current working' distance array that maintains the newest distance cost
-           counts as we iterate through the characters of String s.  Each time we increment
-           the index of String t we are comparing, d is copied to p, the second int[].  Doing so
-           allows us to retain the previous cost counts as required by the algorithm (taking
-           the minimum of the cost count to the left, up one, and diagonally up and to the left
-           of the current cost count being calculated).  (Note that the arrays aren't really
-           copied anymore, just switched...this is clearly much better than cloning an array
-           or doing a System.arraycopy() each time  through the outer loop.)
-
-           Effectively, the difference between the two implementations is this one does not
-           cause an out of memory condition when calculating the LD over two very large strings.
-         */
-
-        int n = left.length(); // length of left
-        int m = right.length(); // length of right
-
-        if (n == 0) {
-            return new LevenshteinResults(m, m, 0, 0);
-        } else if (m == 0) {
-            return new LevenshteinResults(n, 0, n, 0);
-        }
-        boolean swapped = false;
-        if (n > m) {
-            // swap the input strings to consume less memory
-            final CharSequence tmp = left;
-            left = right;
-            right = tmp;
-            n = m;
-            m = right.length();
-            swapped = true;
-        }
-
-        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
-        int[] d = new int[n + 1]; // cost array, horizontally
-        int[] tempD; //placeholder to assist in swapping p and d
-        final int[][] matrix = new int[m + 1][n + 1];
-
-        // filling the first row and first column values in the matrix
-        for (int index = 0; index <= n; index++) {
-            matrix[0][index] = index;
-        }
-        for (int index = 0; index <= m; index++) {
-            matrix[index][0] = index;
-        }
-
-        // indexes into strings left and right
-        int i; // iterates through left
-        int j; // iterates through right
-
-        char rightJ; // jth character of right
-
-        int cost; // cost
-        for (i = 0; i <= n; i++) {
-            p[i] = i;
-        }
-
-        for (j = 1; j <= m; j++) {
-            rightJ = right.charAt(j - 1);
-            d[0] = j;
-
-            for (i = 1; i <= n; i++) {
-                cost = left.charAt(i - 1) == rightJ ? 0 : 1;
-                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
-                d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
-                //filling the matrix
-                matrix[j][i] = d[i];
-            }
-
-            // copy current distance counts to 'previous row' distance counts
-            tempD = p;
-            p = d;
-            d = tempD;
-        }
-        return findDetailedResults(left, right, matrix, swapped);
-    }
-
-    /**
-     * Finds count for each of the three [insert, delete, substitute] operations
-     * needed. This is based on the matrix formed based on the two character
-     * sequence.
-     *
-     * @param left character sequence which need to be converted from
-     * @param right character sequence which need to be converted to
-     * @param matrix two dimensional array containing
-     * @param swapped tells whether the value for left character sequence and right
-     *            character sequence were swapped to save memory
-     * @return result object containing the count of insert, delete and substitute and total count needed
-     */
-    private static LevenshteinResults findDetailedResults(final CharSequence left,
-                                                          final CharSequence right,
-                                                          final int[][] matrix,
-                                                          final boolean swapped) {
-
-        int delCount = 0;
-        int addCount = 0;
-        int subCount = 0;
-
-        int rowIndex = right.length();
-        int columnIndex = left.length();
-
-        int dataAtLeft = 0;
-        int dataAtTop = 0;
-        int dataAtDiagonal = 0;
-        int data = 0;
-        boolean deleted = false;
-        boolean added = false;
-
-        while (rowIndex >= 0 && columnIndex >= 0) {
-
-            if (columnIndex == 0) {
-                dataAtLeft = -1;
-            } else {
-                dataAtLeft = matrix[rowIndex][columnIndex - 1];
-            }
-            if (rowIndex == 0) {
-                dataAtTop = -1;
-            } else {
-                dataAtTop = matrix[rowIndex - 1][columnIndex];
-            }
-            if (rowIndex > 0 && columnIndex > 0) {
-                dataAtDiagonal = matrix[rowIndex - 1][columnIndex - 1];
-            } else {
-                dataAtDiagonal = -1;
-            }
-            if (dataAtLeft == -1 && dataAtTop == -1 && dataAtDiagonal == -1) {
-                break;
-            }
-            data = matrix[rowIndex][columnIndex];
-
-            // case in which the character at left and right are the same,
-            // in this case none of the counters will be incremented.
-            if (columnIndex > 0 && rowIndex > 0 && left.charAt(columnIndex - 1) == right.charAt(rowIndex - 1)) {
-                columnIndex--;
-                rowIndex--;
-                continue;
-            }
-
-            // handling insert and delete cases.
-            deleted = false;
-            added = false;
-            if (data - 1 == dataAtLeft && (data <= dataAtDiagonal && data <= dataAtTop)
-                    || (dataAtDiagonal == -1 && dataAtTop == -1)) { // NOPMD
-                columnIndex--;
-                if (swapped) {
-                    addCount++;
-                    added = true;
-                } else {
-                    delCount++;
-                    deleted = true;
-                }
-            } else if (data - 1 == dataAtTop && (data <= dataAtDiagonal && data <= dataAtLeft)
-                    || (dataAtDiagonal == -1 && dataAtLeft == -1)) { // NOPMD
-                rowIndex--;
-                if (swapped) {
-                    delCount++;
-                    deleted = true;
-                } else {
-                    addCount++;
-                    added = true;
-                }
-            }
-
-            // substituted case
-            if (!added && !deleted) {
-                subCount++;
-                columnIndex--;
-                rowIndex--;
-            }
-        }
-        return new LevenshteinResults(addCount + delCount + subCount, addCount, delCount, subCount);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDistance.java
deleted file mode 100644
index 1f7d9a8..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinDistance.java
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.Arrays;
-
-/**
- * An algorithm for measuring the difference between two character sequences.
- *
- * <p>
- * This is the number of changes needed to change one sequence into another,
- * where each change is a single character modification (deletion, insertion
- * or substitution).
- * </p>
- *
- * <p>
- * This code has been adapted from Apache Commons Lang 3.3.
- * </p>
- *
- * @since 1.0
- */
-public class LevenshteinDistance implements EditDistance<Integer> {
-
-    /**
-     * Default instance.
-     */
-    private static final LevenshteinDistance DEFAULT_INSTANCE = new LevenshteinDistance();
-
-    /**
-     * Threshold.
-     */
-    private final Integer threshold;
-
-    /**
-     * <p>
-     * This returns the default instance that uses a version
-     * of the algorithm that does not use a threshold parameter.
-     * </p>
-     *
-     * @see LevenshteinDistance#getDefaultInstance()
-     */
-    public LevenshteinDistance() {
-        this(null);
-    }
-
-    /**
-     * <p>
-     * If the threshold is not null, distance calculations will be limited to a maximum length.
-     * If the threshold is null, the unlimited version of the algorithm will be used.
-     * </p>
-     *
-     * @param threshold
-     *        If this is null then distances calculations will not be limited.
-     *        This may not be negative.
-     */
-    public LevenshteinDistance(final Integer threshold) {
-        if (threshold != null && threshold < 0) {
-            throw new IllegalArgumentException("Threshold must not be negative");
-        }
-        this.threshold = threshold;
-    }
-
-    /**
-     * <p>Find the Levenshtein distance between two Strings.</p>
-     *
-     * <p>A higher score indicates a greater distance.</p>
-     *
-     * <p>The previous implementation of the Levenshtein distance algorithm
-     * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
-     *
-     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
-     * which can occur when my Java implementation is used with very large strings.<br>
-     * This implementation of the Levenshtein distance algorithm
-     * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
-     *
-     * <pre>
-     * distance.apply(null, *)             = IllegalArgumentException
-     * distance.apply(*, null)             = IllegalArgumentException
-     * distance.apply("","")               = 0
-     * distance.apply("","a")              = 1
-     * distance.apply("aaapppp", "")       = 7
-     * distance.apply("frog", "fog")       = 1
-     * distance.apply("fly", "ant")        = 3
-     * distance.apply("elephant", "hippo") = 7
-     * distance.apply("hippo", "elephant") = 7
-     * distance.apply("hippo", "zzzzzzzz") = 8
-     * distance.apply("hello", "hallo")    = 1
-     * </pre>
-     *
-     * @param left the first string, must not be null
-     * @param right the second string, must not be null
-     * @return result distance, or -1
-     * @throws IllegalArgumentException if either String input {@code null}
-     */
-    @Override
-    public Integer apply(final CharSequence left, final CharSequence right) {
-        if (threshold != null) {
-            return limitedCompare(left, right, threshold);
-        }
-        return unlimitedCompare(left, right);
-    }
-
-    /**
-     * Gets the default instance.
-     *
-     * @return the default instace
-     */
-    public static LevenshteinDistance getDefaultInstance() {
-        return DEFAULT_INSTANCE;
-    }
-
-    /**
-     * Gets the distance threshold.
-     *
-     * @return the distance threshold
-     */
-    public Integer getThreshold() {
-        return threshold;
-    }
-
-    /**
-     * Find the Levenshtein distance between two CharSequences if it's less than or
-     * equal to a given threshold.
-     *
-     * <p>
-     * This implementation follows from Algorithms on Strings, Trees and
-     * Sequences by Dan Gusfield and Chas Emerick's implementation of the
-     * Levenshtein distance algorithm from <a
-     * href="http://www.merriampark.com/ld.htm"
-     * >http://www.merriampark.com/ld.htm</a>
-     * </p>
-     *
-     * <pre>
-     * limitedCompare(null, *, *)             = IllegalArgumentException
-     * limitedCompare(*, null, *)             = IllegalArgumentException
-     * limitedCompare(*, *, -1)               = IllegalArgumentException
-     * limitedCompare("","", 0)               = 0
-     * limitedCompare("aaapppp", "", 8)       = 7
-     * limitedCompare("aaapppp", "", 7)       = 7
-     * limitedCompare("aaapppp", "", 6))      = -1
-     * limitedCompare("elephant", "hippo", 7) = 7
-     * limitedCompare("elephant", "hippo", 6) = -1
-     * limitedCompare("hippo", "elephant", 7) = 7
-     * limitedCompare("hippo", "elephant", 6) = -1
-     * </pre>
-     *
-     * @param left the first string, must not be null
-     * @param right the second string, must not be null
-     * @param threshold the target threshold, must not be negative
-     * @return result distance, or -1
-     */
-    private static int limitedCompare(CharSequence left, CharSequence right, final int threshold) { // NOPMD
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-        if (threshold < 0) {
-            throw new IllegalArgumentException("Threshold must not be negative");
-        }
-
-        /*
-         * This implementation only computes the distance if it's less than or
-         * equal to the threshold value, returning -1 if it's greater. The
-         * advantage is performance: unbounded distance is O(nm), but a bound of
-         * k allows us to reduce it to O(km) time by only computing a diagonal
-         * stripe of width 2k + 1 of the cost table. It is also possible to use
-         * this to compute the unbounded Levenshtein distance by starting the
-         * threshold at 1 and doubling each time until the distance is found;
-         * this is O(dm), where d is the distance.
-         *
-         * One subtlety comes from needing to ignore entries on the border of
-         * our stripe eg. p[] = |#|#|#|* d[] = *|#|#|#| We must ignore the entry
-         * to the left of the leftmost member We must ignore the entry above the
-         * rightmost member
-         *
-         * Another subtlety comes from our stripe running off the matrix if the
-         * strings aren't of the same size. Since string s is always swapped to
-         * be the shorter of the two, the stripe will always run off to the
-         * upper right instead of the lower left of the matrix.
-         *
-         * As a concrete example, suppose s is of length 5, t is of length 7,
-         * and our threshold is 1. In this case we're going to walk a stripe of
-         * length 3. The matrix would look like so:
-         *
-         * <pre>
-         *    1 2 3 4 5
-         * 1 |#|#| | | |
-         * 2 |#|#|#| | |
-         * 3 | |#|#|#| |
-         * 4 | | |#|#|#|
-         * 5 | | | |#|#|
-         * 6 | | | | |#|
-         * 7 | | | | | |
-         * </pre>
-         *
-         * Note how the stripe leads off the table as there is no possible way
-         * to turn a string of length 5 into one of length 7 in edit distance of
-         * 1.
-         *
-         * Additionally, this implementation decreases memory usage by using two
-         * single-dimensional arrays and swapping them back and forth instead of
-         * allocating an entire n by m matrix. This requires a few minor
-         * changes, such as immediately returning when it's detected that the
-         * stripe has run off the matrix and initially filling the arrays with
-         * large values so that entries we don't compute are ignored.
-         *
-         * See Algorithms on Strings, Trees and Sequences by Dan Gusfield for
-         * some discussion.
-         */
-
-        int n = left.length(); // length of left
-        int m = right.length(); // length of right
-
-        // if one string is empty, the edit distance is necessarily the length
-        // of the other
-        if (n == 0) {
-            return m <= threshold ? m : -1;
-        } else if (m == 0) {
-            return n <= threshold ? n : -1;
-        }
-
-        if (n > m) {
-            // swap the two strings to consume less memory
-            final CharSequence tmp = left;
-            left = right;
-            right = tmp;
-            n = m;
-            m = right.length();
-        }
-
-        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
-        int[] d = new int[n + 1]; // cost array, horizontally
-        int[] tempD; // placeholder to assist in swapping p and d
-
-        // fill in starting table values
-        final int boundary = Math.min(n, threshold) + 1;
-        for (int i = 0; i < boundary; i++) {
-            p[i] = i;
-        }
-        // these fills ensure that the value above the rightmost entry of our
-        // stripe will be ignored in following loop iterations
-        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
-        Arrays.fill(d, Integer.MAX_VALUE);
-
-        // iterates through t
-        for (int j = 1; j <= m; j++) {
-            final char rightJ = right.charAt(j - 1); // jth character of right
-            d[0] = j;
-
-            // compute stripe indices, constrain to array size
-            final int min = Math.max(1, j - threshold);
-            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(
-                    n, j + threshold);
-
-            // the stripe may lead off of the table if s and t are of different
-            // sizes
-            if (min > max) {
-                return -1;
-            }
-
-            // ignore entry left of leftmost
-            if (min > 1) {
-                d[min - 1] = Integer.MAX_VALUE;
-            }
-
-            // iterates through [min, max] in s
-            for (int i = min; i <= max; i++) {
-                if (left.charAt(i - 1) == rightJ) {
-                    // diagonally left and up
-                    d[i] = p[i - 1];
-                } else {
-                    // 1 + minimum of cell to the left, to the top, diagonally
-                    // left and up
-                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
-                }
-            }
-
-            // copy current distance counts to 'previous row' distance counts
-            tempD = p;
-            p = d;
-            d = tempD;
-        }
-
-        // if p[n] is greater than the threshold, there's no guarantee on it
-        // being the correct
-        // distance
-        if (p[n] <= threshold) {
-            return p[n];
-        }
-        return -1;
-    }
-
-    /**
-     * <p>Find the Levenshtein distance between two Strings.</p>
-     *
-     * <p>A higher score indicates a greater distance.</p>
-     *
-     * <p>The previous implementation of the Levenshtein distance algorithm
-     * was from <a href="https://web.archive.org/web/20120526085419/http://www.merriampark.com/ldjava.htm">
-     * https://web.archive.org/web/20120526085419/http://www.merriampark.com/ldjava.htm</a></p>
-     *
-     * <p>This implementation only need one single-dimensional arrays of length s.length() + 1</p>
-     *
-     * <pre>
-     * unlimitedCompare(null, *)             = IllegalArgumentException
-     * unlimitedCompare(*, null)             = IllegalArgumentException
-     * unlimitedCompare("","")               = 0
-     * unlimitedCompare("","a")              = 1
-     * unlimitedCompare("aaapppp", "")       = 7
-     * unlimitedCompare("frog", "fog")       = 1
-     * unlimitedCompare("fly", "ant")        = 3
-     * unlimitedCompare("elephant", "hippo") = 7
-     * unlimitedCompare("hippo", "elephant") = 7
-     * unlimitedCompare("hippo", "zzzzzzzz") = 8
-     * unlimitedCompare("hello", "hallo")    = 1
-     * </pre>
-     *
-     * @param left the first String, must not be null
-     * @param right the second String, must not be null
-     * @return result distance, or -1
-     * @throws IllegalArgumentException if either String input {@code null}
-     */
-    private static int unlimitedCompare(CharSequence left, CharSequence right) {
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Strings must not be null");
-        }
-
-        /*
-           This implementation use two variable to record the previous cost counts,
-           So this implementation use less memory than previous impl.
-         */
-
-        int n = left.length(); // length of left
-        int m = right.length(); // length of right
-
-        if (n == 0) {
-            return m;
-        } else if (m == 0) {
-            return n;
-        }
-
-        if (n > m) {
-            // swap the input strings to consume less memory
-            final CharSequence tmp = left;
-            left = right;
-            right = tmp;
-            n = m;
-            m = right.length();
-        }
-
-        int[] p = new int[n + 1];
-
-        // indexes into strings left and right
-        int i; // iterates through left
-        int j; // iterates through right
-        int upperLeft;
-        int upper;
-
-        char rightJ; // jth character of right
-        int cost; // cost
-
-        for (i = 0; i <= n; i++) {
-            p[i] = i;
-        }
-
-        for (j = 1; j <= m; j++) {
-            upperLeft = p[0];
-            rightJ = right.charAt(j - 1);
-            p[0] = j;
-
-            for (i = 1; i <= n; i++) {
-                upper = p[i];
-                cost = left.charAt(i - 1) == rightJ ? 0 : 1;
-                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
-                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperLeft + cost);
-                upperLeft = upper;
-            }
-        }
-
-        return p[n];
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinResults.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinResults.java b/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinResults.java
deleted file mode 100644
index 4e0c272..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/LevenshteinResults.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.Objects;
-
-/**
- * Container class to store Levenshtein distance between two character sequences.
- *
- * <p>Stores the count of insert, deletion and substitute operations needed to
- * change one character sequence into another.</p>
- *
- * <p>This class is immutable.</p>
- *
- * @since 1.0
- */
-public class LevenshteinResults {
-    /**
-     * Edit distance.
-     */
-    private final Integer distance;
-    /**
-     * Insert character count.
-     */
-    private final Integer insertCount;
-    /**
-     * Delete character count.
-     */
-    private final Integer deleteCount;
-    /**
-     * Substitute character count.
-     */
-    private final Integer substituteCount;
-
-    /**
-     * Create the results for a detailed Levenshtein distance.
-     *
-     * @param distance distance between two character sequences.
-     * @param insertCount insert character count
-     * @param deleteCount delete character count
-     * @param substituteCount substitute character count
-     */
-    public LevenshteinResults(final Integer distance, final Integer insertCount, final Integer deleteCount,
-            final Integer substituteCount) {
-        this.distance = distance;
-        this.insertCount = insertCount;
-        this.deleteCount = deleteCount;
-        this.substituteCount = substituteCount;
-    }
-
-    /**
-     * Get the distance between two character sequences.
-     *
-     * @return distance between two character sequence
-     */
-    public Integer getDistance() {
-        return distance;
-    }
-
-    /**
-     * Get the number of insertion needed to change one character sequence into another.
-     *
-     * @return insert character count
-     */
-    public Integer getInsertCount() {
-        return insertCount;
-    }
-
-    /**
-     * Get the number of character deletion needed to change one character sequence to other.
-     *
-     * @return delete character count
-     */
-    public Integer getDeleteCount() {
-        return deleteCount;
-    }
-
-    /**
-     * Get the number of character substitution needed to change one character sequence into another.
-     *
-     * @return substitute character count
-     */
-    public Integer getSubstituteCount() {
-        return substituteCount;
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        final LevenshteinResults result = (LevenshteinResults) o;
-        return Objects.equals(distance, result.distance) && Objects.equals(insertCount, result.insertCount)
-                && Objects.equals(deleteCount, result.deleteCount)
-                && Objects.equals(substituteCount, result.substituteCount);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(distance, insertCount, deleteCount, substituteCount);
-    }
-
-    @Override
-    public String toString() {
-        return "Distance: " + distance + ", Insert: " + insertCount + ", Delete: " + deleteCount + ", Substitute: "
-                + substituteCount;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequence.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequence.java b/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequence.java
deleted file mode 100644
index b985a67..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequence.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * A similarity algorithm indicating the length of the longest common subsequence between two strings.
- *
- * <p>
- * The Longest common subsequence algorithm returns the length of the longest subsequence that two strings have in
- * common. Two strings that are entirely different, return a value of 0, and two strings that return a value
- * of the commonly shared length implies that the strings are completely the same in value and position.
- * <i>Note.</i>  Generally this algorithm is fairly inefficient, as for length <i>m</i>, <i>n</i> of the input
- * <code>CharSequence</code>'s <code>left</code> and <code>right</code> respectively, the runtime of the
- * algorithm is <i>O(m*n)</i>.
- * </p>
- *
- * <p>
- * This implementation is based on the Longest Commons Substring algorithm
- * from <a href="https://en.wikipedia.org/wiki/Longest_common_subsequence_problem">
- * https://en.wikipedia.org/wiki/Longest_common_subsequence_problem</a>.
- * </p>
- *
- * <p>For further reading see:</p>
- *
- * <p>Lothaire, M. <i>Applied combinatorics on words</i>. New York: Cambridge U Press, 2005. <b>12-13</b></p>
- *
- * @since 1.0
- */
-public class LongestCommonSubsequence implements SimilarityScore<Integer> {
-
-    /**
-     * Calculates longestCommonSubsequence similarity score of two <code>CharSequence</code>'s passed as
-     * input.
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return longestCommonSubsequenceLength
-     * @throws IllegalArgumentException
-     *             if either String input {@code null}
-     */
-    @Override
-    public Integer apply(final CharSequence left, final CharSequence right) {
-        // Quick return for invalid inputs
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Inputs must not be null");
-        }
-        return logestCommonSubsequence(left, right).length();
-    }
-
-    /**
-     *
-     * Computes the longestCommonSubsequence between the two <code>CharSequence</code>'s passed as
-     * input.
-     *
-     * <p>
-     * Note, a substring and
-     * subsequence are not necessarily the same thing. Indeed, <code>abcxyzqrs</code> and
-     * <code>xyzghfm</code> have both the same common substring and subsequence, namely <code>xyz</code>. However,
-     * <code>axbyczqrs</code> and <code>abcxyzqtv</code> have the longest common subsequence <code>xyzq</code> because a
-     * subsequence need not have adjacent characters.
-     * </p>
-     *
-     * <p>
-     * For reference, we give the definition of a subsequence for the reader: a <i>subsequence</i> is a sequence that
-     * can be derived from another sequence by deleting some elements without changing the order of the remaining
-     * elements.
-     * </p>
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return lcsLengthArray
-     * @throws IllegalArgumentException
-     *             if either String input {@code null}
-     */
-    public CharSequence logestCommonSubsequence(final CharSequence left, final CharSequence right) {
-        // Quick return
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Inputs must not be null");
-        }
-        StringBuilder longestCommonSubstringArray = new StringBuilder(Math.max(left.length(), right.length()));
-        int[][] lcsLengthArray = longestCommonSubstringLengthArray(left, right);
-        int i = left.length() - 1;
-        int j = right.length() - 1;
-        int k = lcsLengthArray[left.length()][right.length()] - 1;
-        while (k >= 0) {
-            if (left.charAt(i) == right.charAt(j)) {
-                longestCommonSubstringArray.append(left.charAt(i));
-                i = i - 1;
-                j = j - 1;
-                k = k - 1;
-            } else if (lcsLengthArray[i + 1][j] < lcsLengthArray[i][j + 1]) {
-                i = i - 1;
-            } else {
-                j = j - 1;
-            }
-        }
-        return longestCommonSubstringArray.reverse().toString();
-    }
-
-    /**
-     *
-     * Computes the lcsLengthArray for the sake of doing the actual lcs calculation. This is the
-     * dynamic programming portion of the algorithm, and is the reason for the runtime complexity being
-     * O(m*n), where m=left.length() and n=right.length().
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return lcsLengthArray
-     */
-    public int[][] longestCommonSubstringLengthArray(final CharSequence left, final CharSequence right) {
-        int[][] lcsLengthArray = new int[left.length() + 1][right.length() + 1];
-        for (int i = 0; i < left.length(); i++) {
-            for (int j = 0; j < right.length(); j++) {
-                if (i == 0) {
-                    lcsLengthArray[i][j] = 0;
-                }
-                if (j == 0) {
-                    lcsLengthArray[i][j] = 0;
-                }
-                if (left.charAt(i) == right.charAt(j)) {
-                    lcsLengthArray[i + 1][j + 1] = lcsLengthArray[i][j] + 1;
-                } else {
-                    lcsLengthArray[i + 1][j + 1] = Math.max(lcsLengthArray[i + 1][j], lcsLengthArray[i][j + 1]);
-                }
-            }
-        }
-        return lcsLengthArray;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistance.java b/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistance.java
deleted file mode 100644
index 46a73a3..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistance.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * An edit distance algorithm based on the length of the longest common subsequence between two strings.
- *
- * <p>
- * This code is directly based upon the implementation in {@link LongestCommonSubsequence}.
- * </p>
- *
- * <p>
- * For reference see: <a href="https://en.wikipedia.org/wiki/Longest_common_subsequence_problem">
- * https://en.wikipedia.org/wiki/Longest_common_subsequence_problem</a>.
- * </p>
- *
- * <p>For further reading see:</p>
- *
- * <p>Lothaire, M. <i>Applied combinatorics on words</i>. New York: Cambridge U Press, 2005. <b>12-13</b></p>
- *
- * @since 1.0
- */
-public class LongestCommonSubsequenceDistance implements EditDistance<Integer> {
-
-    /**
-     * Object for calculating the longest common subsequence that we can then normalize in apply.
-     */
-    private final LongestCommonSubsequence longestCommonSubsequence = new LongestCommonSubsequence();
-
-    /**
-     * Calculates an edit distance between two <code>CharSequence</code>'s <code>left</code> and
-     * <code>right</code> as: <code>left.length() + right.length() - 2 * LCS(left, right)</code>, where
-     * <code>LCS</code> is given in {@link LongestCommonSubsequence#apply(CharSequence, CharSequence)}.
-     *
-     * @param left first character sequence
-     * @param right second character sequence
-     * @return distance
-     * @throws IllegalArgumentException
-     *             if either String input {@code null}
-     */
-    @Override
-    public Integer apply(final CharSequence left, final CharSequence right) {
-        // Quick return for invalid inputs
-        if (left == null || right == null) {
-            throw new IllegalArgumentException("Inputs must not be null");
-        }
-        return left.length() + right.length() - 2 * longestCommonSubsequence.apply(left, right);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/RegexTokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/RegexTokenizer.java b/src/main/java/org/apache/commons/text/beta/similarity/RegexTokenizer.java
deleted file mode 100644
index 014ace8..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/RegexTokenizer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A simple word tokenizer that utilizes regex to find words. It applies a regex
- * {@code}(\w)+{@code} over the input text to extract words from a given character
- * sequence.
- *
- * @since 1.0
- */
-class RegexTokenizer implements Tokenizer<CharSequence> {
-
-    /**
-     * {@inheritDoc}
-     *
-     * @throws IllegalArgumentException if the input text is blank
-     */
-    @Override
-    public CharSequence[] tokenize(final CharSequence text) {
-        if (text == null || text.toString().trim().equals("")) {
-            throw new IllegalArgumentException("Invalid text");
-        }
-        final Pattern pattern = Pattern.compile("(\\w)+");
-        final Matcher matcher = pattern.matcher(text.toString());
-        final List<String> tokens = new ArrayList<>();
-        while (matcher.find()) {
-            tokens.add(matcher.group(0));
-        }
-        return tokens.toArray(new String[0]);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScore.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScore.java b/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScore.java
deleted file mode 100644
index f92aefb..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScore.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * Interface for the concept of a string similarity score.
- *
- * <p>
- * A string similarity score is intended to have <i>some</i> of the properties of a metric, yet
- * allowing for exceptions, namely the Jaro-Winkler similarity score.
- * </p>
- * <p>
- * We Define a SimilarityScore to be a function <code>d: [X * X] -&gt; [0, INFINITY)</code> with the
- * following properties:
- * </p>
- * <ul>
- *     <li><code>d(x,y) &gt;= 0</code>, non-negativity or separation axiom</li>
- *     <li><code>d(x,y) == d(y,x)</code>, symmetry.</li>
- * </ul>
- *
- * <p>
- * Notice, these are two of the properties that contribute to d being a metric.
- * </p>
- *
- *
- * <p>
- * Further, this intended to be BiFunction&lt;CharSequence, CharSequence, R&gt;.
- * The <code>apply</code> method
- * accepts a pair of {@link CharSequence} parameters
- * and returns an <code>R</code> type similarity score. We have ommitted the explicit
- * statement of extending BiFunction due to it only being implemented in Java 1.8, and we
- * wish to maintain Java 1.7 compatibility.
- * </p>
- *
- * @param <R> The type of similarity score unit used by this EditDistance.
- * @since 1.0
- */
-public interface SimilarityScore<R> {
-
-    /**
-     * Compares two CharSequences.
-     *
-     * @param left the first CharSequence
-     * @param right the second CharSequence
-     * @return the similarity score between two CharSequences
-     */
-    R apply(CharSequence left, CharSequence right);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScoreFrom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScoreFrom.java b/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScoreFrom.java
deleted file mode 100644
index dd66f73..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/SimilarityScoreFrom.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * <p>
- * This stores a {@link SimilarityScore} implementation and a {@link CharSequence} "left" string.
- * The {@link #apply(CharSequence right)} method accepts the "right" string and invokes the
- * comparison function for the pair of strings.
- * </p>
- *
- * <p>
- * The following is an example which finds the most similar string:
- * </p>
- * <pre>
- * SimilarityScore&lt;Integer&gt; similarityScore = new LevenshteinDistance();
- * String target = "Apache";
- * SimilarityScoreFrom&lt;Integer&gt; similarityScoreFrom =
- *     new SimilarityScoreFrom&lt;Integer&gt;(similarityScore, target);
- * String mostSimilar = null;
- * Integer shortestDistance = null;
- *
- * for (String test : new String[] { "Appaloosa", "a patchy", "apple" }) {
- *     Integer distance = similarityScoreFrom.apply(test);
- *     if (shortestDistance == null || distance &lt; shortestDistance) {
- *         shortestDistance = distance;
- *         mostSimilar = test;
- *     }
- * }
- *
- * System.out.println("The string most similar to \"" + target + "\" "
- *     + "is \"" + mostSimilar + "\" because "
- *     + "its distance is only " + shortestDistance + ".");
- * </pre>
- *
- * @param <R> This is the type of similarity score used by the SimilarityScore function.
- * @since 1.0
- */
-public class SimilarityScoreFrom<R> {
-
-    /**
-     * Similarity score.
-     */
-    private final SimilarityScore<R> similarityScore;
-    /**
-     * Left parameter used in distance function.
-     */
-    private final CharSequence left;
-
-    /**
-     * <p>This accepts the similarity score implementation and the "left" string.</p>
-     *
-     * @param similarityScore This may not be null.
-     * @param left This may be null here,
-     *             but the SimilarityScore#compare(CharSequence left, CharSequence right)
-     *             implementation may not accept nulls.
-     */
-    public SimilarityScoreFrom(final SimilarityScore<R> similarityScore, final CharSequence left) {
-        if (similarityScore == null) {
-            throw new IllegalArgumentException("The edit distance may not be null.");
-        }
-
-        this.similarityScore = similarityScore;
-        this.left = left;
-    }
-
-    /**
-     * <p>
-     * This compares "left" field against the "right" parameter
-     * using the "similarity score" implementation.
-     * </p>
-     *
-     * @param right the second CharSequence
-     * @return the similarity score between two CharSequences
-     */
-    public R apply(final CharSequence right) {
-        return similarityScore.apply(left, right);
-    }
-
-    /**
-     * Gets the left parameter.
-     *
-     * @return the left parameter
-     */
-    public CharSequence getLeft() {
-        return left;
-    }
-
-    /**
-     * Gets the edit distance.
-     *
-     * @return the edit distance
-     */
-    public SimilarityScore<R> getSimilarityScore() {
-        return similarityScore;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/Tokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/Tokenizer.java b/src/main/java/org/apache/commons/text/beta/similarity/Tokenizer.java
deleted file mode 100644
index 08e1ecc..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/Tokenizer.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-/**
- * A tokenizer. Can produce arrays of tokens from a given type.
- *
- * @param <T> given type
- * @since 1.0
- */
-interface Tokenizer<T> {
-
-    /**
-     * Returns an array of tokens.
-     *
-     * @param text input text
-     * @return array of tokens
-     */
-    T[] tokenize(CharSequence text);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/similarity/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/similarity/package-info.java b/src/main/java/org/apache/commons/text/beta/similarity/package-info.java
deleted file mode 100644
index de5a313..0000000
--- a/src/main/java/org/apache/commons/text/beta/similarity/package-info.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * <p>Provides algorithms for string similarity.</p>
- *
- * <p>The algorithms that implement the EditDistance interface follow the same
- * simple principle: the more similar (closer) strings are, lower is the distance.
- * For example, the words house and hose are closer than house and trousers.</p>
- *
- * <p>The following algorithms are available at the moment:</p>
- *
- * <ul>
- * <li>{@link org.apache.commons.text.beta.similarity.CosineDistance Cosine Distance}</li>
- * <li>{@link org.apache.commons.text.beta.similarity.CosineSimilarity Cosine Similarity}</li>
- * <li>{@link org.apache.commons.text.beta.similarity.FuzzyScore Fuzzy Score}</li>
- * <li>{@link org.apache.commons.text.beta.similarity.HammingDistance Hamming Distance}</li>
- * <li>{@link org.apache.commons.text.beta.similarity.JaroWinklerDistance Jaro-Winkler Distance}</li>
- * <li>{@link org.apache.commons.text.beta.similarity.LevenshteinDistance Levenshtein Distance}</li>
- * <li>{@link org.apache.commons.text.beta.similarity.LongestCommonSubsequenceDistance
- * Longest Commons Subsequence Distance}</li>
- * </ul>
- *
- * <p>The {@link org.apache.commons.text.beta.similarity.CosineDistance Cosine Distance}
- * utilises a {@link org.apache.commons.text.beta.similarity.RegexTokenizer regular expression tokenizer (\w+)}.
- * And the {@link org.apache.commons.text.beta.similarity.LevenshteinDistance Levenshtein Distance}'s
- * behaviour can be changed to take into consideration a maximum throughput.</p>
- *
- * @since 1.0
- */
-package org.apache.commons.text.beta.similarity;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/AggregateTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/AggregateTranslator.java b/src/main/java/org/apache/commons/text/beta/translate/AggregateTranslator.java
deleted file mode 100644
index 897790b..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/AggregateTranslator.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Executes a sequence of translators one after the other. Execution ends whenever 
- * the first translator consumes codepoints from the input.
- *
- * @since 1.0
- */
-public class AggregateTranslator extends CharSequenceTranslator {
-
-    private final List<CharSequenceTranslator> translators = new ArrayList<>();
-
-    /**
-     * Specify the translators to be used at creation time. 
-     *
-     * @param translators CharSequenceTranslator array to aggregate
-     */
-    public AggregateTranslator(final CharSequenceTranslator... translators) {
-        if (translators != null) {
-            for (CharSequenceTranslator translator : translators) {
-                if (translator != null) {
-                    this.translators.add(translator);
-                }
-            }
-        }
-    }
-
-    /**
-     * The first translator to consume codepoints from the input is the 'winner'. 
-     * Execution stops with the number of consumed codepoints being returned. 
-     * {@inheritDoc}
-     */
-    @Override
-    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        for (final CharSequenceTranslator translator : translators) {
-            final int consumed = translator.translate(input, index, out);
-            if(consumed != 0) {
-                return consumed;
-            }
-        }
-        return 0;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/CharSequenceTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/CharSequenceTranslator.java b/src/main/java/org/apache/commons/text/beta/translate/CharSequenceTranslator.java
deleted file mode 100644
index 1025528..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/CharSequenceTranslator.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Locale;
-
-/**
- * An API for translating text. 
- * Its core use is to escape and unescape text. Because escaping and unescaping 
- * is completely contextual, the API does not present two separate signatures.
- *
- * @since 1.0
- */
-public abstract class CharSequenceTranslator {
-
-    static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
-
-    /**
-     * Translate a set of codepoints, represented by an int index into a CharSequence, 
-     * into another set of codepoints. The number of codepoints consumed must be returned, 
-     * and the only IOExceptions thrown must be from interacting with the Writer so that 
-     * the top level API may reliably ignore StringWriter IOExceptions. 
-     *
-     * @param input CharSequence that is being translated
-     * @param index int representing the current point of translation
-     * @param out Writer to translate the text to
-     * @return int count of codepoints consumed
-     * @throws IOException if and only if the Writer produces an IOException
-     */
-    public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
-
-    /**
-     * Helper for non-Writer usage. 
-     * @param input CharSequence to be translated
-     * @return String output of translation
-     */
-    public final String translate(final CharSequence input) {
-        if (input == null) {
-            return null;
-        }
-        try {
-            final StringWriter writer = new StringWriter(input.length() * 2);
-            translate(input, writer);
-            return writer.toString();
-        } catch (final IOException ioe) {
-            // this should never ever happen while writing to a StringWriter
-            throw new RuntimeException(ioe);
-        }
-    }
-
-    /**
-     * Translate an input onto a Writer. This is intentionally final as its algorithm is 
-     * tightly coupled with the abstract method of this class. 
-     *
-     * @param input CharSequence that is being translated
-     * @param out Writer to translate the text to
-     * @throws IOException if and only if the Writer produces an IOException
-     */
-    public final void translate(final CharSequence input, final Writer out) throws IOException {
-        if (out == null) {
-            throw new IllegalArgumentException("The Writer must not be null");
-        }
-        if (input == null) {
-            return;
-        }
-        int pos = 0;
-        final int len = input.length();
-        while (pos < len) {
-            final int consumed = translate(input, pos, out);
-            if (consumed == 0) {
-                // inlined implementation of Character.toChars(Character.codePointAt(input, pos))
-                // avoids allocating temp char arrays and duplicate checks
-                final char c1 = input.charAt(pos);
-                out.write(c1);
-                pos++;
-                if (Character.isHighSurrogate(c1) && pos < len) {
-                    final char c2 = input.charAt(pos);
-                    if (Character.isLowSurrogate(c2)) {
-                      out.write(c2);
-                      pos++;
-                    }
-                }
-                continue;
-            }
-            // contract with translators is that they have to understand codepoints
-            // and they just took care of a surrogate pair
-            for (int pt = 0; pt < consumed; pt++) {
-                pos += Character.charCount(Character.codePointAt(input, pos));
-            }
-        }
-    }
-
-    /**
-     * Helper method to create a merger of this translator with another set of 
-     * translators. Useful in customizing the standard functionality.
-     *
-     * @param translators CharSequenceTranslator array of translators to merge with this one
-     * @return CharSequenceTranslator merging this translator with the others
-     */
-    public final CharSequenceTranslator with(final CharSequenceTranslator... translators) {
-        final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1];
-        newArray[0] = this;
-        System.arraycopy(translators, 0, newArray, 1, translators.length);
-        return new AggregateTranslator(newArray);
-    }
-
-    /**
-     * <p>Returns an upper case hexadecimal <code>String</code> for the given
-     * character.</p>
-     *
-     * @param codepoint The codepoint to convert.
-     * @return An upper case hexadecimal <code>String</code>
-     */
-    public static String hex(final int codepoint) {
-        return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/CodePointTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/CodePointTranslator.java b/src/main/java/org/apache/commons/text/beta/translate/CodePointTranslator.java
deleted file mode 100644
index 83386db..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/CodePointTranslator.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Helper subclass to CharSequenceTranslator to allow for translations that 
- * will replace up to one character at a time.
- *
- * @since 1.0
- */
-public abstract class CodePointTranslator extends CharSequenceTranslator {
-
-    /**
-     * Implementation of translate that maps onto the abstract translate(int, Writer) method. 
-     * {@inheritDoc}
-     */
-    @Override
-    public final int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        final int codepoint = Character.codePointAt(input, index);
-        final boolean consumed = translate(codepoint, out);
-        return consumed ? 1 : 0; 
-    }
-
-    /**
-     * Translate the specified codepoint into another. 
-     * 
-     * @param codepoint int character input to translate
-     * @param out Writer to optionally push the translated output to
-     * @return boolean as to whether translation occurred or not
-     * @throws IOException if and only if the Writer produces an IOException
-     */
-    public abstract boolean translate(int codepoint, Writer out) throws IOException;
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/CsvTranslators.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/CsvTranslators.java b/src/main/java/org/apache/commons/text/beta/translate/CsvTranslators.java
deleted file mode 100644
index e1dbf83..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/CsvTranslators.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import org.apache.commons.lang3.CharUtils;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * This class holds inner classes for escaping/unescaping Comma Separated Values.
- */
-public class CsvTranslators {
-
-    private static final char CSV_DELIMITER = ',';
-    private static final char CSV_QUOTE = '"';
-    private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
-    private static final String CSV_ESCAPED_QUOTE_STR = CSV_QUOTE_STR + CSV_QUOTE_STR;
-    private static final char[] CSV_SEARCH_CHARS =
-            new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
-
-    private CsvTranslators() { }
-
-    /**
-     * Translator for escaping Comma Separated Values.
-     */
-    public static class CsvEscaper extends SinglePassTranslator {
-
-        @Override
-        void translateWhole(final CharSequence input, final Writer out) throws IOException {
-            final String inputSting = input.toString();
-            if (StringUtils.containsNone(inputSting, CSV_SEARCH_CHARS)) {
-                out.write(inputSting);
-            } else {
-                // input needs quoting
-                out.write(CSV_QUOTE);
-                out.write(StringUtils.replace(inputSting, CSV_QUOTE_STR, CSV_ESCAPED_QUOTE_STR));
-                out.write(CSV_QUOTE);
-            }
-        }
-    }
-
-    /**
-     * Translator for unescaping escaped Comma Separated Value entries.
-     */
-    public static class CsvUnescaper extends SinglePassTranslator {
-
-        @Override
-        void translateWhole(final CharSequence input, final Writer out) throws IOException {
-            // is input not quoted?
-            if (input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE) {
-                out.write(input.toString());
-                return;
-            }
-
-            // strip quotes
-            final String quoteless = input.subSequence(1, input.length() - 1).toString();
-
-            if (StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS)) {
-                // deal with escaped quotes; ie) ""
-                out.write(StringUtils.replace(quoteless, CSV_ESCAPED_QUOTE_STR, CSV_QUOTE_STR));
-            } else {
-                out.write(input.toString());
-            }
-        }
-    }
-}
\ No newline at end of file


[08/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StrSubstitutorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StrSubstitutorTest.java b/src/test/java/org/apache/commons/text/beta/StrSubstitutorTest.java
deleted file mode 100644
index f2cddd2..0000000
--- a/src/test/java/org/apache/commons/text/beta/StrSubstitutorTest.java
+++ /dev/null
@@ -1,740 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import org.apache.commons.lang3.mutable.MutableObject;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Test class for {@link StrSubstitutor}.
- */
-public class StrSubstitutorTest {
-
-    private Map<String, String> values;
-
-    @Before
-    public void setUp() throws Exception {
-        values = new HashMap<>();
-        values.put("animal", "quick brown fox");
-        values.put("target", "lazy dog");
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        values = null;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Tests simple key replace.
-     */
-    @Test
-    public void testReplaceSimple() {
-        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests simple key replace.
-     */
-    @Test
-    public void testReplaceSolo() {
-        doTestReplace("quick brown fox", "${animal}", false);
-    }
-
-    /**
-     * Tests replace with no variables.
-     */
-    @Test
-    public void testReplaceNoVariables() {
-        doTestNoReplace("The balloon arrived.");
-    }
-
-    /**
-     * Tests replace with null.
-     */
-    @Test
-    public void testReplaceNull() {
-        doTestNoReplace(null);
-    }
-
-    /**
-     * Tests replace with null.
-     */
-    @Test
-    public void testReplaceEmpty() {
-        doTestNoReplace("");
-    }
-
-    /**
-     * Tests key replace changing map after initialization (not recommended).
-     */
-    @Test
-    public void testReplaceChangedMap() {
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        values.put("target", "moon");
-        assertEquals("The quick brown fox jumps over the moon.", sub.replace("The ${animal} jumps over the ${target}."));
-    }
-
-    /**
-     * Tests unknown key replace.
-     */
-    @Test
-    public void testReplaceUnknownKey() {
-        doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true);
-        doTestReplace("The ${person} jumps over the lazy dog. 1234567890.", "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true);
-    }
-
-    /**
-     * Tests adjacent keys.
-     */
-    @Test
-    public void testReplaceAdjacentAtStart() {
-        values.put("code", "GBP");
-        values.put("amount", "12.50");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged"));
-    }
-
-    /**
-     * Tests adjacent keys.
-     */
-    @Test
-    public void testReplaceAdjacentAtEnd() {
-        values.put("code", "GBP");
-        values.put("amount", "12.50");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}"));
-    }
-
-    /**
-     * Tests simple recursive replace.
-     */
-    @Test
-    public void testReplaceRecursive() {
-        values.put("animal", "${critter}");
-        values.put("target", "${pet}");
-        values.put("pet", "${petCharacteristic} dog");
-        values.put("petCharacteristic", "lazy");
-        values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
-        values.put("critterSpeed", "quick");
-        values.put("critterColor", "brown");
-        values.put("critterType", "fox");
-        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
-
-        values.put("pet", "${petCharacteristicUnknown:-lazy} dog");
-        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests escaping.
-     */
-    @Test
-    public void testReplaceEscaping() {
-        doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests escaping.
-     */
-    @Test
-    public void testReplaceSoloEscaping() {
-        doTestReplace("${animal}", "$${animal}", false);
-    }
-
-    /**
-     * Tests complex escaping.
-     */
-    @Test
-    public void testReplaceComplexEscaping() {
-        doTestReplace("The ${quick brown fox} jumps over the lazy dog.", "The $${${animal}} jumps over the ${target}.", true);
-        doTestReplace("The ${quick brown fox} jumps over the lazy dog. ${1234567890}.", "The $${${animal}} jumps over the ${target}. $${${undefined.number:-1234567890}}.", true);
-    }
-
-    /**
-     * Tests when no prefix or suffix.
-     */
-    @Test
-    public void testReplaceNoPrefixNoSuffix() {
-        doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests when no incomplete prefix.
-     */
-    @Test
-    public void testReplaceIncompletePrefix() {
-        doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests when prefix but no suffix.
-     */
-    @Test
-    public void testReplacePrefixNoSuffix() {
-        doTestReplace("The ${animal jumps over the ${target} lazy dog.", "The ${animal jumps over the ${target} ${target}.", true);
-    }
-
-    /**
-     * Tests when suffix but no prefix.
-     */
-    @Test
-    public void testReplaceNoPrefixSuffix() {
-        doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests when no variable name.
-     */
-    @Test
-    public void testReplaceEmptyKeys() {
-        doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true);
-        doTestReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true);
-    }
-
-    /**
-     * Tests replace creates output same as input.
-     */
-    @Test
-    public void testReplaceToIdentical() {
-        values.put("animal", "$${${thing}}");
-        values.put("thing", "animal");
-        doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true);
-    }
-
-    /**
-     * Tests a cyclic replace operation.
-     * The cycle should be detected and cause an exception to be thrown.
-     */
-    @Test
-    public void testCyclicReplacement() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("animal", "${critter}");
-        map.put("target", "${pet}");
-        map.put("pet", "${petCharacteristic} dog");
-        map.put("petCharacteristic", "lazy");
-        map.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
-        map.put("critterSpeed", "quick");
-        map.put("critterColor", "brown");
-        map.put("critterType", "${animal}");
-        StrSubstitutor sub = new StrSubstitutor(map);
-        try {
-            sub.replace("The ${animal} jumps over the ${target}.");
-            fail("Cyclic replacement was not detected!");
-        } catch (final IllegalStateException ex) {
-            // expected
-        }
-
-        // also check even when default value is set.
-        map.put("critterType", "${animal:-fox}");
-        sub = new StrSubstitutor(map);
-        try {
-            sub.replace("The ${animal} jumps over the ${target}.");
-            fail("Cyclic replacement was not detected!");
-        } catch (final IllegalStateException ex) {
-            // expected
-        }
-    }
-
-    /**
-     * Tests interpolation with weird boundary patterns.
-     */
-    @Test
-    public void testReplaceWeirdPattens() {
-        doTestNoReplace("");
-        doTestNoReplace("${}");
-        doTestNoReplace("${ }");
-        doTestNoReplace("${\t}");
-        doTestNoReplace("${\n}");
-        doTestNoReplace("${\b}");
-        doTestNoReplace("${");
-        doTestNoReplace("$}");
-        doTestNoReplace("}");
-        doTestNoReplace("${}$");
-        doTestNoReplace("${${");
-        doTestNoReplace("${${}}");
-        doTestNoReplace("${$${}}");
-        doTestNoReplace("${$$${}}");
-        doTestNoReplace("${$$${$}}");
-        doTestNoReplace("${${}}");
-        doTestNoReplace("${${ }}");
-    }
-
-    /**
-     * Tests simple key replace.
-     */
-    @Test
-    public void testReplacePartialString_noReplace() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
-    }
-
-    /**
-     * Tests whether a variable can be replaced in a variable name.
-     */
-    @Test
-    public void testReplaceInVariable() {
-        values.put("animal.1", "fox");
-        values.put("animal.2", "mouse");
-        values.put("species", "2");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        sub.setEnableSubstitutionInVariables(true);
-        assertEquals(
-                "Wrong result (1)",
-                "The mouse jumps over the lazy dog.",
-                sub.replace("The ${animal.${species}} jumps over the ${target}."));
-        values.put("species", "1");
-        assertEquals(
-                "Wrong result (2)",
-                "The fox jumps over the lazy dog.",
-                sub.replace("The ${animal.${species}} jumps over the ${target}."));
-        assertEquals(
-                "Wrong result (3)",
-                "The fox jumps over the lazy dog.",
-                sub.replace("The ${unknown.animal.${unknown.species:-1}:-fox} jumps over the ${unknow.target:-lazy dog}."));
-    }
-
-    /**
-     * Tests whether substitution in variable names is disabled per default.
-     */
-    @Test
-    public void testReplaceInVariableDisabled() {
-        values.put("animal.1", "fox");
-        values.put("animal.2", "mouse");
-        values.put("species", "2");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        assertEquals(
-                "Wrong result (1)",
-                "The ${animal.${species}} jumps over the lazy dog.",
-                sub.replace("The ${animal.${species}} jumps over the ${target}."));
-        assertEquals(
-                "Wrong result (2)",
-                "The ${animal.${species:-1}} jumps over the lazy dog.",
-                sub.replace("The ${animal.${species:-1}} jumps over the ${target}."));
-    }
-
-    /**
-     * Tests complex and recursive substitution in variable names.
-     */
-    @Test
-    public void testReplaceInVariableRecursive() {
-        values.put("animal.2", "brown fox");
-        values.put("animal.1", "white mouse");
-        values.put("color", "white");
-        values.put("species.white", "1");
-        values.put("species.brown", "2");
-        final StrSubstitutor sub = new StrSubstitutor(values);
-        sub.setEnableSubstitutionInVariables(true);
-        assertEquals(
-                "Wrong result (1)",
-                "The white mouse jumps over the lazy dog.",
-                sub.replace("The ${animal.${species.${color}}} jumps over the ${target}."));
-        assertEquals(
-                "Wrong result (2)",
-                "The brown fox jumps over the lazy dog.",
-                sub.replace("The ${animal.${species.${unknownColor:-brown}}} jumps over the ${target}."));
-    }
-
-    @Test
-    public void testDefaultValueDelimiters() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("animal", "fox");
-        map.put("target", "dog");
-
-        StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number:-1234567890}."));
-
-        sub = new StrSubstitutor(map, "${", "}", '$', "?:");
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number?:1234567890}."));
-
-        sub = new StrSubstitutor(map, "${", "}", '$', "||");
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number||1234567890}."));
-
-        sub = new StrSubstitutor(map, "${", "}", '$', "!");
-        assertEquals("The fox jumps over the lazy dog. 1234567890.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
-
-        sub = new StrSubstitutor(map, "${", "}", '$', "");
-        sub.setValueDelimiterMatcher(null);
-        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
-
-        sub = new StrSubstitutor(map, "${", "}", '$');
-        sub.setValueDelimiterMatcher(null);
-        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
-                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Tests protected.
-     */
-    @Test
-    public void testResolveVariable() {
-        final StrBuilder builder = new StrBuilder("Hi ${name}!");
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        final StrSubstitutor sub = new StrSubstitutor(map) {
-            @Override
-            protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) {
-                assertEquals("name", variableName);
-                assertSame(builder, buf);
-                assertEquals(3, startPos);
-                assertEquals(10, endPos);
-                return "jakarta";
-            }
-        };
-        sub.replaceIn(builder);
-        assertEquals("Hi jakarta!", builder.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Tests constructor.
-     */
-    @Test
-    public void testConstructorNoArgs() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
-    }
-
-    /**
-     * Tests constructor.
-     */
-    @Test
-    public void testConstructorMapPrefixSuffix() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        final StrSubstitutor sub = new StrSubstitutor(map, "<", ">");
-        assertEquals("Hi < commons", sub.replace("Hi $< <name>"));
-    }
-
-    /**
-     * Tests constructor.
-     */
-    @Test
-    public void testConstructorMapFull() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!');
-        assertEquals("Hi < commons", sub.replace("Hi !< <name>"));
-        sub = new StrSubstitutor(map, "<", ">", '!', "||");
-        assertEquals("Hi < commons", sub.replace("Hi !< <name2||commons>"));
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Tests get set.
-     */
-    @Test
-    public void testGetSetEscape() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertEquals('$', sub.getEscapeChar());
-        sub.setEscapeChar('<');
-        assertEquals('<', sub.getEscapeChar());
-    }
-
-    /**
-     * Tests get set.
-     */
-    @Test
-    public void testGetSetPrefix() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setVariablePrefix('<');
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.CharMatcher);
-
-        sub.setVariablePrefix("<<");
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
-        try {
-            sub.setVariablePrefix((String) null);
-            fail();
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
-
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        sub.setVariablePrefixMatcher(matcher);
-        assertSame(matcher, sub.getVariablePrefixMatcher());
-        try {
-            sub.setVariablePrefixMatcher((StrMatcher) null);
-            fail();
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        assertSame(matcher, sub.getVariablePrefixMatcher());
-    }
-
-    /**
-     * Tests get set.
-     */
-    @Test
-    public void testGetSetSuffix() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setVariableSuffix('<');
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.CharMatcher);
-
-        sub.setVariableSuffix("<<");
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
-        try {
-            sub.setVariableSuffix((String) null);
-            fail();
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
-
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        sub.setVariableSuffixMatcher(matcher);
-        assertSame(matcher, sub.getVariableSuffixMatcher());
-        try {
-            sub.setVariableSuffixMatcher((StrMatcher) null);
-            fail();
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
-        assertSame(matcher, sub.getVariableSuffixMatcher());
-    }
-
-    /**
-     * Tests get set.
-     */
-    @Test
-    public void testGetSetValueDelimiter() {
-        final StrSubstitutor sub = new StrSubstitutor();
-        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setValueDelimiter(':');
-        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.CharMatcher);
-
-        sub.setValueDelimiter("||");
-        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
-        sub.setValueDelimiter((String) null);
-        assertNull(sub.getValueDelimiterMatcher());
-
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        sub.setValueDelimiterMatcher(matcher);
-        assertSame(matcher, sub.getValueDelimiterMatcher());
-        sub.setValueDelimiterMatcher((StrMatcher) null);
-        assertNull(sub.getValueDelimiterMatcher());
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Tests static.
-     */
-    @Test
-    public void testStaticReplace() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        assertEquals("Hi commons!", StrSubstitutor.replace("Hi ${name}!", map));
-    }
-
-    /**
-     * Tests static.
-     */
-    @Test
-    public void testStaticReplacePrefixSuffix() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("name", "commons");
-        assertEquals("Hi commons!", StrSubstitutor.replace("Hi <name>!", map, "<", ">"));
-    }
-
-    /**
-     * Tests interpolation with system properties.
-     */
-    @Test
-    public void testStaticReplaceSystemProperties() {
-        final StrBuilder buf = new StrBuilder();
-        buf.append("Hi ").append(System.getProperty("user.name"));
-        buf.append(", you are working with ");
-        buf.append(System.getProperty("os.name"));
-        buf.append(", your home directory is ");
-        buf.append(System.getProperty("user.home")).append('.');
-        assertEquals(buf.toString(), StrSubstitutor.replaceSystemProperties("Hi ${user.name}, you are "
-            + "working with ${os.name}, your home "
-            + "directory is ${user.home}."));
-    }
-
-    /**
-     * Test for LANG-1055: StrSubstitutor.replaceSystemProperties does not work consistently
-     */
-    @Test
-    public void testLANG1055() {
-        System.setProperty("test_key",  "test_value");
-
-        final String expected = StrSubstitutor.replace("test_key=${test_key}", System.getProperties());
-        final String actual = StrSubstitutor.replaceSystemProperties("test_key=${test_key}");
-        assertEquals(expected, actual);
-    }
-
-    /**
-     * Test the replace of a properties object
-     */
-    @Test
-    public void testSubstituteDefaultProperties(){
-        final String org = "${doesnotwork}";
-        System.setProperty("doesnotwork", "It works!");
-
-        // create a new Properties object with the System.getProperties as default
-        final Properties props = new Properties(System.getProperties());
-
-        assertEquals("It works!", StrSubstitutor.replace(org, props));
-    }
-
-    @Test
-    public void testSamePrefixAndSuffix() {
-        final Map<String, String> map = new HashMap<>();
-        map.put("greeting", "Hello");
-        map.put(" there ", "XXX");
-        map.put("name", "commons");
-        assertEquals("Hi commons!", StrSubstitutor.replace("Hi @name@!", map, "@", "@"));
-        assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@"));
-    }
-
-    @Test
-    public void testSubstitutePreserveEscape() {
-        final String org = "${not-escaped} $${escaped}";
-        final Map<String, String> map = new HashMap<>();
-        map.put("not-escaped", "value");
-
-        final StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
-        assertFalse(sub.isPreserveEscapes());
-        assertEquals("value ${escaped}", sub.replace(org));
-
-        sub.setPreserveEscapes(true);
-        assertTrue(sub.isPreserveEscapes());
-        assertEquals("value $${escaped}", sub.replace(org));
-    }
-
-    //-----------------------------------------------------------------------
-    private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) {
-        final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);
-        final StrSubstitutor sub = new StrSubstitutor(values);
-
-        // replace using String
-        assertEquals(expectedResult, sub.replace(replaceTemplate));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2));
-        }
-
-        // replace using char[]
-        final char[] chars = replaceTemplate.toCharArray();
-        assertEquals(expectedResult, sub.replace(chars));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2));
-        }
-
-        // replace using StringBuffer
-        StringBuffer buf = new StringBuffer(replaceTemplate);
-        assertEquals(expectedResult, sub.replace(buf));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2));
-        }
-
-        // replace using StringBuilder
-        StringBuilder builder = new StringBuilder(replaceTemplate);
-        assertEquals(expectedResult, sub.replace(builder));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2));
-        }
-
-        // replace using StrBuilder
-        StrBuilder bld = new StrBuilder(replaceTemplate);
-        assertEquals(expectedResult, sub.replace(bld));
-        if (substring) {
-            assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2));
-        }
-
-        // replace using object
-        final MutableObject<String> obj = new MutableObject<>(replaceTemplate);  // toString returns template
-        assertEquals(expectedResult, sub.replace(obj));
-
-        // replace in StringBuffer
-        buf = new StringBuffer(replaceTemplate);
-        assertTrue(sub.replaceIn(buf));
-        assertEquals(expectedResult, buf.toString());
-        if (substring) {
-            buf = new StringBuffer(replaceTemplate);
-            assertTrue(sub.replaceIn(buf, 1, buf.length() - 2));
-            assertEquals(expectedResult, buf.toString());  // expect full result as remainder is untouched
-        }
-
-        // replace in StringBuilder
-        builder = new StringBuilder(replaceTemplate);
-        assertTrue(sub.replaceIn(builder));
-        assertEquals(expectedResult, builder.toString());
-        if (substring) {
-            builder = new StringBuilder(replaceTemplate);
-            assertTrue(sub.replaceIn(builder, 1, builder.length() - 2));
-            assertEquals(expectedResult, builder.toString());  // expect full result as remainder is untouched
-        }
-
-        // replace in StrBuilder
-        bld = new StrBuilder(replaceTemplate);
-        assertTrue(sub.replaceIn(bld));
-        assertEquals(expectedResult, bld.toString());
-        if (substring) {
-            bld = new StrBuilder(replaceTemplate);
-            assertTrue(sub.replaceIn(bld, 1, bld.length() - 2));
-            assertEquals(expectedResult, bld.toString());  // expect full result as remainder is untouched
-        }
-    }
-
-    private void doTestNoReplace(final String replaceTemplate) {
-        final StrSubstitutor sub = new StrSubstitutor(values);
-
-        if (replaceTemplate == null) {
-            assertEquals(null, sub.replace((String) null));
-            assertEquals(null, sub.replace((String) null, 0, 100));
-            assertEquals(null, sub.replace((char[]) null));
-            assertEquals(null, sub.replace((char[]) null, 0, 100));
-            assertEquals(null, sub.replace((StringBuffer) null));
-            assertEquals(null, sub.replace((StringBuffer) null, 0, 100));
-            assertEquals(null, sub.replace((StrBuilder) null));
-            assertEquals(null, sub.replace((StrBuilder) null, 0, 100));
-            assertEquals(null, sub.replace((Object) null));
-            assertFalse(sub.replaceIn((StringBuffer) null));
-            assertFalse(sub.replaceIn((StringBuffer) null, 0, 100));
-            assertFalse(sub.replaceIn((StrBuilder) null));
-            assertFalse(sub.replaceIn((StrBuilder) null, 0, 100));
-        } else {
-            assertEquals(replaceTemplate, sub.replace(replaceTemplate));
-            final StrBuilder bld = new StrBuilder(replaceTemplate);
-            assertFalse(sub.replaceIn(bld));
-            assertEquals(replaceTemplate, bld.toString());
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StrTokenizerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StrTokenizerTest.java b/src/test/java/org/apache/commons/text/beta/StrTokenizerTest.java
deleted file mode 100644
index a956ad4..0000000
--- a/src/test/java/org/apache/commons/text/beta/StrTokenizerTest.java
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-/**
- * Unit test for {@link StrTokenizer}.
- */
-public class StrTokenizerTest {
-
-    private static final String CSV_SIMPLE_FIXTURE = "A,b,c";
-
-    private static final String TSV_SIMPLE_FIXTURE = "A\tb\tc";
-
-    private void checkClone(final StrTokenizer tokenizer) {
-        assertFalse(StrTokenizer.getCSVInstance() == tokenizer);
-        assertFalse(StrTokenizer.getTSVInstance() == tokenizer);
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void test1() {
-
-        final String input = "a;b;c;\"d;\"\"e\";f; ; ;  ";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterChar(';');
-        tok.setQuoteChar('"');
-        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", "", "", "",};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void test2() {
-
-        final String input = "a;b;c ;\"d;\"\"e\";f; ; ;";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterChar(';');
-        tok.setQuoteChar('"');
-        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", "c ", "d;\"e", "f", " ", " ", "",};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void test3() {
-
-        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterChar(';');
-        tok.setQuoteChar('"');
-        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", " ", " ", "",};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void test4() {
-
-        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterChar(';');
-        tok.setQuoteChar('"');
-        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(true);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f",};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void test5() {
-
-        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterChar(';');
-        tok.setQuoteChar('"');
-        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", null, null, null,};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void test6() {
-
-        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterChar(';');
-        tok.setQuoteChar('"');
-        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        // tok.setTreatingEmptyAsNull(true);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", null, null, null,};
-
-        int nextCount = 0;
-        while (tok.hasNext()) {
-            tok.next();
-            nextCount++;
-        }
-
-        int prevCount = 0;
-        while (tok.hasPrevious()) {
-            tok.previous();
-            prevCount++;
-        }
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-
-        assertTrue("could not cycle through entire token list" + " using the 'hasNext' and 'next' methods",
-                nextCount == expected.length);
-
-        assertTrue("could not cycle through entire token list" + " using the 'hasPrevious' and 'previous' methods",
-                prevCount == expected.length);
-
-    }
-
-    @Test
-    public void test7() {
-
-        final String input = "a   b c \"d e\" f ";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
-        tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
-        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "", "", "b", "c", "d e", "f", "",};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void test8() {
-
-        final String input = "a   b c \"d e\" f ";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
-        tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
-        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
-        tok.setIgnoreEmptyTokens(true);
-        final String tokens[] = tok.getTokenArray();
-
-        final String expected[] = new String[]{"a", "b", "c", "d e", "f",};
-
-        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
-                    expected[i], tokens[i]);
-        }
-
-    }
-
-    @Test
-    public void testBasic1() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasic2() {
-        final String input = "a \nb\fc";
-        final StrTokenizer tok = new StrTokenizer(input);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasic3() {
-        final String input = "a \nb\u0001\fc";
-        final StrTokenizer tok = new StrTokenizer(input);
-        assertEquals("a", tok.next());
-        assertEquals("b\u0001", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasic4() {
-        final String input = "a \"b\" c";
-        final StrTokenizer tok = new StrTokenizer(input);
-        assertEquals("a", tok.next());
-        assertEquals("\"b\"", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasic5() {
-        final String input = "a:b':c";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        assertEquals("a", tok.next());
-        assertEquals("b'", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicDelim1() {
-        final String input = "a:b:c";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicDelim2() {
-        final String input = "a:b:c";
-        final StrTokenizer tok = new StrTokenizer(input, ',');
-        assertEquals("a:b:c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testDelimString() {
-        final String input = "a##b##c";
-        final StrTokenizer tok = new StrTokenizer(input, "##");
-
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testDelimMatcher() {
-        final String input = "a/b\\c";
-        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[]{'/', '\\'});
-
-        final StrTokenizer tok = new StrTokenizer(input, delimMatcher);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testDelimMatcherQuoteMatcher() {
-        final String input = "`a`;`b`;`c`";
-        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[]{';'});
-        final StrMatcher quoteMatcher = new StrMatcher.CharSetMatcher(new char[]{'`'});
-
-        final StrTokenizer tok = new StrTokenizer(input, delimMatcher, quoteMatcher);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicEmpty1() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setIgnoreEmptyTokens(false);
-        assertEquals("a", tok.next());
-        assertEquals("", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicEmpty2() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals(null, tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted1() {
-        final String input = "a 'b' c";
-        final StrTokenizer tok = new StrTokenizer(input, ' ', '\'');
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted2() {
-        final String input = "a:'b':";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted3() {
-        final String input = "a:'b''c'";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("b'c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted4() {
-        final String input = "a: 'b' 'c' :d";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("b c", tok.next());
-        assertEquals("d", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted5() {
-        final String input = "a: 'b'x'c' :d";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bxc", tok.next());
-        assertEquals("d", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted6() {
-        final String input = "a:'b'\"c':d";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setQuoteMatcher(StrMatcher.quoteMatcher());
-        assertEquals("a", tok.next());
-        assertEquals("b\"c:d", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuoted7() {
-        final String input = "a:\"There's a reason here\":b";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setQuoteMatcher(StrMatcher.quoteMatcher());
-        assertEquals("a", tok.next());
-        assertEquals("There's a reason here", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicQuotedTrimmed1() {
-        final String input = "a: 'b' :";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicTrimmed1() {
-        final String input = "a: b :  ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicTrimmed2() {
-        final String input = "a:  b  :";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setTrimmerMatcher(StrMatcher.stringMatcher("  "));
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed1() {
-        final String input = "a: bIGNOREc : ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bc", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed2() {
-        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bc", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed3() {
-        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
-        final StrTokenizer tok = new StrTokenizer(input, ':');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("  bc  ", tok.next());
-        assertEquals("  ", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    @Test
-    public void testBasicIgnoreTrimmed4() {
-        final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
-        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
-        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
-        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
-        tok.setIgnoreEmptyTokens(false);
-        tok.setEmptyTokenAsNull(true);
-        assertEquals("a", tok.next());
-        assertEquals("bIGNOREcd", tok.next());
-        assertEquals(null, tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testListArray() {
-        final String input = "a  b c";
-        final StrTokenizer tok = new StrTokenizer(input);
-        final String[] array = tok.getTokenArray();
-        final List<?> list = tok.getTokenList();
-        
-        assertEquals(Arrays.asList(array), list);
-        assertEquals(3, list.size());
-    }
-
-    //-----------------------------------------------------------------------
-    private void testCSV(final String data) {
-        this.testXSVAbc(StrTokenizer.getCSVInstance(data));
-        this.testXSVAbc(StrTokenizer.getCSVInstance(data.toCharArray()));
-    }
-
-    @Test
-    public void testCSVEmpty() {
-        this.testEmpty(StrTokenizer.getCSVInstance());
-        this.testEmpty(StrTokenizer.getCSVInstance(""));
-    }
-
-    @Test
-    public void testCSVSimple() {
-        this.testCSV(CSV_SIMPLE_FIXTURE);
-    }
-
-    @Test
-    public void testCSVSimpleNeedsTrim() {
-        this.testCSV("   " + CSV_SIMPLE_FIXTURE);
-        this.testCSV("   \n\t  " + CSV_SIMPLE_FIXTURE);
-        this.testCSV("   \n  " + CSV_SIMPLE_FIXTURE + "\n\n\r");
-    }
-
-    void testEmpty(final StrTokenizer tokenizer) {
-        this.checkClone(tokenizer);
-        assertFalse(tokenizer.hasNext());
-        assertFalse(tokenizer.hasPrevious());
-        assertEquals(null, tokenizer.nextToken());
-        assertEquals(0, tokenizer.size());
-        try {
-            tokenizer.next();
-            fail();
-        } catch (final NoSuchElementException ex) {}
-    }
-
-    @Test
-    public void testGetContent() {
-        final String input = "a   b c \"d e\" f ";
-        StrTokenizer tok = new StrTokenizer(input);
-        assertEquals(input, tok.getContent());
-
-        tok = new StrTokenizer(input.toCharArray());
-        assertEquals(input, tok.getContent());
-        
-        tok = new StrTokenizer();
-        assertEquals(null, tok.getContent());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testChaining() {
-        final StrTokenizer tok = new StrTokenizer();
-        Assert.assertEquals(tok, tok.reset());
-        Assert.assertEquals(tok, tok.reset(""));
-        Assert.assertEquals(tok, tok.reset(new char[0]));
-        assertEquals(tok, tok.setDelimiterChar(' '));
-        assertEquals(tok, tok.setDelimiterString(" "));
-        assertEquals(tok, tok.setDelimiterMatcher(null));
-        assertEquals(tok, tok.setQuoteChar(' '));
-        assertEquals(tok, tok.setQuoteMatcher(null));
-        assertEquals(tok, tok.setIgnoredChar(' '));
-        assertEquals(tok, tok.setIgnoredMatcher(null));
-        assertEquals(tok, tok.setTrimmerMatcher(null));
-        assertEquals(tok, tok.setEmptyTokenAsNull(false));
-        assertEquals(tok, tok.setIgnoreEmptyTokens(false));
-    }
-
-    /**
-     * Tests that the {@link StrTokenizer#clone()} clone method catches {@link CloneNotSupportedException} and returns
-     * <code>null</code>.
-     */
-    @Test
-    public void testCloneNotSupportedException() {
-        final Object notCloned = new StrTokenizer() {
-            @Override
-            Object cloneReset() throws CloneNotSupportedException {
-                throw new CloneNotSupportedException("test");
-            }
-        }.clone();
-        assertNull(notCloned);
-    }
-
-    @Test
-    public void testCloneNull() {
-        final StrTokenizer tokenizer = new StrTokenizer((char[]) null);
-        // Start sanity check
-        assertEquals(null, tokenizer.nextToken());
-        tokenizer.reset();
-        assertEquals(null, tokenizer.nextToken());
-        // End sanity check
-        final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
-        tokenizer.reset();
-        assertEquals(null, tokenizer.nextToken());
-        assertEquals(null, clonedTokenizer.nextToken());
-    }
-
-    @Test
-    public void testCloneReset() {
-        final char[] input = new char[]{'a'};
-        final StrTokenizer tokenizer = new StrTokenizer(input);
-        // Start sanity check
-        assertEquals("a", tokenizer.nextToken());
-        tokenizer.reset(input);
-        assertEquals("a", tokenizer.nextToken());
-        // End sanity check
-        final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
-        input[0] = 'b';
-        tokenizer.reset(input);
-        assertEquals("b", tokenizer.nextToken());
-        assertEquals("a", clonedTokenizer.nextToken());
-    }
-  
-    // -----------------------------------------------------------------------
-    @Test
-    public void testConstructor_String() {
-        StrTokenizer tok = new StrTokenizer("a b");
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer("");
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer((String) null);
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testConstructor_String_char() {
-        StrTokenizer tok = new StrTokenizer("a b", ' ');
-        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer("", ' ');
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer((String) null, ' ');
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testConstructor_String_char_char() {
-        StrTokenizer tok = new StrTokenizer("a b", ' ', '"');
-        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
-        assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer("", ' ', '"');
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer((String) null, ' ', '"');
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testConstructor_charArray() {
-        StrTokenizer tok = new StrTokenizer("a b".toCharArray());
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer(new char[0]);
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer((char[]) null);
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testConstructor_charArray_char() {
-        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ');
-        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer(new char[0], ' ');
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer((char[]) null, ' ');
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testConstructor_charArray_char_char() {
-        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ', '"');
-        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
-        assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer(new char[0], ' ', '"');
-        assertFalse(tok.hasNext());
-        
-        tok = new StrTokenizer((char[]) null, ' ', '"');
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReset() {
-        final StrTokenizer tok = new StrTokenizer("a b c");
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok.reset();
-        assertEquals("a", tok.next());
-        assertEquals("b", tok.next());
-        assertEquals("c", tok.next());
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReset_String() {
-        final StrTokenizer tok = new StrTokenizer("x x x");
-        tok.reset("d e");
-        assertEquals("d", tok.next());
-        assertEquals("e", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok.reset((String) null);
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReset_charArray() {
-        final StrTokenizer tok = new StrTokenizer("x x x");
-        
-        final char[] array = new char[] {'a', 'b', 'c'};
-        tok.reset(array);
-        assertEquals("abc", tok.next());
-        assertFalse(tok.hasNext());
-        
-        tok.reset((char[]) null);
-        assertFalse(tok.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTSV() {
-        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
-        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
-    }
-
-    @Test
-    public void testTSVEmpty() {
-        this.testEmpty(StrTokenizer.getTSVInstance());
-        this.testEmpty(StrTokenizer.getTSVInstance(""));
-    }
-
-    void testXSVAbc(final StrTokenizer tokenizer) {
-        this.checkClone(tokenizer);
-        assertEquals(-1, tokenizer.previousIndex());
-        assertEquals(0, tokenizer.nextIndex());
-        assertEquals(null, tokenizer.previousToken());
-        assertEquals("A", tokenizer.nextToken());
-        assertEquals(1, tokenizer.nextIndex());
-        assertEquals("b", tokenizer.nextToken());
-        assertEquals(2, tokenizer.nextIndex());
-        assertEquals("c", tokenizer.nextToken());
-        assertEquals(3, tokenizer.nextIndex());
-        assertEquals(null, tokenizer.nextToken());
-        assertEquals(3, tokenizer.nextIndex());
-        assertEquals("c", tokenizer.previousToken());
-        assertEquals(2, tokenizer.nextIndex());
-        assertEquals("b", tokenizer.previousToken());
-        assertEquals(1, tokenizer.nextIndex());
-        assertEquals("A", tokenizer.previousToken());
-        assertEquals(0, tokenizer.nextIndex());
-        assertEquals(null, tokenizer.previousToken());
-        assertEquals(0, tokenizer.nextIndex());
-        assertEquals(-1, tokenizer.previousIndex());
-        assertEquals(3, tokenizer.size());
-    }
-
-    @Test
-    public void testIteration() {
-        final StrTokenizer tkn = new StrTokenizer("a b c");
-        assertFalse(tkn.hasPrevious());
-        try {
-            tkn.previous();
-            fail();
-        } catch (final NoSuchElementException ex) {}
-        assertTrue(tkn.hasNext());
-        
-        assertEquals("a", tkn.next());
-        try {
-            tkn.remove();
-            fail();
-        } catch (final UnsupportedOperationException ex) {}
-        try {
-            tkn.set("x");
-            fail();
-        } catch (final UnsupportedOperationException ex) {}
-        try {
-            tkn.add("y");
-            fail();
-        } catch (final UnsupportedOperationException ex) {}
-        assertTrue(tkn.hasPrevious());
-        assertTrue(tkn.hasNext());
-        
-        assertEquals("b", tkn.next());
-        assertTrue(tkn.hasPrevious());
-        assertTrue(tkn.hasNext());
-        
-        assertEquals("c", tkn.next());
-        assertTrue(tkn.hasPrevious());
-        assertFalse(tkn.hasNext());
-        
-        try {
-            tkn.next();
-            fail();
-        } catch (final NoSuchElementException ex) {}
-        assertTrue(tkn.hasPrevious());
-        assertFalse(tkn.hasNext());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTokenizeSubclassInputChange() {
-        final StrTokenizer tkn = new StrTokenizer("a b c d e") {
-            @Override
-            protected List<String> tokenize(final char[] chars, final int offset, final int count) {
-                return super.tokenize("w x y z".toCharArray(), 2, 5);
-            }
-        };
-        assertEquals("x", tkn.next());
-        assertEquals("y", tkn.next());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTokenizeSubclassOutputChange() {
-        final StrTokenizer tkn = new StrTokenizer("a b c") {
-            @Override
-            protected List<String> tokenize(final char[] chars, final int offset, final int count) {
-                final List<String> list = super.tokenize(chars, offset, count);
-                Collections.reverse(list);
-                return list;
-            }
-        };
-        assertEquals("c", tkn.next());
-        assertEquals("b", tkn.next());
-        assertEquals("a", tkn.next());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testToString() {
-        final StrTokenizer tkn = new StrTokenizer("a b c d e");
-        assertEquals("StrTokenizer[not tokenized yet]", tkn.toString());
-        tkn.next();
-        assertEquals("StrTokenizer[a, b, c, d, e]", tkn.toString());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StringEscapeUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StringEscapeUtilsTest.java b/src/test/java/org/apache/commons/text/beta/StringEscapeUtilsTest.java
deleted file mode 100644
index 535fa77..0000000
--- a/src/test/java/org/apache/commons/text/beta/StringEscapeUtilsTest.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import org.junit.Test;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-import static org.apache.commons.text.beta.StringEscapeUtils.escapeXSI;
-import static org.apache.commons.text.beta.StringEscapeUtils.unescapeXSI;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/**
- * Unit tests for {@link StringEscapeUtils}.
- *
- * <p>
- * This code has been adapted from Apache Commons Lang 3.5.
- * </p>
- *
- */
-public class StringEscapeUtilsTest {
-    private final static String FOO = "foo";
-
-    @Test
-    public void testConstructor() {
-        assertNotNull(new StringEscapeUtils());
-        final Constructor<?>[] cons = StringEscapeUtils.class.getDeclaredConstructors();
-        assertEquals(1, cons.length);
-        assertTrue(Modifier.isPublic(cons[0].getModifiers()));
-        assertTrue(Modifier.isPublic(StringEscapeUtils.class.getModifiers()));
-        assertFalse(Modifier.isFinal(StringEscapeUtils.class.getModifiers()));
-    }
-
-    @Test
-    public void testEscapeJava() throws IOException {
-        assertEquals(null, StringEscapeUtils.escapeJava(null));
-        try {
-            StringEscapeUtils.ESCAPE_JAVA.translate(null, null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-        try {
-            StringEscapeUtils.ESCAPE_JAVA.translate("", null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-
-        assertEscapeJava("empty string", "", "");
-        assertEscapeJava(FOO, FOO);
-        assertEscapeJava("tab", "\\t", "\t");
-        assertEscapeJava("backslash", "\\\\", "\\");
-        assertEscapeJava("single quote should not be escaped", "'", "'");
-        assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r");
-        assertEscapeJava("\\u1234", "\u1234");
-        assertEscapeJava("\\u0234", "\u0234");
-        assertEscapeJava("\\u00EF", "\u00ef");
-        assertEscapeJava("\\u0001", "\u0001");
-        assertEscapeJava("Should use capitalized Unicode hex", "\\uABCD", "\uabcd");
-
-        assertEscapeJava("He didn't say, \\\"stop!\\\"",
-                "He didn't say, \"stop!\"");
-        assertEscapeJava("non-breaking space", "This space is non-breaking:" + "\\u00A0",
-                "This space is non-breaking:\u00a0");
-        assertEscapeJava("\\uABCD\\u1234\\u012C",
-                "\uABCD\u1234\u012C");
-    }
-
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-421
-     */
-    @Test
-    public void testEscapeJavaWithSlash() {
-        final String input = "String with a slash (/) in it";
-
-        final String expected = input;
-        final String actual = StringEscapeUtils.escapeJava(input);
-
-        /**
-         * In 2.4 StringEscapeUtils.escapeJava(String) escapes '/' characters, which are not a valid character to escape
-         * in a Java string.
-         */
-        assertEquals(expected, actual);
-    }
-
-    private void assertEscapeJava(final String escaped, final String original) throws IOException {
-        assertEscapeJava(null, escaped, original);
-    }
-
-    private void assertEscapeJava(String message, final String expected, final String original) throws IOException {
-        final String converted = StringEscapeUtils.escapeJava(original);
-        message = "escapeJava(String) failed" + (message == null ? "" : (": " + message));
-        assertEquals(message, expected, converted);
-
-        final StringWriter writer = new StringWriter();
-        StringEscapeUtils.ESCAPE_JAVA.translate(original, writer);
-        assertEquals(expected, writer.toString());
-    }
-
-    @Test
-    public void testUnescapeJava() throws IOException {
-        assertEquals(null, StringEscapeUtils.unescapeJava(null));
-        try {
-            StringEscapeUtils.UNESCAPE_JAVA.translate(null, null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-        try {
-            StringEscapeUtils.UNESCAPE_JAVA.translate("", null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-        try {
-            StringEscapeUtils.unescapeJava("\\u02-3");
-            fail();
-        } catch (final RuntimeException ex) {
-        }
-
-        assertUnescapeJava("", "");
-        assertUnescapeJava("test", "test");
-        assertUnescapeJava("\ntest\b", "\\ntest\\b");
-        assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
-        assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
-        assertUnescapeJava("", "\\");
-        //foo
-        assertUnescapeJava("lowercase Unicode", "\uABCDx", "\\uabcdx");
-        assertUnescapeJava("uppercase Unicode", "\uABCDx", "\\uABCDx");
-        assertUnescapeJava("Unicode as final character", "\uABCD", "\\uabcd");
-    }
-
-    private void assertUnescapeJava(final String unescaped, final String original) throws IOException {
-        assertUnescapeJava(null, unescaped, original);
-    }
-
-    private void assertUnescapeJava(final String message, final String unescaped, final String original) throws IOException {
-        final String expected = unescaped;
-        final String actual = StringEscapeUtils.unescapeJava(original);
-
-        assertEquals("unescape(String) failed" +
-                        (message == null ? "" : (": " + message)) +
-                        ": expected '" + StringEscapeUtils.escapeJava(expected) +
-                        // we escape this so we can see it in the error message
-                        "' actual '" + StringEscapeUtils.escapeJava(actual) + "'",
-                expected, actual);
-
-        final StringWriter writer = new StringWriter();
-        StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer);
-        assertEquals(unescaped, writer.toString());
-
-    }
-
-    @Test
-    public void testEscapeEcmaScript() {
-        assertEquals(null, StringEscapeUtils.escapeEcmaScript(null));
-        try {
-            StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-        try {
-            StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-
-        assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\""));
-        assertEquals("document.getElementById(\\\"test\\\").value = \\'<script>alert(\\'aaa\\');<\\/script>\\';",
-                StringEscapeUtils.escapeEcmaScript("document.getElementById(\"test\").value = '<script>alert('aaa');</script>';"));
-    }
-
-
-    // HTML and XML
-    //--------------------------------------------------------------
-
-    private static final String[][] HTML_ESCAPES = {
-            {"no escaping", "plain text", "plain text"},
-            {"no escaping", "plain text", "plain text"},
-            {"empty string", "", ""},
-            {"null", null, null},
-            {"ampersand", "bread &amp; butter", "bread & butter"},
-            {"quotes", "&quot;bread&quot; &amp; butter", "\"bread\" & butter"},
-            {"final character only", "greater than &gt;", "greater than >"},
-            {"first character only", "&lt; less than", "< less than"},
-            {"apostrophe", "Huntington's chorea", "Huntington's chorea"},
-            {"languages", "English,Fran&ccedil;ais,\u65E5\u672C\u8A9E (nihongo)", "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"},
-            {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"},
-    };
-
-    @Test
-    public void testEscapeHtml() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml4(original));
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML4.translate(original, sw);
-            } catch (final IOException e) {
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(message, expected, actual);
-        }
-    }
-
-    @Test
-    public void testEscapeHtml4Once() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml4Once(original));
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml4Once(expected));
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML4_ONCE.translate(original, sw);
-            } catch (final IOException e) {
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(message, expected, actual);
-            final StringWriter sw2 = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML4_ONCE.translate(expected, sw2);
-            } catch (final IOException e) {
-            }
-            final String actual2 = original == null ? null : sw2.toString();
-            assertEquals(message, expected, actual2);
-        }
-    }
-
-    @Test
-    public void testEscapeHtml3Once() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[1];
-            final String original = element[2];
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml3Once(original));
-            assertEquals(message, expected, StringEscapeUtils.escapeHtml3Once(expected));
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML3_ONCE.translate(original, sw);
-            } catch (final IOException e) {
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(message, expected, actual);
-            final StringWriter sw2 = new StringWriter();
-            try {
-                StringEscapeUtils.ESCAPE_HTML3_ONCE.translate(expected, sw2);
-            } catch (final IOException e) {
-            }
-            final String actual2 = original == null ? null : sw2.toString();
-            assertEquals(message, expected, actual2);
-        }
-    }
-
-    @Test
-    public void testUnescapeHtml4() {
-        for (final String[] element : HTML_ESCAPES) {
-            final String message = element[0];
-            final String expected = element[2];
-            final String original = element[1];
-            assertEquals(message, expected, StringEscapeUtils.unescapeHtml4(original));
-
-            final StringWriter sw = new StringWriter();
-            try {
-                StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw);
-            } catch (final IOException e) {
-            }
-            final String actual = original == null ? null : sw.toString();
-            assertEquals(message, expected, actual);
-        }
-        // \u00E7 is a cedilla (c with wiggle under)
-        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
-        // on some locales        
-        assertEquals("funny chars pass through OK", "Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"));
-
-        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World"));
-        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World"));
-        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World"));
-        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World"));
-    }
-
-    @Test
-    public void testUnescapeHexCharsHtml() {
-        // Simple easy to grok test 
-        assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#x80;&#x9F;"));
-        assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#X80;&#X9F;"));
-        // Test all Character values:
-        for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
-            final Character c1 = new Character(i);
-            final Character c2 = new Character((char)(i+1));
-            final String expected = c1.toString() + c2.toString();
-            final String escapedC1 = "&#x" + Integer.toHexString((c1.charValue())) + ";";
-            final String escapedC2 = "&#x" + Integer.toHexString((c2.charValue())) + ";";
-            assertEquals("hex number unescape index " + (int)i, expected, StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2));
-        }
-    }
-
-    @Test
-    public void testUnescapeUnknownEntity() throws Exception {
-        assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;"));
-    }
-
-    @Test
-    public void testEscapeHtmlVersions() throws Exception {
-        assertEquals("&Beta;", StringEscapeUtils.escapeHtml4("\u0392"));
-        assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("&Beta;"));
-
-        // TODO: refine API for escaping/unescaping specific HTML versions
-    }
-
-
-
-    @Test
-    public void testEscapeXml10() throws Exception {
-        assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml10("a<b>c\"d'e&f"));
-        assertEquals("XML 1.0 should not escape \t \n \r",
-                "a\tb\rc\nd", StringEscapeUtils.escapeXml10("a\tb\rc\nd"));
-        assertEquals("XML 1.0 should omit most #x0-x8 | #xb | #xc | #xe-#x19",
-                "ab", StringEscapeUtils.escapeXml10("a\u0000\u0001\u0008\u000b\u000c\u000e\u001fb"));
-        assertEquals("XML 1.0 should omit #xd800-#xdfff",
-                "a\ud7ff  \ue000b", StringEscapeUtils.escapeXml10("a\ud7ff\ud800 \udfff \ue000b"));
-        assertEquals("XML 1.0 should omit #xfffe | #xffff",
-                "a\ufffdb", StringEscapeUtils.escapeXml10("a\ufffd\ufffe\uffffb"));
-        assertEquals("XML 1.0 should escape #x7f-#x84 | #x86 - #x9f, for XML 1.1 compatibility",
-                "a\u007e&#127;&#132;\u0085&#134;&#159;\u00a0b", StringEscapeUtils.escapeXml10("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"));
-    }
-
-    @Test
-    public void testEscapeXml11() throws Exception {
-        assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml11("a<b>c\"d'e&f"));
-        assertEquals("XML 1.1 should not escape \t \n \r",
-                "a\tb\rc\nd", StringEscapeUtils.escapeXml11("a\tb\rc\nd"));
-        assertEquals("XML 1.1 should omit #x0",
-                "ab", StringEscapeUtils.escapeXml11("a\u0000b"));
-        assertEquals("XML 1.1 should escape #x1-x8 | #xb | #xc | #xe-#x19",
-                "a&#1;&#8;&#11;&#12;&#14;&#31;b", StringEscapeUtils.escapeXml11("a\u0001\u0008\u000b\u000c\u000e\u001fb"));
-        assertEquals("XML 1.1 should escape #x7F-#x84 | #x86-#x9F",
-                "a\u007e&#127;&#132;\u0085&#134;&#159;\u00a0b", StringEscapeUtils.escapeXml11("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"));
-        assertEquals("XML 1.1 should omit #xd800-#xdfff",
-                "a\ud7ff  \ue000b", StringEscapeUtils.escapeXml11("a\ud7ff\ud800 \udfff \ue000b"));
-        assertEquals("XML 1.1 should omit #xfffe | #xffff",
-                "a\ufffdb", StringEscapeUtils.escapeXml11("a\ufffd\ufffe\uffffb"));
-    }
-
-    /**
-     * Reverse of the above.
-     *
-     * @see <a href="https://issues.apache.org/jira/browse/LANG-729">LANG-729</a>
-     */
-    @Test
-    public void testUnescapeXmlSupplementaryCharacters() {
-        assertEquals("Supplementary character must be represented using a single escape", "\uD84C\uDFB4",
-                StringEscapeUtils.unescapeXml("&#144308;") );
-
-        assertEquals("Supplementary characters mixed with basic characters should be decoded correctly", "a b c \uD84C\uDFB4",
-                StringEscapeUtils.unescapeXml("a b c &#144308;") );
-    }
-
-    // Tests issue #38569
-    // http://issues.apache.org/bugzilla/show_bug.cgi?id=38569
-    @Test
-    public void testStandaloneAmphersand() {
-        assertEquals("<P&O>", StringEscapeUtils.unescapeHtml4("&lt;P&O&gt;"));
-        assertEquals("test & <", StringEscapeUtils.unescapeHtml4("test & &lt;"));
-        assertEquals("<P&O>", StringEscapeUtils.unescapeXml("&lt;P&O&gt;"));
-        assertEquals("test & <", StringEscapeUtils.unescapeXml("test & &lt;"));
-    }
-
-    @Test
-    public void testLang313() {
-        assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &amp;"));
-    }
-
-    @Test
-    public void testEscapeCsvString() throws Exception {
-        assertEquals("foo.bar",            StringEscapeUtils.escapeCsv("foo.bar"));
-        assertEquals("\"foo,bar\"",        StringEscapeUtils.escapeCsv("foo,bar"));
-        assertEquals("\"foo\nbar\"",       StringEscapeUtils.escapeCsv("foo\nbar"));
-        assertEquals("\"foo\rbar\"",       StringEscapeUtils.escapeCsv("foo\rbar"));
-        assertEquals("\"foo\"\"bar\"",     StringEscapeUtils.escapeCsv("foo\"bar"));
-        assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.escapeCsv("foo\uD84C\uDFB4bar"));
-        assertEquals("",   StringEscapeUtils.escapeCsv(""));
-        assertEquals(null, StringEscapeUtils.escapeCsv(null));
-    }
-
-    @Test
-    public void testEscapeCsvWriter() throws Exception {
-        checkCsvEscapeWriter("foo.bar",            "foo.bar");
-        checkCsvEscapeWriter("\"foo,bar\"",        "foo,bar");
-        checkCsvEscapeWriter("\"foo\nbar\"",       "foo\nbar");
-        checkCsvEscapeWriter("\"foo\rbar\"",       "foo\rbar");
-        checkCsvEscapeWriter("\"foo\"\"bar\"",     "foo\"bar");
-        checkCsvEscapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
-        checkCsvEscapeWriter("", null);
-        checkCsvEscapeWriter("", "");
-    }
-
-    private void checkCsvEscapeWriter(final String expected, final String value) {
-        try {
-            final StringWriter writer = new StringWriter();
-            StringEscapeUtils.ESCAPE_CSV.translate(value, writer);
-            assertEquals(expected, writer.toString());
-        } catch (final IOException e) {
-            fail("Threw: " + e);
-        }
-    }
-
-    @Test
-    public void testUnescapeCsvString() throws Exception {
-        assertEquals("foo.bar",              StringEscapeUtils.unescapeCsv("foo.bar"));
-        assertEquals("foo,bar",              StringEscapeUtils.unescapeCsv("\"foo,bar\""));
-        assertEquals("foo\nbar",             StringEscapeUtils.unescapeCsv("\"foo\nbar\""));
-        assertEquals("foo\rbar",             StringEscapeUtils.unescapeCsv("\"foo\rbar\""));
-        assertEquals("foo\"bar",             StringEscapeUtils.unescapeCsv("\"foo\"\"bar\""));
-        assertEquals("foo\uD84C\uDFB4bar",   StringEscapeUtils.unescapeCsv("foo\uD84C\uDFB4bar"));
-        assertEquals("",   StringEscapeUtils.unescapeCsv(""));
-        assertEquals(null, StringEscapeUtils.unescapeCsv(null));
-
-        assertEquals("\"foo.bar\"",          StringEscapeUtils.unescapeCsv("\"foo.bar\""));
-    }
-
-    @Test
-    public void testUnescapeCsvWriter() throws Exception {
-        checkCsvUnescapeWriter("foo.bar",            "foo.bar");
-        checkCsvUnescapeWriter("foo,bar",            "\"foo,bar\"");
-        checkCsvUnescapeWriter("foo\nbar",           "\"foo\nbar\"");
-        checkCsvUnescapeWriter("foo\rbar",           "\"foo\rbar\"");
-        checkCsvUnescapeWriter("foo\"bar",           "\"foo\"\"bar\"");
-        checkCsvUnescapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
-        checkCsvUnescapeWriter("", null);
-        checkCsvUnescapeWriter("", "");
-
-        checkCsvUnescapeWriter("\"foo.bar\"",        "\"foo.bar\"");
-    }
-
-    private void checkCsvUnescapeWriter(final String expected, final String value) {
-        try {
-            final StringWriter writer = new StringWriter();
-            StringEscapeUtils.UNESCAPE_CSV.translate(value, writer);
-            assertEquals(expected, writer.toString());
-        } catch (final IOException e) {
-            fail("Threw: " + e);
-        }
-    }
-
-    /**
-     * Tests // https://issues.apache.org/jira/browse/LANG-480
-     */
-    @Test
-    public void testEscapeHtmlHighUnicode() {
-        // this is the utf8 representation of the character:
-        // COUNTING ROD UNIT DIGIT THREE
-        // in Unicode
-        // codepoint: U+1D362
-        final byte[] data = new byte[] { (byte)0xF0, (byte)0x9D, (byte)0x8D, (byte)0xA2 };
-
-        final String original = new String(data, Charset.forName("UTF8"));
-
-        final String escaped = StringEscapeUtils.escapeHtml4( original );
-        assertEquals( "High Unicode should not have been escaped", original, escaped);
-
-        final String unescaped = StringEscapeUtils.unescapeHtml4( escaped );
-        assertEquals( "High Unicode should have been unchanged", original, unescaped);
-
-        // TODO: I think this should hold, needs further investigation
-        //        String unescapedFromEntity = StringEscapeUtils.unescapeHtml4( "&#119650;" );
-        //        assertEquals( "High Unicode should have been unescaped", original, unescapedFromEntity);
-    }
-
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-339
-     */
-    @Test
-    public void testEscapeHiragana() {
-        // Some random Japanese Unicode characters
-        final String original = "\u304B\u304C\u3068";
-        final String escaped = StringEscapeUtils.escapeHtml4(original);
-        assertEquals( "Hiragana character Unicode behaviour should not be being escaped by escapeHtml4",
-                original, escaped);
-
-        final String unescaped = StringEscapeUtils.unescapeHtml4( escaped );
-
-        assertEquals( "Hiragana character Unicode behaviour has changed - expected no unescaping", escaped, unescaped);
-    }
-
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-708
-     *
-     * @throws IOException
-     *             if an I/O error occurs
-     */
-    @Test
-    public void testLang708() throws IOException {
-        byte[] inputBytes = Files.readAllBytes(Paths.get("src/test/resources/stringEscapeUtilsTestData.txt"));
-        final String input = new String(inputBytes, StandardCharsets.UTF_8);
-        final String escaped = StringEscapeUtils.escapeEcmaScript(input);
-        // just the end:
-        assertTrue(escaped, escaped.endsWith("}]"));
-        // a little more:
-        assertTrue(escaped, escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"));
-    }
-
-    /**
-     * Tests https://issues.apache.org/jira/browse/LANG-911
-     */
-    @Test
-    public void testLang911() {
-        final String bellsTest = "\ud83d\udc80\ud83d\udd14";
-        final String value = StringEscapeUtils.escapeJava(bellsTest);
-        final String valueTest = StringEscapeUtils.unescapeJava(value);
-        assertEquals(bellsTest, valueTest);
-    }
-
-    @Test
-    public void testEscapeJson() {
-        assertEquals(null, StringEscapeUtils.escapeJson(null));
-        try {
-            StringEscapeUtils.ESCAPE_JSON.translate(null, null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-        try {
-            StringEscapeUtils.ESCAPE_JSON.translate("", null);
-            fail();
-        } catch (final IOException ex) {
-            fail();
-        } catch (final IllegalArgumentException ex) {
-        }
-
-        assertEquals("He didn't say, \\\"stop!\\\"", StringEscapeUtils.escapeJson("He didn't say, \"stop!\""));
-
-        final String expected = "\\\"foo\\\" isn't \\\"bar\\\". specials: \\b\\r\\n\\f\\t\\\\\\/";
-        final String input ="\"foo\" isn't \"bar\". specials: \b\r\n\f\t\\/";
-
-        assertEquals(expected, StringEscapeUtils.escapeJson(input));
-    }
-
-    @Test
-    public void testBuilder() {
-        String result = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_XML10).escape("<").append(">").toString();
-        assertEquals("&lt;>", result);
-    }
-
-    @Test
-    public void testEscapeXSI() {
-        assertNull(null, escapeXSI(null));
-        assertEquals("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"", escapeXSI("He didn't say, \"Stop!\""));
-        assertEquals("\\\\", escapeXSI("\\"));
-        assertEquals("", escapeXSI("\n"));
-    }
-
-    @Test
-    public void testUnscapeXSI() {
-        assertNull(null, unescapeXSI(null));
-        assertEquals("\"", unescapeXSI("\\\""));
-        assertEquals("He didn't say, \"Stop!\"", unescapeXSI("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\""));
-        assertEquals("\\", unescapeXSI("\\\\"));
-        assertEquals("", unescapeXSI("\\"));
-    }
-
-}
\ No newline at end of file


[23/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/StrLookup.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StrLookup.java b/src/main/java/org/apache/commons/text/beta/StrLookup.java
deleted file mode 100644
index b133b4f..0000000
--- a/src/main/java/org/apache/commons/text/beta/StrLookup.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.util.Map;
-
-/**
- * Lookup a String key to a String value.
- * <p>
- * This class represents the simplest form of a string to string map.
- * It has a benefit over a map in that it can create the result on
- * demand based on the key.
- * <p>
- * This class comes complete with various factory methods.
- * If these do not suffice, you can subclass and implement your own matcher.
- * <p>
- * For example, it would be possible to implement a lookup that used the
- * key as a primary key, and looked up the value on demand from the database
- *
- * @since 1.0
- */
-public abstract class StrLookup<V> {
-
-    /**
-     * Lookup that always returns null.
-     */
-    private static final StrLookup<String> NONE_LOOKUP = new MapStrLookup<>(null);
-
-    /**
-     * Lookup based on system properties.
-     */
-    private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup();
-
-    //-----------------------------------------------------------------------
-    /**
-     * Returns a lookup which always returns null.
-     *
-     * @return a lookup that always returns null, not null
-     */
-    public static StrLookup<?> noneLookup() {
-        return NONE_LOOKUP;
-    }
-
-    /**
-     * Returns a new lookup which uses a copy of the current
-     * {@link System#getProperties() System properties}.
-     * <p>
-     * If a security manager blocked access to system properties, then null will
-     * be returned from every lookup.
-     * <p>
-     * If a null key is used, this lookup will throw a NullPointerException.
-     *
-     * @return a lookup using system properties, not null
-     */
-    public static StrLookup<String> systemPropertiesLookup() {
-        return SYSTEM_PROPERTIES_LOOKUP;
-    }
-
-    /**
-     * Returns a lookup which looks up values using a map.
-     * <p>
-     * If the map is null, then null will be returned from every lookup.
-     * The map result object is converted to a string using toString().
-     *
-     * @param <V> the type of the values supported by the lookup
-     * @param map  the map of keys to values, may be null
-     * @return a lookup using the map, not null
-     */
-    public static <V> StrLookup<V> mapLookup(final Map<String, V> map) {
-        return new MapStrLookup<>(map);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Constructor.
-     */
-    protected StrLookup() {
-        super();
-    }
-
-    /**
-     * Looks up a String key to a String value.
-     * <p>
-     * The internal implementation may use any mechanism to return the value.
-     * The simplest implementation is to use a Map. However, virtually any
-     * implementation is possible.
-     * <p>
-     * For example, it would be possible to implement a lookup that used the
-     * key as a primary key, and looked up the value on demand from the database
-     * Or, a numeric based implementation could be created that treats the key
-     * as an integer, increments the value and return the result as a string -
-     * converting 1 to 2, 15 to 16 etc.
-     * <p>
-     * The {@link #lookup(String)} method always returns a String, regardless of
-     * the underlying data, by converting it as necessary. For example:
-     * <pre>
-     * Map&lt;String, Object&gt; map = new HashMap&lt;String, Object&gt;();
-     * map.put("number", Integer.valueOf(2));
-     * assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
-     * </pre>
-     * @param key  the key to be looked up, may be null
-     * @return the matching value, null if no match
-     */
-    public abstract String lookup(String key);
-
-    //-----------------------------------------------------------------------
-    /**
-     * Lookup implementation that uses a Map.
-     */
-    static class MapStrLookup<V> extends StrLookup<V> {
-
-        /** Map keys are variable names and value. */
-        private final Map<String, V> map;
-
-        /**
-         * Creates a new instance backed by a Map.
-         *
-         * @param map  the map of keys to values, may be null
-         */
-        MapStrLookup(final Map<String, V> map) {
-            this.map = map;
-        }
-
-        /**
-         * Looks up a String key to a String value using the map.
-         * <p>
-         * If the map is null, then null is returned.
-         * The map result object is converted to a string using toString().
-         *
-         * @param key  the key to be looked up, may be null
-         * @return the matching value, null if no match
-         */
-        @Override
-        public String lookup(final String key) {
-            if (map == null) {
-                return null;
-            }
-            final Object obj = map.get(key);
-            if (obj == null) {
-                return null;
-            }
-            return obj.toString();
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Lookup implementation based on system properties.
-     */
-    private static class SystemPropertiesStrLookup extends StrLookup<String> {
-        /**
-         * {@inheritDoc} This implementation directly accesses system properties.
-         */
-        @Override
-        public String lookup(final String key) {
-            if (key.length() > 0) {
-                try {
-                    return System.getProperty(key);
-                } catch (final SecurityException scex) {
-                    // Squelched. All lookup(String) will return null.
-                }
-            }
-            return null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/StrMatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StrMatcher.java b/src/main/java/org/apache/commons/text/beta/StrMatcher.java
deleted file mode 100644
index c9e1618..0000000
--- a/src/main/java/org/apache/commons/text/beta/StrMatcher.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.util.Arrays;
-
-/**
- * A matcher class that can be queried to determine if a character array
- * portion matches.
- * <p>
- * This class comes complete with various factory methods.
- * If these do not suffice, you can subclass and implement your own matcher.
- *
- * @since 1.0
- */
-public abstract class StrMatcher {
-
-    /**
-     * Matches the comma character.
-     */
-    private static final StrMatcher COMMA_MATCHER = new CharMatcher(',');
-    /**
-     * Matches the tab character.
-     */
-    private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
-    /**
-     * Matches the space character.
-     */
-    private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
-    /**
-     * Matches the same characters as StringTokenizer,
-     * namely space, tab, newline, formfeed.
-     */
-    private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray());
-    /**
-     * Matches the String trim() whitespace characters.
-     */
-    private static final StrMatcher TRIM_MATCHER = new TrimMatcher();
-    /**
-     * Matches the double quote character.
-     */
-    private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
-    /**
-     * Matches the double quote character.
-     */
-    private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
-    /**
-     * Matches the single or double quote character.
-     */
-    private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray());
-    /**
-     * Matches no characters.
-     */
-    private static final StrMatcher NONE_MATCHER = new NoMatcher();
-
-    // -----------------------------------------------------------------------
-
-    /**
-     * Returns a matcher which matches the comma character.
-     *
-     * @return a matcher for a comma
-     */
-    public static StrMatcher commaMatcher() {
-        return COMMA_MATCHER;
-    }
-
-    /**
-     * Returns a matcher which matches the tab character.
-     *
-     * @return a matcher for a tab
-     */
-    public static StrMatcher tabMatcher() {
-        return TAB_MATCHER;
-    }
-
-    /**
-     * Returns a matcher which matches the space character.
-     *
-     * @return a matcher for a space
-     */
-    public static StrMatcher spaceMatcher() {
-        return SPACE_MATCHER;
-    }
-
-    /**
-     * Matches the same characters as StringTokenizer,
-     * namely space, tab, newline and formfeed.
-     *
-     * @return the split matcher
-     */
-    public static StrMatcher splitMatcher() {
-        return SPLIT_MATCHER;
-    }
-
-    /**
-     * Matches the String trim() whitespace characters.
-     *
-     * @return the trim matcher
-     */
-    public static StrMatcher trimMatcher() {
-        return TRIM_MATCHER;
-    }
-
-    /**
-     * Returns a matcher which matches the single quote character.
-     *
-     * @return a matcher for a single quote
-     */
-    public static StrMatcher singleQuoteMatcher() {
-        return SINGLE_QUOTE_MATCHER;
-    }
-
-    /**
-     * Returns a matcher which matches the double quote character.
-     *
-     * @return a matcher for a double quote
-     */
-    public static StrMatcher doubleQuoteMatcher() {
-        return DOUBLE_QUOTE_MATCHER;
-    }
-
-    /**
-     * Returns a matcher which matches the single or double quote character.
-     *
-     * @return a matcher for a single or double quote
-     */
-    public static StrMatcher quoteMatcher() {
-        return QUOTE_MATCHER;
-    }
-
-    /**
-     * Matches no characters.
-     *
-     * @return a matcher that matches nothing
-     */
-    public static StrMatcher noneMatcher() {
-        return NONE_MATCHER;
-    }
-
-    /**
-     * Constructor that creates a matcher from a character.
-     *
-     * @param ch  the character to match, must not be null
-     * @return a new Matcher for the given char
-     */
-    public static StrMatcher charMatcher(final char ch) {
-        return new CharMatcher(ch);
-    }
-
-    /**
-     * Constructor that creates a matcher from a set of characters.
-     *
-     * @param chars  the characters to match, null or empty matches nothing
-     * @return a new matcher for the given char[]
-     */
-    public static StrMatcher charSetMatcher(final char... chars) {
-        if (chars == null || chars.length == 0) {
-            return NONE_MATCHER;
-        }
-        if (chars.length == 1) {
-            return new CharMatcher(chars[0]);
-        }
-        return new CharSetMatcher(chars);
-    }
-
-    /**
-     * Constructor that creates a matcher from a string representing a set of characters.
-     *
-     * @param chars  the characters to match, null or empty matches nothing
-     * @return a new Matcher for the given characters
-     */
-    public static StrMatcher charSetMatcher(final String chars) {
-        if (chars == null || chars.length() == 0) {
-            return NONE_MATCHER;
-        }
-        if (chars.length() == 1) {
-            return new CharMatcher(chars.charAt(0));
-        }
-        return new CharSetMatcher(chars.toCharArray());
-    }
-
-    /**
-     * Constructor that creates a matcher from a string.
-     *
-     * @param str  the string to match, null or empty matches nothing
-     * @return a new Matcher for the given String
-     */
-    public static StrMatcher stringMatcher(final String str) {
-        if (str == null || str.length() == 0) {
-            return NONE_MATCHER;
-        }
-        return new StringMatcher(str);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Constructor.
-     */
-    protected StrMatcher() {
-        super();
-    }
-
-    /**
-     * Returns the number of matching characters, zero for no match.
-     * <p>
-     * This method is called to check for a match.
-     * The parameter <code>pos</code> represents the current position to be
-     * checked in the string <code>buffer</code> (a character array which must
-     * not be changed).
-     * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
-     * <p>
-     * The character array may be larger than the active area to be matched.
-     * Only values in the buffer between the specified indices may be accessed.
-     * <p>
-     * The matching code may check one character or many.
-     * It may check characters preceding <code>pos</code> as well as those
-     * after, so long as no checks exceed the bounds specified.
-     * <p>
-     * It must return zero for no match, or a positive number if a match was found.
-     * The number indicates the number of characters that matched.
-     *
-     * @param buffer  the text content to match against, do not change
-     * @param pos  the starting position for the match, valid for buffer
-     * @param bufferStart  the first active index in the buffer, valid for buffer
-     * @param bufferEnd  the end index (exclusive) of the active buffer, valid for buffer
-     * @return the number of matching characters, zero for no match
-     */
-    public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
-
-    /**
-     * Returns the number of matching characters, zero for no match.
-     * <p>
-     * This method is called to check for a match.
-     * The parameter <code>pos</code> represents the current position to be
-     * checked in the string <code>buffer</code> (a character array which must
-     * not be changed).
-     * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
-     * <p>
-     * The matching code may check one character or many.
-     * It may check characters preceding <code>pos</code> as well as those after.
-     * <p>
-     * It must return zero for no match, or a positive number if a match was found.
-     * The number indicates the number of characters that matched.
-     *
-     * @param buffer  the text content to match against, do not change
-     * @param pos  the starting position for the match, valid for buffer
-     * @return the number of matching characters, zero for no match
-     */
-    public int isMatch(final char[] buffer, final int pos) {
-        return isMatch(buffer, pos, 0, buffer.length);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Class used to define a set of characters for matching purposes.
-     */
-    static final class CharSetMatcher extends StrMatcher {
-        /** The set of characters to match. */
-        private final char[] chars;
-
-        /**
-         * Constructor that creates a matcher from a character array.
-         *
-         * @param chars  the characters to match, must not be null
-         */
-        CharSetMatcher(final char chars[]) {
-            super();
-            this.chars = chars.clone();
-            Arrays.sort(this.chars);
-        }
-
-        /**
-         * Returns whether or not the given character matches.
-         *
-         * @param buffer  the text content to match against, do not change
-         * @param pos  the starting position for the match, valid for buffer
-         * @param bufferStart  the first active index in the buffer, valid for buffer
-         * @param bufferEnd  the end index of the active buffer, valid for buffer
-         * @return the number of matching characters, zero for no match
-         */
-        @Override
-        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
-            return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Class used to define a character for matching purposes.
-     */
-    static final class CharMatcher extends StrMatcher {
-        /** The character to match. */
-        private final char ch;
-
-        /**
-         * Constructor that creates a matcher that matches a single character.
-         *
-         * @param ch  the character to match
-         */
-        CharMatcher(final char ch) {
-            super();
-            this.ch = ch;
-        }
-
-        /**
-         * Returns whether or not the given character matches.
-         *
-         * @param buffer  the text content to match against, do not change
-         * @param pos  the starting position for the match, valid for buffer
-         * @param bufferStart  the first active index in the buffer, valid for buffer
-         * @param bufferEnd  the end index of the active buffer, valid for buffer
-         * @return the number of matching characters, zero for no match
-         */
-        @Override
-        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
-            return ch == buffer[pos] ? 1 : 0;
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Class used to define a set of characters for matching purposes.
-     */
-    static final class StringMatcher extends StrMatcher {
-        /** The string to match, as a character array. */
-        private final char[] chars;
-
-        /**
-         * Constructor that creates a matcher from a String.
-         *
-         * @param str  the string to match, must not be null
-         */
-        StringMatcher(final String str) {
-            super();
-            chars = str.toCharArray();
-        }
-
-        /**
-         * Returns whether or not the given text matches the stored string.
-         *
-         * @param buffer  the text content to match against, do not change
-         * @param pos  the starting position for the match, valid for buffer
-         * @param bufferStart  the first active index in the buffer, valid for buffer
-         * @param bufferEnd  the end index of the active buffer, valid for buffer
-         * @return the number of matching characters, zero for no match
-         */
-        @Override
-        public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
-            final int len = chars.length;
-            if (pos + len > bufferEnd) {
-                return 0;
-            }
-            for (int i = 0; i < chars.length; i++, pos++) {
-                if (chars[i] != buffer[pos]) {
-                    return 0;
-                }
-            }
-            return len;
-        }
-        
-        @Override
-        public String toString() {
-            return super.toString() + ' ' + Arrays.toString(chars);
-        }
-
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Class used to match no characters.
-     */
-    static final class NoMatcher extends StrMatcher {
-
-        /**
-         * Constructs a new instance of <code>NoMatcher</code>.
-         */
-        NoMatcher() {
-            super();
-        }
-
-        /**
-         * Always returns <code>false</code>.
-         *
-         * @param buffer  the text content to match against, do not change
-         * @param pos  the starting position for the match, valid for buffer
-         * @param bufferStart  the first active index in the buffer, valid for buffer
-         * @param bufferEnd  the end index of the active buffer, valid for buffer
-         * @return the number of matching characters, zero for no match
-         */
-        @Override
-        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
-            return 0;
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Class used to match whitespace as per trim().
-     */
-    static final class TrimMatcher extends StrMatcher {
-
-        /**
-         * Constructs a new instance of <code>TrimMatcher</code>.
-         */
-        TrimMatcher() {
-            super();
-        }
-
-        /**
-         * Returns whether or not the given character matches.
-         *
-         * @param buffer  the text content to match against, do not change
-         * @param pos  the starting position for the match, valid for buffer
-         * @param bufferStart  the first active index in the buffer, valid for buffer
-         * @param bufferEnd  the end index of the active buffer, valid for buffer
-         * @return the number of matching characters, zero for no match
-         */
-        @Override
-        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
-            return buffer[pos] <= 32 ? 1 : 0;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/StrSubstitutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StrSubstitutor.java b/src/main/java/org/apache/commons/text/beta/StrSubstitutor.java
deleted file mode 100644
index 0599f07..0000000
--- a/src/main/java/org/apache/commons/text/beta/StrSubstitutor.java
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * Substitutes variables within a string by values.
- * <p>
- * This class takes a piece of text and substitutes all the variables within it.
- * The default definition of a variable is <code>${variableName}</code>.
- * The prefix and suffix can be changed via constructors and set methods.
- * <p>
- * Variable values are typically resolved from a map, but could also be resolved
- * from system properties, or by supplying a custom variable resolver.
- * <p>
- * The simplest example is to use this class to replace Java System properties. For example:
- * <pre>
- * StrSubstitutor.replaceSystemProperties(
- *      "You are running with java.version = ${java.version} and os.name = ${os.name}.");
- * </pre>
- * <p>
- * Typical usage of this class follows the following pattern: First an instance is created
- * and initialized with the map that contains the values for the available variables.
- * If a prefix and/or suffix for variables should be used other than the default ones,
- * the appropriate settings can be performed. After that the <code>replace()</code>
- * method can be called passing in the source text for interpolation. In the returned
- * text all variable references (as long as their values are known) will be resolved.
- * The following example demonstrates this:
- * <pre>
- * Map valuesMap = HashMap();
- * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
- * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
- * String templateString = &quot;The ${animal} jumped over the ${target}.&quot;;
- * StrSubstitutor sub = new StrSubstitutor(valuesMap);
- * String resolvedString = sub.replace(templateString);
- * </pre>
- * yielding:
- * <pre>
- *      The quick brown fox jumped over the lazy dog.
- * </pre>
- * <p>
- * Also, this class allows to set a default value for unresolved variables.
- * The default value for a variable can be appended to the variable name after the variable
- * default value delimiter. The default value of the variable default value delimiter is ':-',
- * as in bash and other *nix shells, as those are arguably where the default ${} delimiter set originated.
- * The variable default value delimiter can be manually set by calling {@link #setValueDelimiterMatcher(StrMatcher)},
- * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}.
- * The following shows an example with variable default value settings:
- * <pre>
- * Map valuesMap = HashMap();
- * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
- * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
- * String templateString = &quot;The ${animal} jumped over the ${target}. ${undefined.number:-1234567890}.&quot;;
- * StrSubstitutor sub = new StrSubstitutor(valuesMap);
- * String resolvedString = sub.replace(templateString);
- * </pre>
- * yielding:
- * <pre>
- *      The quick brown fox jumped over the lazy dog. 1234567890.
- * </pre>
- * <p>
- * In addition to this usage pattern there are some static convenience methods that
- * cover the most common use cases. These methods can be used without the need of
- * manually creating an instance. However if multiple replace operations are to be
- * performed, creating and reusing an instance of this class will be more efficient.
- * <p>
- * Variable replacement works in a recursive way. Thus, if a variable value contains
- * a variable then that variable will also be replaced. Cyclic replacements are
- * detected and will cause an exception to be thrown.
- * <p>
- * Sometimes the interpolation's result must contain a variable prefix. As an example
- * take the following source text:
- * <pre>
- *   The variable ${${name}} must be used.
- * </pre>
- * Here only the variable's name referred to in the text should be replaced resulting
- * in the text (assuming that the value of the <code>name</code> variable is <code>x</code>):
- * <pre>
- *   The variable ${x} must be used.
- * </pre>
- * To achieve this effect there are two possibilities: Either set a different prefix
- * and suffix for variables which do not conflict with the result text you want to
- * produce. The other possibility is to use the escape character, by default '$'.
- * If this character is placed before a variable reference, this reference is ignored
- * and won't be replaced. For example:
- * <pre>
- *   The variable $${${name}} must be used.
- * </pre>
- * <p>
- * In some complex scenarios you might even want to perform substitution in the
- * names of variables, for instance
- * <pre>
- * ${jre-${java.specification.version}}
- * </pre>
- * <code>StrSubstitutor</code> supports this recursive substitution in variable
- * names, but it has to be enabled explicitly by setting the
- * {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables}
- * property to <b>true</b>.
- * <p>This class is <b>not</b> thread safe.</p>
- *
- * @since 1.0
- */
-public class StrSubstitutor {
-
-    /**
-     * Constant for the default escape character.
-     */
-    public static final char DEFAULT_ESCAPE = '$';
-    /**
-     * Constant for the default variable prefix.
-     */
-    public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${");
-    /**
-     * Constant for the default variable suffix.
-     */
-    public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}");
-    /**
-     * Constant for the default value delimiter of a variable.
-     */
-    public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(":-");
-
-    /**
-     * Stores the escape character.
-     */
-    private char escapeChar;
-    /**
-     * Stores the variable prefix.
-     */
-    private StrMatcher prefixMatcher;
-    /**
-     * Stores the variable suffix.
-     */
-    private StrMatcher suffixMatcher;
-    /**
-     * Stores the default variable value delimiter
-     */
-    private StrMatcher valueDelimiterMatcher;
-    /**
-     * Variable resolution is delegated to an implementor of VariableResolver.
-     */
-    private StrLookup<?> variableResolver;
-    /**
-     * The flag whether substitution in variable names is enabled.
-     */
-    private boolean enableSubstitutionInVariables;
-    /**
-     * Whether escapes should be preserved.  Default is false;
-     */
-    private boolean preserveEscapes = false;
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables in the given source object with
-     * their matching values from the map.
-     *
-     * @param <V> the type of the values in the map
-     * @param source  the source text containing the variables to substitute, null returns null
-     * @param valueMap  the map with the values, may be null
-     * @return the result of the replace operation
-     */
-    public static <V> String replace(final Object source, final Map<String, V> valueMap) {
-        return new StrSubstitutor(valueMap).replace(source);
-    }
-
-    /**
-     * Replaces all the occurrences of variables in the given source object with
-     * their matching values from the map. This method allows to specifiy a
-     * custom variable prefix and suffix
-     *
-     * @param <V> the type of the values in the map
-     * @param source  the source text containing the variables to substitute, null returns null
-     * @param valueMap  the map with the values, may be null
-     * @param prefix  the prefix of variables, not null
-     * @param suffix  the suffix of variables, not null
-     * @return the result of the replace operation
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public static <V> String replace(final Object source, final Map<String, V> valueMap, final String prefix, final String suffix) {
-        return new StrSubstitutor(valueMap, prefix, suffix).replace(source);
-    }
-
-    /**
-     * Replaces all the occurrences of variables in the given source object with their matching
-     * values from the properties.
-     *
-     * @param source the source text containing the variables to substitute, null returns null
-     * @param valueProperties the properties with values, may be null
-     * @return the result of the replace operation
-     */
-    public static String replace(final Object source, final Properties valueProperties) {
-        if (valueProperties == null) {
-            return source.toString();
-        }
-        final Map<String,String> valueMap = new HashMap<>();
-        final Enumeration<?> propNames = valueProperties.propertyNames();
-        while (propNames.hasMoreElements()) {
-            final String propName = (String)propNames.nextElement();
-            final String propValue = valueProperties.getProperty(propName);
-            valueMap.put(propName, propValue);
-        }
-        return StrSubstitutor.replace(source, valueMap);
-    }
-
-    /**
-     * Replaces all the occurrences of variables in the given source object with
-     * their matching values from the system properties.
-     *
-     * @param source  the source text containing the variables to substitute, null returns null
-     * @return the result of the replace operation
-     */
-    public static String replaceSystemProperties(final Object source) {
-        return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Creates a new instance with defaults for variable prefix and suffix
-     * and the escaping character.
-     */
-    public StrSubstitutor() {
-        this((StrLookup<?>) null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
-    }
-
-    /**
-     * Creates a new instance and initializes it. Uses defaults for variable
-     * prefix and suffix and the escaping character.
-     *
-     * @param <V> the type of the values in the map
-     * @param valueMap  the map with the variables' values, may be null
-     */
-    public <V> StrSubstitutor(final Map<String, V> valueMap) {
-        this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
-    }
-
-    /**
-     * Creates a new instance and initializes it. Uses a default escaping character.
-     *
-     * @param <V> the type of the values in the map
-     * @param valueMap  the map with the variables' values, may be null
-     * @param prefix  the prefix for variables, not null
-     * @param suffix  the suffix for variables, not null
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public <V> StrSubstitutor(final Map<String, V> valueMap, final String prefix, final String suffix) {
-        this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param <V> the type of the values in the map
-     * @param valueMap  the map with the variables' values, may be null
-     * @param prefix  the prefix for variables, not null
-     * @param suffix  the suffix for variables, not null
-     * @param escape  the escape character
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public <V> StrSubstitutor(final Map<String, V> valueMap, final String prefix, final String suffix,
-                              final char escape) {
-        this(StrLookup.mapLookup(valueMap), prefix, suffix, escape);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param <V> the type of the values in the map
-     * @param valueMap  the map with the variables' values, may be null
-     * @param prefix  the prefix for variables, not null
-     * @param suffix  the suffix for variables, not null
-     * @param escape  the escape character
-     * @param valueDelimiter  the variable default value delimiter, may be null
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public <V> StrSubstitutor(final Map<String, V> valueMap, final String prefix, final String suffix,
-                              final char escape, final String valueDelimiter) {
-        this(StrLookup.mapLookup(valueMap), prefix, suffix, escape, valueDelimiter);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param variableResolver  the variable resolver, may be null
-     */
-    public StrSubstitutor(final StrLookup<?> variableResolver) {
-        this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param variableResolver  the variable resolver, may be null
-     * @param prefix  the prefix for variables, not null
-     * @param suffix  the suffix for variables, not null
-     * @param escape  the escape character
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public StrSubstitutor(final StrLookup<?> variableResolver, final String prefix, final String suffix,
-                          final char escape) {
-        this.setVariableResolver(variableResolver);
-        this.setVariablePrefix(prefix);
-        this.setVariableSuffix(suffix);
-        this.setEscapeChar(escape);
-        this.setValueDelimiterMatcher(DEFAULT_VALUE_DELIMITER);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param variableResolver  the variable resolver, may be null
-     * @param prefix  the prefix for variables, not null
-     * @param suffix  the suffix for variables, not null
-     * @param escape  the escape character
-     * @param valueDelimiter  the variable default value delimiter string, may be null
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public StrSubstitutor(final StrLookup<?> variableResolver, final String prefix, final String suffix,
-                          final char escape, final String valueDelimiter) {
-        this.setVariableResolver(variableResolver);
-        this.setVariablePrefix(prefix);
-        this.setVariableSuffix(suffix);
-        this.setEscapeChar(escape);
-        this.setValueDelimiter(valueDelimiter);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param variableResolver  the variable resolver, may be null
-     * @param prefixMatcher  the prefix for variables, not null
-     * @param suffixMatcher  the suffix for variables, not null
-     * @param escape  the escape character
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public StrSubstitutor(
-            final StrLookup<?> variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher,
-            final char escape) {
-        this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER);
-    }
-
-    /**
-     * Creates a new instance and initializes it.
-     *
-     * @param variableResolver  the variable resolver, may be null
-     * @param prefixMatcher  the prefix for variables, not null
-     * @param suffixMatcher  the suffix for variables, not null
-     * @param escape  the escape character
-     * @param valueDelimiterMatcher  the variable default value delimiter matcher, may be null
-     * @throws IllegalArgumentException if the prefix or suffix is null
-     */
-    public StrSubstitutor(
-            final StrLookup<?> variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher,
-            final char escape, final StrMatcher valueDelimiterMatcher) {
-        this.setVariableResolver(variableResolver);
-        this.setVariablePrefixMatcher(prefixMatcher);
-        this.setVariableSuffixMatcher(suffixMatcher);
-        this.setEscapeChar(escape);
-        this.setValueDelimiterMatcher(valueDelimiterMatcher);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source string as a template.
-     *
-     * @param source  the string to replace in, null returns null
-     * @return the result of the replace operation
-     */
-    public String replace(final String source) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(source);
-        if (substitute(buf, 0, source.length()) == false) {
-            return source;
-        }
-        return buf.toString();
-    }
-
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source string as a template.
-     * <p>
-     * Only the specified portion of the string will be processed.
-     * The rest of the string is not processed, and is not returned.
-     *
-     * @param source  the string to replace in, null returns null
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the array to be processed, must be valid
-     * @return the result of the replace operation
-     */
-    public String replace(final String source, final int offset, final int length) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        if (substitute(buf, 0, length) == false) {
-            return source.substring(offset, offset + length);
-        }
-        return buf.toString();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source array as a template.
-     * The array is not altered by this method.
-     *
-     * @param source  the character array to replace in, not altered, null returns null
-     * @return the result of the replace operation
-     */
-    public String replace(final char[] source) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(source.length).append(source);
-        substitute(buf, 0, source.length);
-        return buf.toString();
-    }
-
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source array as a template.
-     * The array is not altered by this method.
-     * <p>
-     * Only the specified portion of the array will be processed.
-     * The rest of the array is not processed, and is not returned.
-     *
-     * @param source  the character array to replace in, not altered, null returns null
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the array to be processed, must be valid
-     * @return the result of the replace operation
-     */
-    public String replace(final char[] source, final int offset, final int length) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        substitute(buf, 0, length);
-        return buf.toString();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source buffer as a template.
-     * The buffer is not altered by this method.
-     *
-     * @param source  the buffer to use as a template, not changed, null returns null
-     * @return the result of the replace operation
-     */
-    public String replace(final StringBuffer source) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(source.length()).append(source);
-        substitute(buf, 0, buf.length());
-        return buf.toString();
-    }
-
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source buffer as a template.
-     * The buffer is not altered by this method.
-     * <p>
-     * Only the specified portion of the buffer will be processed.
-     * The rest of the buffer is not processed, and is not returned.
-     *
-     * @param source  the buffer to use as a template, not changed, null returns null
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the array to be processed, must be valid
-     * @return the result of the replace operation
-     */
-    public String replace(final StringBuffer source, final int offset, final int length) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        substitute(buf, 0, length);
-        return buf.toString();
-    }
-
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source as a template.
-     * The source is not altered by this method.
-     *
-     * @param source  the buffer to use as a template, not changed, null returns null
-     * @return the result of the replace operation
-     */
-    public String replace(final CharSequence source) {
-        if (source == null) {
-            return null;
-        }
-        return replace(source, 0, source.length());
-    }
-
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source as a template.
-     * The source is not altered by this method.
-     * <p>
-     * Only the specified portion of the buffer will be processed.
-     * The rest of the buffer is not processed, and is not returned.
-     *
-     * @param source  the buffer to use as a template, not changed, null returns null
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the array to be processed, must be valid
-     * @return the result of the replace operation
-     */
-    public String replace(final CharSequence source, final int offset, final int length) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        substitute(buf, 0, length);
-        return buf.toString();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source builder as a template.
-     * The builder is not altered by this method.
-     *
-     * @param source  the builder to use as a template, not changed, null returns null
-     * @return the result of the replace operation
-     */
-    public String replace(final StrBuilder source) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(source.length()).append(source);
-        substitute(buf, 0, buf.length());
-        return buf.toString();
-    }
-
-    /**
-     * Replaces all the occurrences of variables with their matching values
-     * from the resolver using the given source builder as a template.
-     * The builder is not altered by this method.
-     * <p>
-     * Only the specified portion of the builder will be processed.
-     * The rest of the builder is not processed, and is not returned.
-     *
-     * @param source  the builder to use as a template, not changed, null returns null
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the array to be processed, must be valid
-     * @return the result of the replace operation
-     */
-    public String replace(final StrBuilder source, final int offset, final int length) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        substitute(buf, 0, length);
-        return buf.toString();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables in the given source object with
-     * their matching values from the resolver. The input source object is
-     * converted to a string using <code>toString</code> and is not altered.
-     *
-     * @param source  the source to replace in, null returns null
-     * @return the result of the replace operation
-     */
-    public String replace(final Object source) {
-        if (source == null) {
-            return null;
-        }
-        final StrBuilder buf = new StrBuilder().append(source);
-        substitute(buf, 0, buf.length());
-        return buf.toString();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables within the given source buffer
-     * with their matching values from the resolver.
-     * The buffer is updated with the result.
-     *
-     * @param source  the buffer to replace in, updated, null returns zero
-     * @return true if altered
-     */
-    public boolean replaceIn(final StringBuffer source) {
-        if (source == null) {
-            return false;
-        }
-        return replaceIn(source, 0, source.length());
-    }
-
-    /**
-     * Replaces all the occurrences of variables within the given source buffer
-     * with their matching values from the resolver.
-     * The buffer is updated with the result.
-     * <p>
-     * Only the specified portion of the buffer will be processed.
-     * The rest of the buffer is not processed, but it is not deleted.
-     *
-     * @param source  the buffer to replace in, updated, null returns zero
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the buffer to be processed, must be valid
-     * @return true if altered
-     */
-    public boolean replaceIn(final StringBuffer source, final int offset, final int length) {
-        if (source == null) {
-            return false;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        if (substitute(buf, 0, length) == false) {
-            return false;
-        }
-        source.replace(offset, offset + length, buf.toString());
-        return true;
-    }
-
-  //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables within the given source buffer
-     * with their matching values from the resolver.
-     * The buffer is updated with the result.
-     *
-     * @param source  the buffer to replace in, updated, null returns zero
-     * @return true if altered
-     */
-    public boolean replaceIn(final StringBuilder source) {
-        if (source == null) {
-            return false;
-        }
-        return replaceIn(source, 0, source.length());
-    }
-
-    /**
-     * Replaces all the occurrences of variables within the given source builder
-     * with their matching values from the resolver.
-     * The builder is updated with the result.
-     * <p>
-     * Only the specified portion of the buffer will be processed.
-     * The rest of the buffer is not processed, but it is not deleted.
-     *
-     * @param source  the buffer to replace in, updated, null returns zero
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the buffer to be processed, must be valid
-     * @return true if altered
-     */
-    public boolean replaceIn(final StringBuilder source, final int offset, final int length) {
-        if (source == null) {
-            return false;
-        }
-        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        if (substitute(buf, 0, length) == false) {
-            return false;
-        }
-        source.replace(offset, offset + length, buf.toString());
-        return true;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all the occurrences of variables within the given source
-     * builder with their matching values from the resolver.
-     *
-     * @param source  the builder to replace in, updated, null returns zero
-     * @return true if altered
-     */
-    public boolean replaceIn(final StrBuilder source) {
-        if (source == null) {
-            return false;
-        }
-        return substitute(source, 0, source.length());
-    }
-
-    /**
-     * Replaces all the occurrences of variables within the given source
-     * builder with their matching values from the resolver.
-     * <p>
-     * Only the specified portion of the builder will be processed.
-     * The rest of the builder is not processed, but it is not deleted.
-     *
-     * @param source  the builder to replace in, null returns zero
-     * @param offset  the start offset within the array, must be valid
-     * @param length  the length within the builder to be processed, must be valid
-     * @return true if altered
-     */
-    public boolean replaceIn(final StrBuilder source, final int offset, final int length) {
-        if (source == null) {
-            return false;
-        }
-        return substitute(source, offset, length);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Internal method that substitutes the variables.
-     * <p>
-     * Most users of this class do not need to call this method. This method will
-     * be called automatically by another (public) method.
-     * <p>
-     * Writers of subclasses can override this method if they need access to
-     * the substitution process at the start or end.
-     *
-     * @param buf  the string builder to substitute into, not null
-     * @param offset  the start offset within the builder, must be valid
-     * @param length  the length within the builder to be processed, must be valid
-     * @return true if altered
-     */
-    protected boolean substitute(final StrBuilder buf, final int offset, final int length) {
-        return substitute(buf, offset, length, null) > 0;
-    }
-
-    /**
-     * Recursive handler for multiple levels of interpolation. This is the main
-     * interpolation method, which resolves the values of all variable references
-     * contained in the passed in text.
-     *
-     * @param buf  the string builder to substitute into, not null
-     * @param offset  the start offset within the builder, must be valid
-     * @param length  the length within the builder to be processed, must be valid
-     * @param priorVariables  the stack keeping track of the replaced variables, may be null
-     * @return the length change that occurs, unless priorVariables is null when the int
-     *  represents a boolean flag as to whether any change occurred.
-     */
-    private int substitute(final StrBuilder buf, final int offset, final int length, List<String> priorVariables) {
-        final StrMatcher pfxMatcher = getVariablePrefixMatcher();
-        final StrMatcher suffMatcher = getVariableSuffixMatcher();
-        final char escape = getEscapeChar();
-        final StrMatcher valueDelimMatcher = getValueDelimiterMatcher();
-        final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables();
-
-        final boolean top = priorVariables == null;
-        boolean altered = false;
-        int lengthChange = 0;
-        char[] chars = buf.buffer;
-        int bufEnd = offset + length;
-        int pos = offset;
-        while (pos < bufEnd) {
-            final int startMatchLen = pfxMatcher.isMatch(chars, pos, offset,
-                    bufEnd);
-            if (startMatchLen == 0) {
-                pos++;
-            } else {
-                // found variable start marker
-                if (pos > offset && chars[pos - 1] == escape) {
-                    // escaped
-                    if (preserveEscapes) {
-                        pos++;
-                        continue;
-                    }
-                    buf.deleteCharAt(pos - 1);
-                    chars = buf.buffer; // in case buffer was altered
-                    lengthChange--;
-                    altered = true;
-                    bufEnd--;
-                } else {
-                    // find suffix
-                    final int startPos = pos;
-                    pos += startMatchLen;
-                    int endMatchLen = 0;
-                    int nestedVarCount = 0;
-                    while (pos < bufEnd) {
-                        if (substitutionInVariablesEnabled
-                                && (endMatchLen = pfxMatcher.isMatch(chars,
-                                        pos, offset, bufEnd)) != 0) {
-                            // found a nested variable start
-                            nestedVarCount++;
-                            pos += endMatchLen;
-                            continue;
-                        }
-
-                        endMatchLen = suffMatcher.isMatch(chars, pos, offset,
-                                bufEnd);
-                        if (endMatchLen == 0) {
-                            pos++;
-                        } else {
-                            // found variable end marker
-                            if (nestedVarCount == 0) {
-                                String varNameExpr = new String(chars, startPos
-                                        + startMatchLen, pos - startPos
-                                        - startMatchLen);
-                                if (substitutionInVariablesEnabled) {
-                                    final StrBuilder bufName = new StrBuilder(varNameExpr);
-                                    substitute(bufName, 0, bufName.length());
-                                    varNameExpr = bufName.toString();
-                                }
-                                pos += endMatchLen;
-                                final int endPos = pos;
-
-                                String varName = varNameExpr;
-                                String varDefaultValue = null;
-
-                                if (valueDelimMatcher != null) {
-                                    final char [] varNameExprChars = varNameExpr.toCharArray();
-                                    int valueDelimiterMatchLen = 0;
-                                    for (int i = 0; i < varNameExprChars.length; i++) {
-                                        // if there's any nested variable when nested variable substitution disabled, then stop resolving name and default value.
-                                        if (!substitutionInVariablesEnabled
-                                                && pfxMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) {
-                                            break;
-                                        }
-                                        if ((valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, i)) != 0) {
-                                            varName = varNameExpr.substring(0, i);
-                                            varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
-                                            break;
-                                        }
-                                    }
-                                }
-
-                                // on the first call initialize priorVariables
-                                if (priorVariables == null) {
-                                    priorVariables = new ArrayList<>();
-                                    priorVariables.add(new String(chars,
-                                            offset, length));
-                                }
-
-                                // handle cyclic substitution
-                                checkCyclicSubstitution(varName, priorVariables);
-                                priorVariables.add(varName);
-
-                                // resolve the variable
-                                String varValue = resolveVariable(varName, buf,
-                                        startPos, endPos);
-                                if (varValue == null) {
-                                    varValue = varDefaultValue;
-                                }
-                                if (varValue != null) {
-                                    // recursive replace
-                                    final int varLen = varValue.length();
-                                    buf.replace(startPos, endPos, varValue);
-                                    altered = true;
-                                    int change = substitute(buf, startPos,
-                                            varLen, priorVariables);
-                                    change = change
-                                            + varLen - (endPos - startPos);
-                                    pos += change;
-                                    bufEnd += change;
-                                    lengthChange += change;
-                                    chars = buf.buffer; // in case buffer was
-                                                        // altered
-                                }
-
-                                // remove variable from the cyclic stack
-                                priorVariables
-                                        .remove(priorVariables.size() - 1);
-                                break;
-                            }
-                            nestedVarCount--;
-                            pos += endMatchLen;
-                        }
-                    }
-                }
-            }
-        }
-        if (top) {
-            return altered ? 1 : 0;
-        }
-        return lengthChange;
-    }
-
-    /**
-     * Checks if the specified variable is already in the stack (list) of variables.
-     *
-     * @param varName  the variable name to check
-     * @param priorVariables  the list of prior variables
-     */
-    private void checkCyclicSubstitution(final String varName, final List<String> priorVariables) {
-        if (priorVariables.contains(varName) == false) {
-            return;
-        }
-        final StrBuilder buf = new StrBuilder(256);
-        buf.append("Infinite loop in property interpolation of ");
-        buf.append(priorVariables.remove(0));
-        buf.append(": ");
-        buf.appendWithSeparators(priorVariables, "->");
-        throw new IllegalStateException(buf.toString());
-    }
-
-    /**
-     * Internal method that resolves the value of a variable.
-     * <p>
-     * Most users of this class do not need to call this method. This method is
-     * called automatically by the substitution process.
-     * <p>
-     * Writers of subclasses can override this method if they need to alter
-     * how each substitution occurs. The method is passed the variable's name
-     * and must return the corresponding value. This implementation uses the
-     * {@link #getVariableResolver()} with the variable's name as the key.
-     *
-     * @param variableName  the name of the variable, not null
-     * @param buf  the buffer where the substitution is occurring, not null
-     * @param startPos  the start position of the variable including the prefix, valid
-     * @param endPos  the end position of the variable including the suffix, valid
-     * @return the variable's value or <b>null</b> if the variable is unknown
-     */
-    protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) {
-        final StrLookup<?> resolver = getVariableResolver();
-        if (resolver == null) {
-            return null;
-        }
-        return resolver.lookup(variableName);
-    }
-
-    // Escape
-    //-----------------------------------------------------------------------
-    /**
-     * Returns the escape character.
-     *
-     * @return the character used for escaping variable references
-     */
-    public char getEscapeChar() {
-        return this.escapeChar;
-    }
-
-    /**
-     * Sets the escape character.
-     * If this character is placed before a variable reference in the source
-     * text, this variable will be ignored.
-     *
-     * @param escapeCharacter  the escape character (0 for disabling escaping)
-     */
-    public void setEscapeChar(final char escapeCharacter) {
-        this.escapeChar = escapeCharacter;
-    }
-
-    // Prefix
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the variable prefix matcher currently in use.
-     * <p>
-     * The variable prefix is the characer or characters that identify the
-     * start of a variable. This prefix is expressed in terms of a matcher
-     * allowing advanced prefix matches.
-     *
-     * @return the prefix matcher in use
-     */
-    public StrMatcher getVariablePrefixMatcher() {
-        return prefixMatcher;
-    }
-
-    /**
-     * Sets the variable prefix matcher currently in use.
-     * <p>
-     * The variable prefix is the characer or characters that identify the
-     * start of a variable. This prefix is expressed in terms of a matcher
-     * allowing advanced prefix matches.
-     *
-     * @param prefixMatcher  the prefix matcher to use, null ignored
-     * @return this, to enable chaining
-     * @throws IllegalArgumentException if the prefix matcher is null
-     */
-    public StrSubstitutor setVariablePrefixMatcher(final StrMatcher prefixMatcher) {
-        if (prefixMatcher == null) {
-            throw new IllegalArgumentException("Variable prefix matcher must not be null!");
-        }
-        this.prefixMatcher = prefixMatcher;
-        return this;
-    }
-
-    /**
-     * Sets the variable prefix to use.
-     * <p>
-     * The variable prefix is the character or characters that identify the
-     * start of a variable. This method allows a single character prefix to
-     * be easily set.
-     *
-     * @param prefix  the prefix character to use
-     * @return this, to enable chaining
-     */
-    public StrSubstitutor setVariablePrefix(final char prefix) {
-        return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix));
-    }
-
-    /**
-     * Sets the variable prefix to use.
-     * <p>
-     * The variable prefix is the characer or characters that identify the
-     * start of a variable. This method allows a string prefix to be easily set.
-     *
-     * @param prefix  the prefix for variables, not null
-     * @return this, to enable chaining
-     * @throws IllegalArgumentException if the prefix is null
-     */
-    public StrSubstitutor setVariablePrefix(final String prefix) {
-       if (prefix == null) {
-            throw new IllegalArgumentException("Variable prefix must not be null!");
-        }
-        return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix));
-    }
-
-    // Suffix
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the variable suffix matcher currently in use.
-     * <p>
-     * The variable suffix is the characer or characters that identify the
-     * end of a variable. This suffix is expressed in terms of a matcher
-     * allowing advanced suffix matches.
-     *
-     * @return the suffix matcher in use
-     */
-    public StrMatcher getVariableSuffixMatcher() {
-        return suffixMatcher;
-    }
-
-    /**
-     * Sets the variable suffix matcher currently in use.
-     * <p>
-     * The variable suffix is the characer or characters that identify the
-     * end of a variable. This suffix is expressed in terms of a matcher
-     * allowing advanced suffix matches.
-     *
-     * @param suffixMatcher  the suffix matcher to use, null ignored
-     * @return this, to enable chaining
-     * @throws IllegalArgumentException if the suffix matcher is null
-     */
-    public StrSubstitutor setVariableSuffixMatcher(final StrMatcher suffixMatcher) {
-        if (suffixMatcher == null) {
-            throw new IllegalArgumentException("Variable suffix matcher must not be null!");
-        }
-        this.suffixMatcher = suffixMatcher;
-        return this;
-    }
-
-    /**
-     * Sets the variable suffix to use.
-     * <p>
-     * The variable suffix is the characer or characters that identify the
-     * end of a variable. This method allows a single character suffix to
-     * be easily set.
-     *
-     * @param suffix  the suffix character to use
-     * @return this, to enable chaining
-     */
-    public StrSubstitutor setVariableSuffix(final char suffix) {
-        return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix));
-    }
-
-    /**
-     * Sets the variable suffix to use.
-     * <p>
-     * The variable suffix is the character or characters that identify the
-     * end of a variable. This method allows a string suffix to be easily set.
-     *
-     * @param suffix  the suffix for variables, not null
-     * @return this, to enable chaining
-     * @throws IllegalArgumentException if the suffix is null
-     */
-    public StrSubstitutor setVariableSuffix(final String suffix) {
-       if (suffix == null) {
-            throw new IllegalArgumentException("Variable suffix must not be null!");
-        }
-        return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix));
-    }
-
-    // Variable Default Value Delimiter
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the variable default value delimiter matcher currently in use.
-     * <p>
-     * The variable default value delimiter is the characer or characters that delimite the
-     * variable name and the variable default value. This delimiter is expressed in terms of a matcher
-     * allowing advanced variable default value delimiter matches.
-     * <p>
-     * If it returns null, then the variable default value resolution is disabled.
-     *
-     * @return the variable default value delimiter matcher in use, may be null
-     */
-    public StrMatcher getValueDelimiterMatcher() {
-        return valueDelimiterMatcher;
-    }
-
-    /**
-     * Sets the variable default value delimiter matcher to use.
-     * <p>
-     * The variable default value delimiter is the characer or characters that delimite the
-     * variable name and the variable default value. This delimiter is expressed in terms of a matcher
-     * allowing advanced variable default value delimiter matches.
-     * <p>
-     * If the <code>valueDelimiterMatcher</code> is null, then the variable default value resolution
-     * becomes disabled.
-     *
-     * @param valueDelimiterMatcher  variable default value delimiter matcher to use, may be null
-     * @return this, to enable chaining
-     */
-    public StrSubstitutor setValueDelimiterMatcher(final StrMatcher valueDelimiterMatcher) {
-        this.valueDelimiterMatcher = valueDelimiterMatcher;
-        return this;
-    }
-
-    /**
-     * Sets the variable default value delimiter to use.
-     * <p>
-     * The variable default value delimiter is the characer or characters that delimite the
-     * variable name and the variable default value. This method allows a single character
-     * variable default value delimiter to be easily set.
-     *
-     * @param valueDelimiter  the variable default value delimiter character to use
-     * @return this, to enable chaining
-     */
-    public StrSubstitutor setValueDelimiter(final char valueDelimiter) {
-        return setValueDelimiterMatcher(StrMatcher.charMatcher(valueDelimiter));
-    }
-
-    /**
-     * Sets the variable default value delimiter to use.
-     * <p>
-     * The variable default value delimiter is the characer or characters that delimite the
-     * variable name and the variable default value. This method allows a string
-     * variable default value delimiter to be easily set.
-     * <p>
-     * If the <code>valueDelimiter</code> is null or empty string, then the variable default
-     * value resolution becomes disabled.
-     *
-     * @param valueDelimiter  the variable default value delimiter string to use, may be null or empty
-     * @return this, to enable chaining
-     */
-    public StrSubstitutor setValueDelimiter(final String valueDelimiter) {
-        if (valueDelimiter == null || valueDelimiter.length() == 0) {
-            setValueDelimiterMatcher(null);
-            return this;
-        }
-        return setValueDelimiterMatcher(StrMatcher.stringMatcher(valueDelimiter));
-    }
-
-    // Resolver
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the VariableResolver that is used to lookup variables.
-     *
-     * @return the VariableResolver
-     */
-    public StrLookup<?> getVariableResolver() {
-        return this.variableResolver;
-    }
-
-    /**
-     * Sets the VariableResolver that is used to lookup variables.
-     *
-     * @param variableResolver  the VariableResolver
-     */
-    public void setVariableResolver(final StrLookup<?> variableResolver) {
-        this.variableResolver = variableResolver;
-    }
-
-    // Substitution support in variable names
-    //-----------------------------------------------------------------------
-    /**
-     * Returns a flag whether substitution is done in variable names.
-     *
-     * @return the substitution in variable names flag
-     */
-    public boolean isEnableSubstitutionInVariables() {
-        return enableSubstitutionInVariables;
-    }
-
-    /**
-     * Sets a flag whether substitution is done in variable names. If set to
-     * <b>true</b>, the names of variables can contain other variables which are
-     * processed first before the original variable is evaluated, e.g.
-     * <code>${jre-${java.version}}</code>. The default value is <b>false</b>.
-     *
-     * @param enableSubstitutionInVariables the new value of the flag
-     */
-    public void setEnableSubstitutionInVariables(
-            final boolean enableSubstitutionInVariables) {
-        this.enableSubstitutionInVariables = enableSubstitutionInVariables;
-    }
-
-    /**
-     * Returns the flag controlling whether escapes are preserved during
-     * substitution.
-     * 
-     * @return the preserve escape flag
-     */
-    public boolean isPreserveEscapes() {
-        return preserveEscapes;
-    }
-
-    /**
-     * Sets a flag controlling whether escapes are preserved during
-     * substitution.  If set to <b>true</b>, the escape character is retained
-     * during substitution (e.g. <code>$${this-is-escaped}</code> remains
-     * <code>$${this-is-escaped}</code>).  If set to <b>false</b>, the escape
-     * character is removed during substitution (e.g.
-     * <code>$${this-is-escaped}</code> becomes
-     * <code>${this-is-escaped}</code>).  The default value is <b>false</b>
-     * 
-     * @param preserveEscapes true if escapes are to be preserved
-     */
-    public void setPreserveEscapes(final boolean preserveEscapes) {
-        this.preserveEscapes = preserveEscapes;
-    }
-}


[29/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
chore: update packages back to org.apache.commons.text.*


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/c7cf533d
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/c7cf533d
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/c7cf533d

Branch: refs/heads/release
Commit: c7cf533d2f1e22624d8210194ade266e97e6f7a0
Parents: 348aa51
Author: Rob Tompkins <ch...@apache.org>
Authored: Fri Feb 10 08:17:04 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Fri Feb 10 08:17:04 2017 -0500

----------------------------------------------------------------------
 fb-excludes.xml                                 |    4 +-
 .../apache/commons/text/AlphabetConverter.java  |  530 +++
 .../java/org/apache/commons/text/Builder.java   |   88 +
 .../apache/commons/text/CharacterPredicate.java |   37 +
 .../commons/text/CharacterPredicates.java       |   52 +
 .../apache/commons/text/CompositeFormat.java    |  116 +
 .../commons/text/ExtendedMessageFormat.java     |  571 ++++
 .../org/apache/commons/text/FormatFactory.java  |   41 +
 .../apache/commons/text/FormattableUtils.java   |  156 +
 .../org/apache/commons/text/StrBuilder.java     | 3092 ++++++++++++++++++
 .../java/org/apache/commons/text/StrLookup.java |  180 +
 .../org/apache/commons/text/StrMatcher.java     |  438 +++
 .../org/apache/commons/text/StrSubstitutor.java | 1213 +++++++
 .../org/apache/commons/text/StrTokenizer.java   | 1118 +++++++
 .../apache/commons/text/StringEscapeUtils.java  |  959 ++++++
 .../commons/text/beta/AlphabetConverter.java    |  530 ---
 .../org/apache/commons/text/beta/Builder.java   |   88 -
 .../commons/text/beta/CharacterPredicate.java   |   37 -
 .../commons/text/beta/CharacterPredicates.java  |   52 -
 .../commons/text/beta/CompositeFormat.java      |  116 -
 .../text/beta/ExtendedMessageFormat.java        |  571 ----
 .../apache/commons/text/beta/FormatFactory.java |   41 -
 .../commons/text/beta/FormattableUtils.java     |  156 -
 .../apache/commons/text/beta/StrBuilder.java    | 3092 ------------------
 .../org/apache/commons/text/beta/StrLookup.java |  180 -
 .../apache/commons/text/beta/StrMatcher.java    |  438 ---
 .../commons/text/beta/StrSubstitutor.java       | 1213 -------
 .../apache/commons/text/beta/StrTokenizer.java  | 1118 -------
 .../commons/text/beta/StringEscapeUtils.java    |  959 ------
 .../commons/text/beta/diff/CommandVisitor.java  |  146 -
 .../commons/text/beta/diff/DeleteCommand.java   |   56 -
 .../commons/text/beta/diff/EditCommand.java     |   88 -
 .../commons/text/beta/diff/EditScript.java      |  133 -
 .../commons/text/beta/diff/InsertCommand.java   |   58 -
 .../commons/text/beta/diff/KeepCommand.java     |   58 -
 .../text/beta/diff/ReplacementsFinder.java      |  124 -
 .../text/beta/diff/ReplacementsHandler.java     |   52 -
 .../text/beta/diff/StringsComparator.java       |  331 --
 .../commons/text/beta/diff/package-info.java    |   25 -
 .../apache/commons/text/beta/package-info.java  |   22 -
 .../text/beta/similarity/CosineDistance.java    |   57 -
 .../text/beta/similarity/CosineSimilarity.java  |  102 -
 .../commons/text/beta/similarity/Counter.java   |   62 -
 .../text/beta/similarity/EditDistance.java      |   59 -
 .../text/beta/similarity/EditDistanceFrom.java  |  112 -
 .../text/beta/similarity/FuzzyScore.java        |  144 -
 .../text/beta/similarity/HammingDistance.java   |   78 -
 .../text/beta/similarity/JaccardDistance.java   |   55 -
 .../text/beta/similarity/JaccardSimilarity.java |   88 -
 .../beta/similarity/JaroWinklerDistance.java    |  157 -
 .../similarity/LevenshteinDetailedDistance.java |  519 ---
 .../beta/similarity/LevenshteinDistance.java    |  396 ---
 .../beta/similarity/LevenshteinResults.java     |  125 -
 .../similarity/LongestCommonSubsequence.java    |  144 -
 .../LongestCommonSubsequenceDistance.java       |   64 -
 .../text/beta/similarity/RegexTokenizer.java    |   52 -
 .../text/beta/similarity/SimilarityScore.java   |   63 -
 .../beta/similarity/SimilarityScoreFrom.java    |  112 -
 .../commons/text/beta/similarity/Tokenizer.java |   35 -
 .../text/beta/similarity/package-info.java      |   44 -
 .../beta/translate/AggregateTranslator.java     |   65 -
 .../beta/translate/CharSequenceTranslator.java  |  135 -
 .../beta/translate/CodePointTranslator.java     |   51 -
 .../text/beta/translate/CsvTranslators.java     |   82 -
 .../text/beta/translate/EntityArrays.java       |  445 ---
 .../text/beta/translate/JavaUnicodeEscaper.java |  113 -
 .../text/beta/translate/LookupTranslator.java   |  100 -
 .../beta/translate/NumericEntityEscaper.java    |  118 -
 .../beta/translate/NumericEntityUnescaper.java  |  138 -
 .../text/beta/translate/OctalUnescaper.java     |   79 -
 .../beta/translate/SingleLookupTranslator.java  |  147 -
 .../beta/translate/SinglePassTranslator.java    |   54 -
 .../text/beta/translate/UnicodeEscaper.java     |  137 -
 .../text/beta/translate/UnicodeUnescaper.java   |   64 -
 .../UnicodeUnpairedSurrogateRemover.java        |   42 -
 .../text/beta/translate/package-info.java       |   24 -
 .../commons/text/diff/CommandVisitor.java       |  146 +
 .../apache/commons/text/diff/DeleteCommand.java |   56 +
 .../apache/commons/text/diff/EditCommand.java   |   88 +
 .../apache/commons/text/diff/EditScript.java    |  133 +
 .../apache/commons/text/diff/InsertCommand.java |   58 +
 .../apache/commons/text/diff/KeepCommand.java   |   58 +
 .../commons/text/diff/ReplacementsFinder.java   |  124 +
 .../commons/text/diff/ReplacementsHandler.java  |   52 +
 .../commons/text/diff/StringsComparator.java    |  331 ++
 .../apache/commons/text/diff/package-info.java  |   25 +
 .../org/apache/commons/text/package-info.java   |   22 +
 .../commons/text/similarity/CosineDistance.java |   57 +
 .../text/similarity/CosineSimilarity.java       |  102 +
 .../apache/commons/text/similarity/Counter.java |   62 +
 .../commons/text/similarity/EditDistance.java   |   59 +
 .../text/similarity/EditDistanceFrom.java       |  112 +
 .../commons/text/similarity/FuzzyScore.java     |  144 +
 .../text/similarity/HammingDistance.java        |   78 +
 .../text/similarity/JaccardDistance.java        |   55 +
 .../text/similarity/JaccardSimilarity.java      |   88 +
 .../text/similarity/JaroWinklerDistance.java    |  157 +
 .../similarity/LevenshteinDetailedDistance.java |  519 +++
 .../text/similarity/LevenshteinDistance.java    |  396 +++
 .../text/similarity/LevenshteinResults.java     |  125 +
 .../similarity/LongestCommonSubsequence.java    |  144 +
 .../LongestCommonSubsequenceDistance.java       |   64 +
 .../commons/text/similarity/RegexTokenizer.java |   52 +
 .../text/similarity/SimilarityScore.java        |   63 +
 .../text/similarity/SimilarityScoreFrom.java    |  112 +
 .../commons/text/similarity/Tokenizer.java      |   35 +
 .../commons/text/similarity/package-info.java   |   44 +
 .../text/translate/AggregateTranslator.java     |   65 +
 .../text/translate/CharSequenceTranslator.java  |  135 +
 .../text/translate/CodePointTranslator.java     |   51 +
 .../commons/text/translate/CsvTranslators.java  |   82 +
 .../commons/text/translate/EntityArrays.java    |  445 +++
 .../text/translate/JavaUnicodeEscaper.java      |  113 +
 .../text/translate/LookupTranslator.java        |  100 +
 .../text/translate/NumericEntityEscaper.java    |  118 +
 .../text/translate/NumericEntityUnescaper.java  |  138 +
 .../commons/text/translate/OctalUnescaper.java  |   79 +
 .../text/translate/SingleLookupTranslator.java  |  147 +
 .../text/translate/SinglePassTranslator.java    |   54 +
 .../commons/text/translate/UnicodeEscaper.java  |  137 +
 .../text/translate/UnicodeUnescaper.java        |   64 +
 .../UnicodeUnpairedSurrogateRemover.java        |   42 +
 .../commons/text/translate/package-info.java    |   24 +
 .../commons/text/AlphabetConverterTest.java     |  204 ++
 .../commons/text/CharacterPredicatesTest.java   |   47 +
 .../commons/text/CompositeFormatTest.java       |   85 +
 .../commons/text/ExtendedMessageFormatTest.java |  497 +++
 .../commons/text/FormattableUtilsTest.java      |  142 +
 .../text/StrBuilderAppendInsertTest.java        | 1605 +++++++++
 .../org/apache/commons/text/StrBuilderTest.java | 2007 ++++++++++++
 .../org/apache/commons/text/StrLookupTest.java  |  115 +
 .../org/apache/commons/text/StrMatcherTest.java |  214 ++
 .../apache/commons/text/StrSubstitutorTest.java |  740 +++++
 .../apache/commons/text/StrTokenizerTest.java   |  913 ++++++
 .../commons/text/StringEscapeUtilsTest.java     |  601 ++++
 .../text/beta/AlphabetConverterTest.java        |  204 --
 .../text/beta/CharacterPredicatesTest.java      |   47 -
 .../commons/text/beta/CompositeFormatTest.java  |   85 -
 .../text/beta/ExtendedMessageFormatTest.java    |  497 ---
 .../commons/text/beta/FormattableUtilsTest.java |  142 -
 .../text/beta/StrBuilderAppendInsertTest.java   | 1605 ---------
 .../commons/text/beta/StrBuilderTest.java       | 2007 ------------
 .../apache/commons/text/beta/StrLookupTest.java |  115 -
 .../commons/text/beta/StrMatcherTest.java       |  214 --
 .../commons/text/beta/StrSubstitutorTest.java   |  740 -----
 .../commons/text/beta/StrTokenizerTest.java     |  914 ------
 .../text/beta/StringEscapeUtilsTest.java        |  601 ----
 .../text/beta/diff/ReplacementsFinderTest.java  |  108 -
 .../text/beta/diff/StringsComparatorTest.java   |  126 -
 .../beta/similarity/CosineDistanceTest.java     |   70 -
 .../text/beta/similarity/FuzzyScoreTest.java    |   64 -
 .../beta/similarity/HammingDistanceTest.java    |   58 -
 .../beta/similarity/JaccardDistanceTest.java    |   67 -
 .../beta/similarity/JaccardSimilarityTest.java  |   67 -
 .../similarity/JaroWinklerDistanceTest.java     |   62 -
 .../LevenshteinDetailedDistanceTest.java        |  402 ---
 .../similarity/LevenshteinDistanceTest.java     |  139 -
 .../LongestCommonSubsequenceDistanceTest.java   |   68 -
 .../LongestCommonSubsequenceTest.java           |   99 -
 .../ParameterizedEditDistanceFromTest.java      |   90 -
 .../ParameterizedLevenshteinDistanceTest.java   |  125 -
 .../ParameterizedSimilarityScoreFromTest.java   |   81 -
 .../beta/similarity/StringMetricFromTest.java   |   66 -
 .../beta/translate/AggregateTranslatorTest.java |   66 -
 .../text/beta/translate/EntityArraysTest.java   |  129 -
 .../beta/translate/JavaUnicodeEscaperTest.java  |   65 -
 .../beta/translate/LookupTranslatorTest.java    |   57 -
 .../translate/NumericEntityEscaperTest.java     |   68 -
 .../translate/NumericEntityUnescaperTest.java   |   80 -
 .../text/beta/translate/OctalUnescaperTest.java |   82 -
 .../translate/SinglePassTranslatorTest.java     |   57 -
 .../text/beta/translate/UnicodeEscaperTest.java |   55 -
 .../beta/translate/UnicodeUnescaperTest.java    |   60 -
 .../UnicodeUnpairedSurrogateRemoverTest.java    |   47 -
 .../text/diff/ReplacementsFinderTest.java       |  108 +
 .../text/diff/StringsComparatorTest.java        |  126 +
 .../text/similarity/CosineDistanceTest.java     |   70 +
 .../commons/text/similarity/FuzzyScoreTest.java |   64 +
 .../text/similarity/HammingDistanceTest.java    |   58 +
 .../text/similarity/JaccardDistanceTest.java    |   67 +
 .../text/similarity/JaccardSimilarityTest.java  |   67 +
 .../similarity/JaroWinklerDistanceTest.java     |   62 +
 .../LevenshteinDetailedDistanceTest.java        |  402 +++
 .../similarity/LevenshteinDistanceTest.java     |  139 +
 .../LongestCommonSubsequenceDistanceTest.java   |   68 +
 .../LongestCommonSubsequenceTest.java           |   99 +
 .../ParameterizedEditDistanceFromTest.java      |   90 +
 .../ParameterizedLevenshteinDistanceTest.java   |  125 +
 .../ParameterizedSimilarityScoreFromTest.java   |   81 +
 .../text/similarity/StringMetricFromTest.java   |   66 +
 .../text/translate/AggregateTranslatorTest.java |   66 +
 .../text/translate/EntityArraysTest.java        |  129 +
 .../text/translate/JavaUnicodeEscaperTest.java  |   65 +
 .../text/translate/LookupTranslatorTest.java    |   57 +
 .../translate/NumericEntityEscaperTest.java     |   68 +
 .../translate/NumericEntityUnescaperTest.java   |   80 +
 .../text/translate/OctalUnescaperTest.java      |   82 +
 .../translate/SinglePassTranslatorTest.java     |   57 +
 .../text/translate/UnicodeEscaperTest.java      |   55 +
 .../text/translate/UnicodeUnescaperTest.java    |   60 +
 .../UnicodeUnpairedSurrogateRemoverTest.java    |   47 +
 201 files changed, 23576 insertions(+), 23577 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/fb-excludes.xml
----------------------------------------------------------------------
diff --git a/fb-excludes.xml b/fb-excludes.xml
index 0ad46c4..30cf5d9 100644
--- a/fb-excludes.xml
+++ b/fb-excludes.xml
@@ -18,12 +18,12 @@
 <FindBugsFilter>
 
   <Match>
-    <Class name="org.apache.commons.text.beta.ExtendedMessageFormat" />
+    <Class name="org.apache.commons.text.ExtendedMessageFormat" />
     <Bug code="UR" />
   </Match>
 
   <Match>
-    <Class name="org.apache.commons.text.beta.StrTokenizer" />
+    <Class name="org.apache.commons.text.StrTokenizer" />
     <Method name="clone" />
     <Bug code="CN" />
   </Match>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/AlphabetConverter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/AlphabetConverter.java b/src/main/java/org/apache/commons/text/AlphabetConverter.java
new file mode 100644
index 0000000..27de69a
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/AlphabetConverter.java
@@ -0,0 +1,530 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * <p>
+ * Convert from one alphabet to another, with the possibility of leaving certain
+ * characters unencoded.
+ * </p>
+ *
+ * <p>
+ * The target and do not encode languages must be in the Unicode BMP, but the
+ * source language does not.
+ * </p>
+ *
+ * <p>
+ * The encoding will all be of a fixed length, except for the 'do not encode'
+ * chars, which will be of length 1
+ * </p>
+ *
+ * <h3>Sample usage</h3>
+ *
+ * <pre>
+ * Character[] originals; // a, b, c, d
+ * Character[] encoding; // 0, 1, d
+ * Character[] doNotEncode; // d
+ *
+ * AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originals,
+ * encoding, doNotEncode);
+ *
+ * ac.encode("a"); // 00
+ * ac.encode("b"); // 01
+ * ac.encode("c"); // 0d
+ * ac.encode("d"); // d
+ * ac.encode("abcd"); // 00010dd
+ * </pre>
+ *
+ * <p>
+ * #ThreadSafe# AlphabetConverter class methods are threadsafe as they do not
+ * change internal state.
+ * </p>
+ *
+ * @since 1.0
+ *
+ */
+public final class AlphabetConverter {
+
+    /**
+     * Original string to be encoded.
+     */
+    private final Map<Integer, String> originalToEncoded;
+    /**
+     * Encoding alphabet.
+     */
+    private final Map<String, String> encodedToOriginal;
+    /**
+     * Length of the encoded letter.
+     */
+    private final int encodedLetterLength;
+    /**
+     * Arrow constant, used for converting the object into a string.
+     */
+    private static final String ARROW = " -> ";
+    /**
+     * Line separator, used for converting the object into a string.
+     */
+    private static final String LINE_SEPARATOR =
+            System.getProperty("line.separator");
+
+    /**
+     * Hidden constructor for alphabet converter. Used by static helper methods.
+     *
+     * @param originalToEncoded original string to be encoded
+     * @param encodedToOriginal encoding alphabet
+     * @param encodedLetterLength length of the encoded letter
+     */
+    private AlphabetConverter(final Map<Integer, String> originalToEncoded,
+                              final Map<String, String> encodedToOriginal,
+                              final int encodedLetterLength) {
+
+        this.originalToEncoded = originalToEncoded;
+        this.encodedToOriginal = encodedToOriginal;
+        this.encodedLetterLength = encodedLetterLength;
+    }
+
+    /**
+     * Encode a given string.
+     *
+     * @param original the string to be encoded
+     * @return the encoded string, {@code null} if the given string is null
+     * @throws UnsupportedEncodingException if chars that are not supported are
+     *                                      encountered
+     */
+    public String encode(final String original)
+            throws UnsupportedEncodingException {
+        if (original == null) {
+            return null;
+        }
+
+        final StringBuilder sb = new StringBuilder();
+
+        for (int i = 0; i < original.length();) {
+            final int codepoint = original.codePointAt(i);
+
+            final String nextLetter = originalToEncoded.get(codepoint);
+
+            if (nextLetter == null) {
+                throw new UnsupportedEncodingException(
+                        "Couldn't find encoding for '"
+                                + codePointToString(codepoint)
+                                + "' in "
+                                + original
+                );
+            }
+
+            sb.append(nextLetter);
+
+            i += Character.charCount(codepoint);
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Decode a given string.
+     *
+     * @param encoded a string that has been encoded using this
+     *                AlphabetConverter
+     * @return the decoded string, {@code null} if the given string is null
+     * @throws UnsupportedEncodingException if unexpected characters that
+     *                                      cannot be handled are encountered
+     */
+    public String decode(final String encoded)
+            throws UnsupportedEncodingException {
+        if (encoded == null) {
+            return null;
+        }
+
+        final StringBuilder result = new StringBuilder();
+
+        for (int j = 0; j < encoded.length();) {
+            final Integer i = encoded.codePointAt(j);
+            final String s = codePointToString(i);
+
+            if (s.equals(originalToEncoded.get(i))) {
+                result.append(s);
+                j++; // because we do not encode in Unicode extended the
+                     // length of each encoded char is 1
+            } else {
+                if (j + encodedLetterLength > encoded.length()) {
+                    throw new UnsupportedEncodingException("Unexpected end "
+                            + "of string while decoding " + encoded);
+                }
+                final String nextGroup = encoded.substring(j,
+                        j + encodedLetterLength);
+                final String next = encodedToOriginal.get(nextGroup);
+                if (next == null) {
+                    throw new UnsupportedEncodingException(
+                            "Unexpected string without decoding ("
+                                    + nextGroup + ") in " + encoded);
+                }
+                result.append(next);
+                j += encodedLetterLength;
+            }
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Get the length of characters in the encoded alphabet that are necessary
+     * for each character in the original
+     * alphabet.
+     *
+     * @return the length of the encoded char
+     */
+    public int getEncodedCharLength() {
+        return encodedLetterLength;
+    }
+
+    /**
+     * Get the mapping from integer code point of source language to encoded
+     * string. Use to reconstruct converter from
+     * serialized map.
+     *
+     * @return the original map
+     */
+    public Map<Integer, String> getOriginalToEncoded() {
+        return Collections.unmodifiableMap(originalToEncoded);
+    }
+
+    /**
+     * Recursive method used when creating encoder/decoder.
+     *
+     * @param level at which point it should add a single encoding
+     * @param currentEncoding current encoding
+     * @param encoding letters encoding
+     * @param originals original values
+     * @param doNotEncodeMap map of values that should not be encoded
+     */
+    @SuppressWarnings("PMD")
+    private void addSingleEncoding(final int level,
+                                   final String currentEncoding,
+                                   final Collection<Integer> encoding,
+                                   final Iterator<Integer> originals,
+                                   final Map<Integer, String> doNotEncodeMap) {
+
+        if (level > 0) {
+            for (final int encodingLetter : encoding) {
+                if (originals.hasNext()) {
+
+                    // this skips the doNotEncode chars if they are in the
+                    // leftmost place
+                    if (level != encodedLetterLength
+                            || !doNotEncodeMap.containsKey(encodingLetter)) {
+                        addSingleEncoding(level - 1,
+                                currentEncoding
+                                        + codePointToString(encodingLetter),
+                                encoding,
+                                originals,
+                                doNotEncodeMap
+                        );
+                    }
+                } else {
+                    return; // done encoding all the original alphabet
+                }
+            }
+        } else {
+            Integer next = originals.next();
+
+            while (doNotEncodeMap.containsKey(next)) {
+                final String originalLetterAsString = codePointToString(next);
+
+                originalToEncoded.put(next, originalLetterAsString);
+                encodedToOriginal.put(originalLetterAsString,
+                        originalLetterAsString);
+
+                if (!originals.hasNext()) {
+                    return;
+                }
+
+                next = originals.next();
+            }
+
+            final String originalLetterAsString = codePointToString(next);
+
+            originalToEncoded.put(next, currentEncoding);
+            encodedToOriginal.put(currentEncoding, originalLetterAsString);
+        }
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+
+        for (final Entry<Integer, String> entry
+                : originalToEncoded.entrySet()) {
+            sb.append(codePointToString(entry.getKey()))
+                    .append(ARROW)
+                    .append(entry.getValue()).append(LINE_SEPARATOR);
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof AlphabetConverter)) {
+            return false;
+        }
+        final AlphabetConverter other = (AlphabetConverter) obj;
+        return originalToEncoded.equals(other.originalToEncoded)
+                && encodedToOriginal.equals(other.encodedToOriginal)
+                && encodedLetterLength == other.encodedLetterLength;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(originalToEncoded,
+                encodedToOriginal,
+                encodedLetterLength);
+    }
+
+    // -- static methods
+
+    /**
+     * Create a new converter from a map.
+     *
+     * @param originalToEncoded a map returned from getOriginalToEncoded()
+     * @return the reconstructed AlphabetConverter
+     * @see AlphabetConverter#getOriginalToEncoded()
+     */
+    public static AlphabetConverter createConverterFromMap(
+            final Map<Integer, String> originalToEncoded) {
+        final Map<Integer, String> unmodifiableOriginalToEncoded =
+                Collections.unmodifiableMap(originalToEncoded);
+        final Map<String, String> encodedToOriginal = new LinkedHashMap<>();
+        final Map<Integer, String> doNotEncodeMap = new HashMap<>();
+
+        int encodedLetterLength = 1;
+
+        for (final Entry<Integer, String> e
+                : unmodifiableOriginalToEncoded.entrySet()) {
+            final String originalAsString = codePointToString(e.getKey());
+            encodedToOriginal.put(e.getValue(), originalAsString);
+
+            if (e.getValue().equals(originalAsString)) {
+                doNotEncodeMap.put(e.getKey(), e.getValue());
+            }
+
+            if (e.getValue().length() > encodedLetterLength) {
+                encodedLetterLength = e.getValue().length();
+            }
+        }
+
+        return new AlphabetConverter(unmodifiableOriginalToEncoded,
+                encodedToOriginal,
+                encodedLetterLength);
+    }
+
+    /**
+     * Create an alphabet converter, for converting from the original alphabet,
+     * to the encoded alphabet, while leaving the characters in
+     * <em>doNotEncode</em> as they are (if possible).
+     *
+     * <p>Duplicate letters in either original or encoding will be ignored.</p>
+     *
+     * @param original an array of chars representing the original alphabet
+     * @param encoding an array of chars representing the alphabet to be used
+     *                 for encoding
+     * @param doNotEncode an array of chars to be encoded using the original
+     *                    alphabet - every char here must appear in
+     *                    both the previous params
+     * @return the AlphabetConverter
+     * @throws IllegalArgumentException if an AlphabetConverter cannot be
+     *                                  constructed
+     */
+    public static AlphabetConverter createConverterFromChars(
+            final Character[] original,
+            final Character[] encoding,
+            final Character[] doNotEncode) {
+        return AlphabetConverter.createConverter(
+                convertCharsToIntegers(original),
+                convertCharsToIntegers(encoding),
+                convertCharsToIntegers(doNotEncode));
+    }
+
+    /**
+     * Convert characters to integers.
+     *
+     * @param chars array of characters
+     * @return an equivalent array of integers
+     */
+    private static Integer[] convertCharsToIntegers(final Character[] chars) {
+        if (chars == null || chars.length == 0) {
+            return new Integer[0];
+        }
+        final Integer[] integers = new Integer[chars.length];
+        for (int i = 0; i < chars.length; i++) {
+            integers[i] = (int) chars[i];
+        }
+        return integers;
+    }
+
+    /**
+     * Create an alphabet converter, for converting from the original alphabet,
+     * to the encoded alphabet, while leaving
+     * the characters in <em>doNotEncode</em> as they are (if possible).
+     *
+     * <p>Duplicate letters in either original or encoding will be ignored.</p>
+     *
+     * @param original an array of ints representing the original alphabet in
+     *                 codepoints
+     * @param encoding an array of ints representing the alphabet to be used for
+     *                 encoding, in codepoints
+     * @param doNotEncode an array of ints representing the chars to be encoded
+     *                    using the original alphabet - every char
+     *                    here must appear in both the previous params
+     * @return the AlphabetConverter
+     * @throws IllegalArgumentException if an AlphabetConverter cannot be
+     *                                   constructed
+     */
+    public static AlphabetConverter createConverter(
+            final Integer[] original,
+            final Integer[] encoding,
+            final Integer[] doNotEncode) {
+        final Set<Integer> originalCopy = new LinkedHashSet<>(Arrays.<Integer> asList(original));
+        final Set<Integer> encodingCopy = new LinkedHashSet<>(Arrays.<Integer> asList(encoding));
+        final Set<Integer> doNotEncodeCopy = new LinkedHashSet<>(Arrays.<Integer> asList(doNotEncode));
+
+        final Map<Integer, String> originalToEncoded = new LinkedHashMap<>();
+        final Map<String, String> encodedToOriginal = new LinkedHashMap<>();
+        final Map<Integer, String> doNotEncodeMap = new HashMap<>();
+
+        int encodedLetterLength;
+
+        for (final int i : doNotEncodeCopy) {
+            if (!originalCopy.contains(i)) {
+                throw new IllegalArgumentException(
+                        "Can not use 'do not encode' list because original "
+                                + "alphabet does not contain '"
+                                + codePointToString(i) + "'");
+            }
+
+            if (!encodingCopy.contains(i)) {
+                throw new IllegalArgumentException(
+                        "Can not use 'do not encode' list because encoding alphabet does not contain '"
+                                + codePointToString(i) + "'");
+            }
+
+            doNotEncodeMap.put(i, codePointToString(i));
+        }
+
+        if (encodingCopy.size() >= originalCopy.size()) {
+            encodedLetterLength = 1;
+
+            final Iterator<Integer> it = encodingCopy.iterator();
+
+            for (final int originalLetter : originalCopy) {
+                final String originalLetterAsString =
+                        codePointToString(originalLetter);
+
+                if (doNotEncodeMap.containsKey(originalLetter)) {
+                    originalToEncoded.put(originalLetter,
+                            originalLetterAsString);
+                    encodedToOriginal.put(originalLetterAsString,
+                            originalLetterAsString);
+                } else {
+                    Integer next = it.next();
+
+                    while (doNotEncodeCopy.contains(next)) {
+                        next = it.next();
+                    }
+
+                    final String encodedLetter = codePointToString(next);
+
+                    originalToEncoded.put(originalLetter, encodedLetter);
+                    encodedToOriginal.put(encodedLetter,
+                            originalLetterAsString);
+                }
+            }
+
+            return new AlphabetConverter(originalToEncoded,
+                    encodedToOriginal,
+                    encodedLetterLength);
+
+        } else if (encodingCopy.size() - doNotEncodeCopy.size() < 2) {
+            throw new IllegalArgumentException(
+                    "Must have at least two encoding characters (excluding "
+                            + "those in the 'do not encode' list), but has "
+                            + (encodingCopy.size() - doNotEncodeCopy.size()));
+        } else {
+            // we start with one which is our minimum, and because we do the
+            // first division outside the loop
+            int lettersSoFar = 1;
+
+            // the first division takes into account that the doNotEncode
+            // letters can't be in the leftmost place
+            int lettersLeft = (originalCopy.size() - doNotEncodeCopy.size())
+                    / (encodingCopy.size() - doNotEncodeCopy.size());
+
+            while (lettersLeft / encodingCopy.size() >= 1) {
+                lettersLeft = lettersLeft / encodingCopy.size();
+                lettersSoFar++;
+            }
+
+            encodedLetterLength = lettersSoFar + 1;
+
+            final AlphabetConverter ac =
+                    new AlphabetConverter(originalToEncoded,
+                            encodedToOriginal,
+                            encodedLetterLength);
+
+            ac.addSingleEncoding(encodedLetterLength,
+                    "",
+                    encodingCopy,
+                    originalCopy.iterator(),
+                    doNotEncodeMap);
+
+            return ac;
+        }
+    }
+
+    /**
+     * Create new String that contains just the given code point.
+     *
+     * @param i code point
+     * @return a new string with the new code point
+     * @see "http://www.oracle.com/us/technologies/java/supplementary-142654.html"
+     */
+    private static String codePointToString(final int i) {
+        if (Character.charCount(i) == 1) {
+            return String.valueOf((char) i);
+        }
+        return new String(Character.toChars(i));
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/Builder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/Builder.java b/src/main/java/org/apache/commons/text/Builder.java
new file mode 100644
index 0000000..c2c435c
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/Builder.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+/**
+ * <p>
+ * The Builder interface is designed to designate a class as a <em>builder</em>
+ * object in the Builder design pattern. Builders are capable of creating and
+ * configuring objects or results that normally take multiple steps to construct
+ * or are very complex to derive.
+ * </p>
+ *
+ * <p>
+ * The builder interface defines a single method, {@link #build()}, that
+ * classes must implement. The result of this method should be the final
+ * configured object or result after all building operations are performed.
+ * </p>
+ *
+ * <p>
+ * It is a recommended practice that the methods supplied to configure the
+ * object or result being built return a reference to {@code this} so that
+ * method calls can be chained together.
+ * </p>
+ *
+ * <p>
+ * Example Builder:
+ * <pre><code>
+ * class FontBuilder implements Builder&lt;Font&gt; {
+ *     private Font font;
+ *
+ *     public FontBuilder(String fontName) {
+ *         this.font = new Font(fontName, Font.PLAIN, 12);
+ *     }
+ *
+ *     public FontBuilder bold() {
+ *         this.font = this.font.deriveFont(Font.BOLD);
+ *         return this; // Reference returned so calls can be chained
+ *     }
+ *
+ *     public FontBuilder size(float pointSize) {
+ *         this.font = this.font.deriveFont(pointSize);
+ *         return this; // Reference returned so calls can be chained
+ *     }
+ *
+ *     // Other Font construction methods
+ *
+ *     public Font build() {
+ *         return this.font;
+ *     }
+ * }
+ * </code></pre>
+ *
+ * Example Builder Usage:
+ * <pre><code>
+ * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
+ *                                                              .size(14.0f)
+ *                                                              .build();
+ * </code></pre>
+ *
+ *
+ * @param <T> the type of object that the builder will construct or compute.
+ * @since 1.0
+ *
+ */
+public interface Builder<T> {
+
+    /**
+     * Returns a reference to the object being constructed or result being
+     * calculated by the builder.
+     *
+     * @return the object constructed or result calculated by the builder.
+     */
+    T build();
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/CharacterPredicate.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/CharacterPredicate.java b/src/main/java/org/apache/commons/text/CharacterPredicate.java
new file mode 100644
index 0000000..164432b
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/CharacterPredicate.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+/**
+ * A predicate for selecting code points. Implementations of this interface must
+ * be thread safe.
+ *
+ * @since 1.0
+ */
+public interface CharacterPredicate {
+
+    /**
+     * Tests the code point with this predicate.
+     *
+     * @param codePoint
+     *            the code point to test
+     * @return {@code true} if the code point matches the predicate,
+     *         {@code false} otherwise
+     * @since 1.0
+     */
+    boolean test(int codePoint);
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/CharacterPredicates.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/CharacterPredicates.java b/src/main/java/org/apache/commons/text/CharacterPredicates.java
new file mode 100644
index 0000000..a4544de
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/CharacterPredicates.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+/**
+ * <p>
+ * Commonly used implementations of {@link CharacterPredicate}. Per the interface
+ * requirements, all implementations are thread safe.
+ * </p>
+ *
+ * @since 1.0
+ */
+public enum CharacterPredicates implements CharacterPredicate {
+
+    /**
+     * Tests code points against {@link Character#isLetter(int)}.
+     *
+     * @since 1.0
+     */
+    LETTERS {
+        @Override
+        public boolean test(int codePoint) {
+            return Character.isLetter(codePoint);
+        }
+    },
+
+    /**
+     * Tests code points against {@link Character#isDigit(int)}.
+     *
+     * @since 1.0
+     */
+    DIGITS {
+        @Override
+        public boolean test(int codePoint) {
+            return Character.isDigit(codePoint);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/CompositeFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/CompositeFormat.java b/src/main/java/org/apache/commons/text/CompositeFormat.java
new file mode 100644
index 0000000..bbe5754
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/CompositeFormat.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParseException;
+import java.text.ParsePosition;
+
+/**
+ * Formats using one formatter and parses using a different formatter. An
+ * example of use for this would be a webapp where data is taken in one way and
+ * stored in a database another way.
+ *
+ * @since 1.0
+ */
+public class CompositeFormat extends Format {
+
+    /**
+     * Required for serialization support.
+     *
+     * @see java.io.Serializable
+     */
+    private static final long serialVersionUID = -4329119827877627683L;
+
+    /** The parser to use. */
+    private final Format parser;
+    /** The formatter to use. */
+    private final Format formatter;
+
+    /**
+     * Create a format that points its parseObject method to one implementation
+     * and its format method to another.
+     *
+     * @param parser implementation
+     * @param formatter implementation
+     */
+    public CompositeFormat(final Format parser, final Format formatter) {
+        this.parser = parser;
+        this.formatter = formatter;
+    }
+
+    /**
+     * Uses the formatter Format instance.
+     *
+     * @param obj the object to format
+     * @param toAppendTo the {@link StringBuffer} to append to
+     * @param pos the FieldPosition to use (or ignore).
+     * @return <code>toAppendTo</code>
+     * @see Format#format(Object, StringBuffer, FieldPosition)
+     */
+    @Override // Therefore has to use StringBuffer
+    public StringBuffer format(final Object obj, final StringBuffer toAppendTo,
+            final FieldPosition pos) {
+        return formatter.format(obj, toAppendTo, pos);
+    }
+
+    /**
+     * Uses the parser Format instance.
+     *
+     * @param source the String source
+     * @param pos the ParsePosition containing the position to parse from, will
+     *            be updated according to parsing success (index) or failure
+     *            (error index)
+     * @return the parsed Object
+     * @see Format#parseObject(String, ParsePosition)
+     */
+    @Override
+    public Object parseObject(final String source, final ParsePosition pos) {
+        return parser.parseObject(source, pos);
+    }
+
+    /**
+     * Provides access to the parser Format implementation.
+     *
+     * @return parser Format implementation
+     */
+    public Format getParser() {
+        return this.parser;
+    }
+
+    /**
+     * Provides access to the parser Format implementation.
+     *
+     * @return formatter Format implementation
+     */
+    public Format getFormatter() {
+        return this.formatter;
+    }
+
+    /**
+     * Utility method to parse and then reformat a String.
+     *
+     * @param input String to reformat
+     * @return A reformatted String
+     * @throws ParseException thrown by parseObject(String) call
+     */
+    public String reformat(final String input) throws ParseException {
+        return format(parseObject(input));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java b/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
new file mode 100644
index 0000000..2a08bbf
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/ExtendedMessageFormat.java
@@ -0,0 +1,571 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.text.Format;
+import java.text.MessageFormat;
+import java.text.ParsePosition;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Extends <code>java.text.MessageFormat</code> to allow pluggable/additional formatting
+ * options for embedded format elements.  Client code should specify a registry
+ * of <code>FormatFactory</code> instances associated with <code>String</code>
+ * format names.  This registry will be consulted when the format elements are
+ * parsed from the message pattern.  In this way custom patterns can be specified,
+ * and the formats supported by <code>java.text.MessageFormat</code> can be overridden
+ * at the format and/or format style level (see MessageFormat).  A "format element"
+ * embedded in the message pattern is specified (<b>()?</b> signifies optionality):<br>
+ * <code>{</code><i>argument-number</i><b>(</b><code>,</code><i>format-name</i><b>
+ * (</b><code>,</code><i>format-style</i><b>)?)?</b><code>}</code>
+ *
+ * <p>
+ * <i>format-name</i> and <i>format-style</i> values are trimmed of surrounding whitespace
+ * in the manner of <code>java.text.MessageFormat</code>.  If <i>format-name</i> denotes
+ * <code>FormatFactory formatFactoryInstance</code> in <code>registry</code>, a <code>Format</code>
+ * matching <i>format-name</i> and <i>format-style</i> is requested from
+ * <code>formatFactoryInstance</code>.  If this is successful, the <code>Format</code>
+ * found is used for this format element.
+ * </p>
+ *
+ * <p><b>NOTICE:</b> The various subformat mutator methods are considered unnecessary; they exist on the parent
+ * class to allow the type of customization which it is the job of this class to provide in
+ * a configurable fashion.  These methods have thus been disabled and will throw
+ * <code>UnsupportedOperationException</code> if called.
+ * </p>
+ *
+ * <p>Limitations inherited from <code>java.text.MessageFormat</code>:</p>
+ * <ul>
+ * <li>When using "choice" subformats, support for nested formatting instructions is limited
+ *     to that provided by the base class.</li>
+ * <li>Thread-safety of <code>Format</code>s, including <code>MessageFormat</code> and thus
+ *     <code>ExtendedMessageFormat</code>, is not guaranteed.</li>
+ * </ul>
+ *
+ * @since 1.0
+ */
+public class ExtendedMessageFormat extends MessageFormat {
+
+    /**
+     * Serializable Object.
+     */
+    private static final long serialVersionUID = -2362048321261811743L;
+
+    /**
+     * Our initial seed value for calculating hashes.
+     */
+    private static final int HASH_SEED = 31;
+
+    /**
+     * The empty string.
+     */
+    private static final String DUMMY_PATTERN = "";
+
+    /**
+     * A comma.
+     */
+    private static final char START_FMT = ',';
+
+    /**
+     * A right side squigly brace.
+     */
+    private static final char END_FE = '}';
+
+    /**
+     * A left side squigly brace.
+     */
+    private static final char START_FE = '{';
+
+    /**
+     * A properly escaped character representing a single quote.
+     */
+    private static final char QUOTE = '\'';
+
+    /**
+     * To pattern string.
+     */
+    private String toPattern;
+
+    /**
+     * Our registry of FormatFactory's.
+     */
+    private final Map<String, ? extends FormatFactory> registry;
+
+    /**
+     * Create a new ExtendedMessageFormat for the default locale.
+     *
+     * @param pattern  the pattern to use, not null
+     * @throws IllegalArgumentException in case of a bad pattern.
+     */
+    public ExtendedMessageFormat(final String pattern) {
+        this(pattern, Locale.getDefault());
+    }
+
+    /**
+     * Create a new ExtendedMessageFormat.
+     *
+     * @param pattern  the pattern to use, not null
+     * @param locale  the locale to use, not null
+     * @throws IllegalArgumentException in case of a bad pattern.
+     */
+    public ExtendedMessageFormat(final String pattern, final Locale locale) {
+        this(pattern, locale, null);
+    }
+
+    /**
+     * Create a new ExtendedMessageFormat for the default locale.
+     *
+     * @param pattern  the pattern to use, not null
+     * @param registry  the registry of format factories, may be null
+     * @throws IllegalArgumentException in case of a bad pattern.
+     */
+    public ExtendedMessageFormat(final String pattern,
+                                 final Map<String, ? extends FormatFactory> registry) {
+        this(pattern, Locale.getDefault(), registry);
+    }
+
+    /**
+     * Create a new ExtendedMessageFormat.
+     *
+     * @param pattern  the pattern to use, not null
+     * @param locale  the locale to use, not null
+     * @param registry  the registry of format factories, may be null
+     * @throws IllegalArgumentException in case of a bad pattern.
+     */
+    public ExtendedMessageFormat(final String pattern,
+                                 final Locale locale,
+                                 final Map<String, ? extends FormatFactory> registry) {
+        super(DUMMY_PATTERN);
+        setLocale(locale);
+        this.registry = registry;
+        applyPattern(pattern);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toPattern() {
+        return toPattern;
+    }
+
+    /**
+     * Apply the specified pattern.
+     *
+     * @param pattern String
+     */
+    @Override
+    public final void applyPattern(final String pattern) {
+        if (registry == null) {
+            super.applyPattern(pattern);
+            toPattern = super.toPattern();
+            return;
+        }
+        final ArrayList<Format> foundFormats = new ArrayList<>();
+        final ArrayList<String> foundDescriptions = new ArrayList<>();
+        final StringBuilder stripCustom = new StringBuilder(pattern.length());
+
+        final ParsePosition pos = new ParsePosition(0);
+        final char[] c = pattern.toCharArray();
+        int fmtCount = 0;
+        while (pos.getIndex() < pattern.length()) {
+            switch (c[pos.getIndex()]) {
+            case QUOTE:
+                appendQuotedString(pattern, pos, stripCustom);
+                break;
+            case START_FE:
+                fmtCount++;
+                seekNonWs(pattern, pos);
+                final int start = pos.getIndex();
+                final int index = readArgumentIndex(pattern, next(pos));
+                stripCustom.append(START_FE).append(index);
+                seekNonWs(pattern, pos);
+                Format format = null;
+                String formatDescription = null;
+                if (c[pos.getIndex()] == START_FMT) {
+                    formatDescription = parseFormatDescription(pattern,
+                            next(pos));
+                    format = getFormat(formatDescription);
+                    if (format == null) {
+                        stripCustom.append(START_FMT).append(formatDescription);
+                    }
+                }
+                foundFormats.add(format);
+                foundDescriptions.add(format == null ? null : formatDescription);
+                if (foundFormats.size() != fmtCount) {
+                    throw new IllegalArgumentException("The validated expression is false");
+                }
+                if (foundDescriptions.size() != fmtCount) {
+                    throw new IllegalArgumentException("The validated expression is false");
+                }
+                if (c[pos.getIndex()] != END_FE) {
+                    throw new IllegalArgumentException(
+                            "Unreadable format element at position " + start);
+                }
+                //$FALL-THROUGH$
+            default:
+                stripCustom.append(c[pos.getIndex()]);
+                next(pos);
+            }
+        }
+        super.applyPattern(stripCustom.toString());
+        toPattern = insertFormats(super.toPattern(), foundDescriptions);
+        if (containsElements(foundFormats)) {
+            final Format[] origFormats = getFormats();
+            // only loop over what we know we have, as MessageFormat on Java 1.3
+            // seems to provide an extra format element:
+            int i = 0;
+            for (final Iterator<Format> it = foundFormats.iterator(); it.hasNext(); i++) {
+                final Format f = it.next();
+                if (f != null) {
+                    origFormats[i] = f;
+                }
+            }
+            super.setFormats(origFormats);
+        }
+    }
+
+    /**
+     * Throws UnsupportedOperationException - see class Javadoc for details.
+     *
+     * @param formatElementIndex format element index
+     * @param newFormat the new format
+     * @throws UnsupportedOperationException always thrown since this isn't
+     *                                       supported by ExtendMessageFormat
+     */
+    @Override
+    public void setFormat(final int formatElementIndex, final Format newFormat) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws UnsupportedOperationException - see class Javadoc for details.
+     *
+     * @param argumentIndex argument index
+     * @param newFormat the new format
+     * @throws UnsupportedOperationException always thrown since this isn't
+     *                                       supported by ExtendMessageFormat
+     */
+    @Override
+    public void setFormatByArgumentIndex(final int argumentIndex,
+                                         final Format newFormat) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws UnsupportedOperationException - see class Javadoc for details.
+     *
+     * @param newFormats new formats
+     * @throws UnsupportedOperationException always thrown since this isn't
+     *                                       supported by ExtendMessageFormat
+     */
+    @Override
+    public void setFormats(final Format[] newFormats) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws UnsupportedOperationException - see class Javadoc for details.
+     *
+     * @param newFormats new formats
+     * @throws UnsupportedOperationException always thrown since this isn't
+     *                                       supported by ExtendMessageFormat
+     */
+    @Override
+    public void setFormatsByArgumentIndex(final Format[] newFormats) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Check if this extended message format is equal to another object.
+     *
+     * @param obj the object to compare to
+     * @return true if this object equals the other, otherwise false
+     */
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (!Objects.equals(getClass(), obj.getClass())) {
+          return false;
+        }
+        final ExtendedMessageFormat rhs = (ExtendedMessageFormat) obj;
+        if (!Objects.equals(toPattern, rhs.toPattern)) {
+            return false;
+        }
+        if (!Objects.equals(registry, rhs.registry)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = HASH_SEED * result + Objects.hashCode(registry);
+        result = HASH_SEED * result + Objects.hashCode(toPattern);
+        return result;
+    }
+
+    /**
+     * Get a custom format from a format description.
+     *
+     * @param desc String
+     * @return Format
+     */
+    private Format getFormat(final String desc) {
+        if (registry != null) {
+            String name = desc;
+            String args = null;
+            final int i = desc.indexOf(START_FMT);
+            if (i > 0) {
+                name = desc.substring(0, i).trim();
+                args = desc.substring(i + 1).trim();
+            }
+            final FormatFactory factory = registry.get(name);
+            if (factory != null) {
+                return factory.getFormat(name, args, getLocale());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Read the argument index from the current format element.
+     *
+     * @param pattern pattern to parse
+     * @param pos current parse position
+     * @return argument index
+     */
+    private int readArgumentIndex(final String pattern, final ParsePosition pos) {
+        final int start = pos.getIndex();
+        seekNonWs(pattern, pos);
+        final StringBuilder result = new StringBuilder();
+        boolean error = false;
+        for (; !error && pos.getIndex() < pattern.length(); next(pos)) {
+            char c = pattern.charAt(pos.getIndex());
+            if (Character.isWhitespace(c)) {
+                seekNonWs(pattern, pos);
+                c = pattern.charAt(pos.getIndex());
+                if (c != START_FMT && c != END_FE) {
+                    error = true;
+                    continue;
+                }
+            }
+            if ((c == START_FMT || c == END_FE) && result.length() > 0) {
+                try {
+                    return Integer.parseInt(result.toString());
+                } catch (final NumberFormatException e) { // NOPMD
+                    // we've already ensured only digits, so unless something
+                    // outlandishly large was specified we should be okay.
+                }
+            }
+            error = !Character.isDigit(c);
+            result.append(c);
+        }
+        if (error) {
+            throw new IllegalArgumentException(
+                    "Invalid format argument index at position " + start + ": "
+                            + pattern.substring(start, pos.getIndex()));
+        }
+        throw new IllegalArgumentException(
+                "Unterminated format element at position " + start);
+    }
+
+    /**
+     * Parse the format component of a format element.
+     *
+     * @param pattern string to parse
+     * @param pos current parse position
+     * @return Format description String
+     */
+    private String parseFormatDescription(final String pattern, final ParsePosition pos) {
+        final int start = pos.getIndex();
+        seekNonWs(pattern, pos);
+        final int text = pos.getIndex();
+        int depth = 1;
+        for (; pos.getIndex() < pattern.length(); next(pos)) {
+            switch (pattern.charAt(pos.getIndex())) {
+            case START_FE:
+                depth++;
+                break;
+            case END_FE:
+                depth--;
+                if (depth == 0) {
+                    return pattern.substring(text, pos.getIndex());
+                }
+                break;
+            case QUOTE:
+                getQuotedString(pattern, pos);
+                break;
+            default:
+                break;
+            }
+        }
+        throw new IllegalArgumentException(
+                "Unterminated format element at position " + start);
+    }
+
+    /**
+     * Insert formats back into the pattern for toPattern() support.
+     *
+     * @param pattern source
+     * @param customPatterns The custom patterns to re-insert, if any
+     * @return full pattern
+     */
+    private String insertFormats(final String pattern, final ArrayList<String> customPatterns) {
+        if (!containsElements(customPatterns)) {
+            return pattern;
+        }
+        final StringBuilder sb = new StringBuilder(pattern.length() * 2);
+        final ParsePosition pos = new ParsePosition(0);
+        int fe = -1;
+        int depth = 0;
+        while (pos.getIndex() < pattern.length()) {
+            final char c = pattern.charAt(pos.getIndex());
+            switch (c) {
+            case QUOTE:
+                appendQuotedString(pattern, pos, sb);
+                break;
+            case START_FE:
+                depth++;
+                sb.append(START_FE).append(readArgumentIndex(pattern, next(pos)));
+                // do not look for custom patterns when they are embedded, e.g. in a choice
+                if (depth == 1) {
+                    fe++;
+                    final String customPattern = customPatterns.get(fe);
+                    if (customPattern != null) {
+                        sb.append(START_FMT).append(customPattern);
+                    }
+                }
+                break;
+            case END_FE:
+                depth--;
+                //$FALL-THROUGH$
+            default:
+                sb.append(c);
+                next(pos);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Consume whitespace from the current parse position.
+     *
+     * @param pattern String to read
+     * @param pos current position
+     */
+    private void seekNonWs(final String pattern, final ParsePosition pos) {
+        int len = 0;
+        final char[] buffer = pattern.toCharArray();
+        do {
+            len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex());
+            pos.setIndex(pos.getIndex() + len);
+        } while (len > 0 && pos.getIndex() < pattern.length());
+    }
+
+    /**
+     * Convenience method to advance parse position by 1.
+     *
+     * @param pos ParsePosition
+     * @return <code>pos</code>
+     */
+    private ParsePosition next(final ParsePosition pos) {
+        pos.setIndex(pos.getIndex() + 1);
+        return pos;
+    }
+
+    /**
+     * Consume a quoted string, adding it to <code>appendTo</code> if
+     * specified.
+     *
+     * @param pattern pattern to parse
+     * @param pos current parse position
+     * @param appendTo optional StringBuilder to append
+     * @return <code>appendTo</code>
+     */
+    private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos,
+            final StringBuilder appendTo) {
+        assert pattern.toCharArray()[pos.getIndex()] == QUOTE
+                : "Quoted string must start with quote character";
+
+        // handle quote character at the beginning of the string
+        if (appendTo != null) {
+            appendTo.append(QUOTE);
+        }
+        next(pos);
+
+        final int start = pos.getIndex();
+        final char[] c = pattern.toCharArray();
+        final int lastHold = start;
+        for (int i = pos.getIndex(); i < pattern.length(); i++) {
+            switch (c[pos.getIndex()]) {
+            case QUOTE:
+                next(pos);
+                return appendTo == null ? null : appendTo.append(c, lastHold,
+                        pos.getIndex() - lastHold);
+            default:
+                next(pos);
+            }
+        }
+        throw new IllegalArgumentException(
+                "Unterminated quoted string at position " + start);
+    }
+
+    /**
+     * Consume quoted string only.
+     *
+     * @param pattern pattern to parse
+     * @param pos current parse position
+     */
+    private void getQuotedString(final String pattern, final ParsePosition pos) {
+        appendQuotedString(pattern, pos, null);
+    }
+
+    /**
+     * Learn whether the specified Collection contains non-null elements.
+     * @param coll to check
+     * @return <code>true</code> if some Object was found, <code>false</code> otherwise.
+     */
+    private boolean containsElements(final Collection<?> coll) {
+        if (coll == null || coll.isEmpty()) {
+            return false;
+        }
+        for (final Object name : coll) {
+            if (name != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/FormatFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/FormatFactory.java b/src/main/java/org/apache/commons/text/FormatFactory.java
new file mode 100644
index 0000000..ceee01b
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/FormatFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.text.Format;
+import java.util.Locale;
+
+/**
+ * Format factory.
+ *
+ * @since 1.0
+ */
+public interface FormatFactory {
+
+    /**
+     * Create or retrieve a format instance.
+     *
+     * @param name The format type name
+     * @param arguments Arguments used to create the format instance. This allows the
+     *                  <code>FormatFactory</code> to implement the "format style"
+     *                  concept from <code>java.text.MessageFormat</code>.
+     * @param locale The locale, may be null
+     * @return The format instance
+     */
+    Format getFormat(String name, String arguments, Locale locale);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/FormattableUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/FormattableUtils.java b/src/main/java/org/apache/commons/text/FormattableUtils.java
new file mode 100644
index 0000000..043cbf1
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/FormattableUtils.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.Formattable;
+import java.util.Formatter;
+
+import static java.util.FormattableFlags.LEFT_JUSTIFY;
+
+/**
+ * <p>Provides utilities for working with the {@code Formattable} interface.</p>
+ *
+ * <p>The {@link Formattable} interface provides basic control over formatting
+ * when using a {@code Formatter}. It is primarily concerned with numeric precision
+ * and padding, and is not designed to allow generalised alternate formats.</p>
+ *
+ * @since 1.0
+ *
+ */
+public class FormattableUtils {
+
+    /**
+     * A format that simply outputs the value as a string.
+     */
+    private static final String SIMPLEST_FORMAT = "%s";
+
+    /**
+     * <p>{@code FormattableUtils} instances should NOT be constructed in
+     * standard programming. Instead, the methods of the class should be invoked
+     * statically.</p>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean
+     * instance to operate.</p>
+     */
+    public FormattableUtils() {
+        super();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Get the default formatted representation of the specified
+     * {@code Formattable}.
+     *
+     * @param formattable  the instance to convert to a string, not null
+     * @return the resulting string, not null
+     */
+    public static String toString(final Formattable formattable) {
+        return String.format(SIMPLEST_FORMAT, formattable);
+    }
+
+    /**
+     * Handles the common {@code Formattable} operations of truncate-pad-append,
+     * with no ellipsis on precision overflow, and padding width underflow with
+     * spaces.
+     *
+     * @param seq  the string to handle, not null
+     * @param formatter  the destination formatter, not null
+     * @param flags  the flags for formatting, see {@code Formattable}
+     * @param width  the width of the output, see {@code Formattable}
+     * @param precision  the precision of the output, see {@code Formattable}
+     * @return the {@code formatter} instance, not null
+     */
+    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
+            final int precision) {
+        return append(seq, formatter, flags, width, precision, ' ', null);
+    }
+
+    /**
+     * Handles the common {@link Formattable} operations of truncate-pad-append,
+     * with no ellipsis on precision overflow.
+     *
+     * @param seq  the string to handle, not null
+     * @param formatter  the destination formatter, not null
+     * @param flags  the flags for formatting, see {@code Formattable}
+     * @param width  the width of the output, see {@code Formattable}
+     * @param precision  the precision of the output, see {@code Formattable}
+     * @param padChar  the pad character to use
+     * @return the {@code formatter} instance, not null
+     */
+    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
+            final int precision, final char padChar) {
+        return append(seq, formatter, flags, width, precision, padChar, null);
+    }
+
+    /**
+     * Handles the common {@link Formattable} operations of truncate-pad-append,
+     * padding width underflow with spaces.
+     *
+     * @param seq  the string to handle, not null
+     * @param formatter  the destination formatter, not null
+     * @param flags  the flags for formatting, see {@code Formattable}
+     * @param width  the width of the output, see {@code Formattable}
+     * @param precision  the precision of the output, see {@code Formattable}
+     * @param ellipsis  the ellipsis to use when precision dictates truncation, null or
+     *  empty causes a hard truncation
+     * @return the {@code formatter} instance, not null
+     */
+    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
+            final int precision, final CharSequence ellipsis) {
+        return append(seq, formatter, flags, width, precision, ' ', ellipsis);
+    }
+
+    /**
+     * Handles the common {@link Formattable} operations of truncate-pad-append.
+     *
+     * @param seq  the string to handle, not null
+     * @param formatter  the destination formatter, not null
+     * @param flags  the flags for formatting, see {@code Formattable}
+     * @param width  the width of the output, see {@code Formattable}
+     * @param precision  the precision of the output, see {@code Formattable}
+     * @param padChar  the pad character to use
+     * @param ellipsis  the ellipsis to use when precision dictates truncation, null or
+     *  empty causes a hard truncation
+     * @return the {@code formatter} instance, not null
+     */
+    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
+            final int precision, final char padChar, final CharSequence ellipsis) {
+        if (!(ellipsis == null || precision < 0 || ellipsis.length() <= precision)) {
+            throw new IllegalArgumentException(
+                    String.format("Specified ellipsis '%1$s' exceeds precision of %2$s",
+                            ellipsis,
+                            Integer.valueOf(precision)));
+        }
+        final StringBuilder buf = new StringBuilder(seq);
+        if (precision >= 0 && precision < seq.length()) {
+            final CharSequence _ellipsis;
+            if (ellipsis == null) {
+                _ellipsis = "";
+            } else {
+                _ellipsis = ellipsis;
+            }
+            buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString());
+        }
+        final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY;
+        for (int i = buf.length(); i < width; i++) {
+            buf.insert(leftJustify ? i : 0, padChar);
+        }
+        formatter.format(buf.toString());
+        return formatter;
+    }
+
+}


[15/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/CompositeFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/CompositeFormatTest.java b/src/test/java/org/apache/commons/text/CompositeFormatTest.java
new file mode 100644
index 0000000..5965fa3
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/CompositeFormatTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Locale;
+
+/**
+ * Unit tests for {@link CompositeFormat}.
+ */
+public class CompositeFormatTest {
+
+    /**
+     * Ensures that the parse/format separation is correctly maintained. 
+     */
+    @Test
+    public void testCompositeFormat() {
+
+        final Format parser = new Format() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
+                throw new UnsupportedOperationException("Not implemented");
+            }
+
+            @Override
+            public Object parseObject(final String source, final ParsePosition pos) {
+                return null;    // do nothing
+            }
+        };
+
+        final Format formatter = new Format() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
+                return null;    // do nothing
+            }
+
+            @Override
+            public Object parseObject(final String source, final ParsePosition pos) {
+                throw new UnsupportedOperationException("Not implemented");
+            }
+        };
+
+        final CompositeFormat composite = new CompositeFormat(parser, formatter);
+
+        composite.parseObject("", null);
+        composite.format(new Object(), new StringBuffer(), null);
+        assertEquals( "Parser get method incorrectly implemented", parser, composite.getParser() );
+        assertEquals( "Formatter get method incorrectly implemented", formatter, composite.getFormatter() );
+    }
+
+    @Test
+    public void testUsage() throws Exception {
+        final Format f1 = new SimpleDateFormat("MMddyyyy", Locale.ENGLISH);
+        final Format f2 = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
+        final CompositeFormat c = new CompositeFormat(f1, f2);
+        final String testString = "January 3, 2005";
+        assertEquals(testString, c.format(c.parseObject("01032005")));
+        assertEquals(testString, c.reformat("01032005"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java b/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
new file mode 100644
index 0000000..bc8cb06
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/ExtendedMessageFormatTest.java
@@ -0,0 +1,497 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import org.junit.Test;
+import org.junit.Before;
+import static org.junit.Assert.*;
+
+import java.text.DateFormat;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.MessageFormat;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Test case for {@link ExtendedMessageFormat}.
+ */
+public class ExtendedMessageFormatTest {
+
+    private final Map<String, FormatFactory> registry = new HashMap<>();
+
+    @Before
+    public void setUp() throws Exception {
+        registry.put("lower", new LowerCaseFormatFactory());
+        registry.put("upper", new UpperCaseFormatFactory());
+    }
+
+    /**
+     * Test extended formats.
+     */
+    @Test
+    public void testExtendedFormats() {
+        final String pattern = "Lower: {0,lower} Upper: {1,upper}";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals("TOPATTERN", pattern, emf.toPattern());
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
+        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
+    }
+
+    /**
+     * Test Bug LANG-477 - out of memory error with escaped quote
+     */
+    @Test
+    public void testEscapedQuote_LANG_477() {
+        final String pattern = "it''s a {0,lower} 'test'!";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
+    }
+
+    /**
+     * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern
+     */
+    @Test
+    public void testEmbeddedPatternInChoice() {
+        final String pattern = "Hi {0,lower}, got {1,choice,0#none|1#one|1<{1,number}}, {2,upper}!";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals(emf.format(new Object[] {"there", 3, "great"}), "Hi there, got 3, GREAT!");
+    }
+
+    /**
+     * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces
+     */
+    @Test
+    public void testEscapedBraces_LANG_948() {
+        // message without placeholder because braces are escaped by quotes 
+        final String pattern = "Message without placeholders '{}'";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+        assertEquals("Message without placeholders {}", emf.format(new Object[] {"DUMMY"}));
+
+        // message with placeholder because quotes are escaped by quotes 
+        final String pattern2 = "Message with placeholder ''{0}''";
+        final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry);
+        assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] {"DUMMY"}));
+    }
+
+    /**
+     * Test extended and built in formats.
+     */
+    @Test
+    public void testExtendedAndBuiltInFormats() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
+        final Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
+        final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
+        final String extendedPattern = "Name: {0,upper} ";
+        final String pattern = extendedPattern + builtinsPattern;
+
+        final HashSet<Locale> testLocales = new HashSet<>();
+        testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
+        testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
+        testLocales.add(null);
+
+        for (final Locale locale : testLocales) {
+            final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
+            final String expectedPattern = extendedPattern + builtins.toPattern();
+            DateFormat df = null;
+            NumberFormat nf = null;
+            ExtendedMessageFormat emf = null;
+            if (locale == null) {
+                df = DateFormat.getDateInstance(DateFormat.SHORT);
+                nf = NumberFormat.getCurrencyInstance();
+                emf = new ExtendedMessageFormat(pattern, registry);
+            } else {
+                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+                nf = NumberFormat.getCurrencyInstance(locale);
+                emf = new ExtendedMessageFormat(pattern, locale, registry);
+            }
+            final StringBuilder expected = new StringBuilder();
+            expected.append("Name: ");
+            expected.append(args[0].toString().toUpperCase());
+            expected.append(" DOB: ");
+            expected.append(df.format(args[1]));
+            expected.append(" Salary: ");
+            expected.append(nf.format(args[2]));
+            assertEquals("pattern comparison for locale " + locale, expectedPattern, emf.toPattern());
+            assertEquals(String.valueOf(locale), expected.toString(), emf.format(args));
+        }
+    }
+
+//    /**
+//     * Test extended formats with choice format.
+//     *
+//     * NOTE: FAILING - currently sub-formats not supported
+//     */
+//    public void testExtendedWithChoiceFormat() {
+//        String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}";
+//        ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
+//        assertPatterns(null, pattern, emf.toPattern());
+//        try {
+//            assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), "ONE"}));
+//            assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), "two"}));
+//        } catch (IllegalArgumentException e) {
+//            // currently sub-formats not supported
+//        }
+//    }
+
+//    /**
+//     * Test mixed extended and built-in formats with choice format.
+//     *
+//     * NOTE: FAILING - currently sub-formats not supported
+//     */
+//    public void testExtendedAndBuiltInWithChoiceFormat() {
+//        String pattern = "Choice: {0,choice,1.0#{0} {1,lower} {2,number}|2.0#{0} {1,upper} {2,number,currency}}";
+//        Object[] lowArgs  = new Object[] {Integer.valueOf(1), "Low",  Double.valueOf("1234.56")};
+//        Object[] highArgs = new Object[] {Integer.valueOf(2), "High", Double.valueOf("9876.54")};
+//        Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
+//        Locale[] testLocales = new Locale[availableLocales.length + 1];
+//        testLocales[0] = null;
+//        System.arraycopy(availableLocales, 0, testLocales, 1, availableLocales.length);
+//        for (int i = 0; i < testLocales.length; i++) {
+//            NumberFormat nf = null;
+//            NumberFormat cf = null;
+//            ExtendedMessageFormat emf = null;
+//            if (testLocales[i] == null) {
+//                nf = NumberFormat.getNumberInstance();
+//                cf = NumberFormat.getCurrencyInstance();
+//                emf = new ExtendedMessageFormat(pattern, registry);
+//            } else {
+//                nf = NumberFormat.getNumberInstance(testLocales[i]);
+//                cf = NumberFormat.getCurrencyInstance(testLocales[i]);
+//                emf = new ExtendedMessageFormat(pattern, testLocales[i], registry);
+//            }
+//            assertPatterns(null, pattern, emf.toPattern());
+//            try {
+//                String lowExpected = lowArgs[0] + " low "    + nf.format(lowArgs[2]);
+//                String highExpected = highArgs[0] + " HIGH "  + cf.format(highArgs[2]);
+//                assertEquals(lowExpected,  emf.format(lowArgs));
+//                assertEquals(highExpected, emf.format(highArgs));
+//            } catch (IllegalArgumentException e) {
+//                // currently sub-formats not supported
+//            }
+//        }
+//    }
+
+    /**
+     * Test the built in choice format.
+     */
+    @Test
+    public void testBuiltInChoiceFormat() {
+        final Object[] values = new Number[] {Integer.valueOf(1), Double.valueOf("2.2"), Double.valueOf("1234.5")};
+        String choicePattern = null;
+        final Locale[] availableLocales = NumberFormat.getAvailableLocales();
+
+        choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
+        for (final Object value : values) {
+            checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
+        }
+
+        choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}";
+        for (final Object value : values) {
+            checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
+        }
+    }
+
+    /**
+     * Test the built in date/time formats
+     */
+    @Test
+    public void testBuiltInDateTimeFormat() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
+        final Object[] args = new Object[] {cal.getTime()};
+        final Locale[] availableLocales = DateFormat.getAvailableLocales();
+
+        checkBuiltInFormat("1: {0,date,short}",    args, availableLocales);
+        checkBuiltInFormat("2: {0,date,medium}",   args, availableLocales);
+        checkBuiltInFormat("3: {0,date,long}",     args, availableLocales);
+        checkBuiltInFormat("4: {0,date,full}",     args, availableLocales);
+        checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
+        checkBuiltInFormat("6: {0,time,short}",    args, availableLocales);
+        checkBuiltInFormat("7: {0,time,medium}",   args, availableLocales);
+        checkBuiltInFormat("8: {0,time,long}",     args, availableLocales);
+        checkBuiltInFormat("9: {0,time,full}",     args, availableLocales);
+        checkBuiltInFormat("10: {0,time,HH:mm}",   args, availableLocales);
+        checkBuiltInFormat("11: {0,date}",         args, availableLocales);
+        checkBuiltInFormat("12: {0,time}",         args, availableLocales);
+    }
+
+    @Test
+    public void testOverriddenBuiltinFormat() {
+        final Calendar cal = Calendar.getInstance();
+        cal.set(2007, Calendar.JANUARY, 23);
+        final Object[] args = new Object[] {cal.getTime()};
+        final Locale[] availableLocales = DateFormat.getAvailableLocales();
+        final Map<String, ? extends FormatFactory> dateRegistry = Collections.singletonMap("date", new OverrideShortDateFormatFactory());
+
+        //check the non-overridden builtins:
+        checkBuiltInFormat("1: {0,date}", dateRegistry,          args, availableLocales);
+        checkBuiltInFormat("2: {0,date,medium}", dateRegistry,   args, availableLocales);
+        checkBuiltInFormat("3: {0,date,long}", dateRegistry,     args, availableLocales);
+        checkBuiltInFormat("4: {0,date,full}", dateRegistry,     args, availableLocales);
+        checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales);
+
+        //check the overridden format:
+        for (int i = -1; i < availableLocales.length; i++) {
+            final Locale locale = i < 0 ? null : availableLocales[i];
+            final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
+            final String pattern = "{0,date,short}";
+            final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry);
+            assertEquals("overridden date,short format", dateDefault.format(args), dateShort.format(args));
+            assertEquals("overridden date,short pattern", pattern, dateShort.toPattern());
+        }
+    }
+
+    /**
+     * Test the built in number formats.
+     */
+    @Test
+    public void testBuiltInNumberFormat() {
+        final Object[] args = new Object[] {Double.valueOf("6543.21")};
+        final Locale[] availableLocales = NumberFormat.getAvailableLocales();
+        checkBuiltInFormat("1: {0,number}",            args, availableLocales);
+        checkBuiltInFormat("2: {0,number,integer}",    args, availableLocales);
+        checkBuiltInFormat("3: {0,number,currency}",   args, availableLocales);
+        checkBuiltInFormat("4: {0,number,percent}",    args, availableLocales);
+        checkBuiltInFormat("5: {0,number,00000.000}",  args, availableLocales);
+    }
+
+    /**
+     * Test equals() and hashcode.
+     */
+    @Test
+    public void testEqualsHashcode() {
+        final Map<String, ? extends FormatFactory> fmtRegistry = Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
+        final Map<String, ? extends FormatFactory> otherRegitry = Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
+
+        final String pattern = "Pattern: {0,testfmt}";
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
+
+        ExtendedMessageFormat other = null;
+
+        // Same object
+        assertTrue("same, equals()",   emf.equals(emf));
+        assertTrue("same, hashcode()", emf.hashCode() == emf.hashCode());
+
+        assertFalse("null, equals", emf.equals(null));
+
+        // Equal Object
+        other = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
+        assertTrue("equal, equals()",   emf.equals(other));
+        assertTrue("equal, hashcode()", emf.hashCode() == other.hashCode());
+
+        // Different Class
+        other = new OtherExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
+        assertFalse("class, equals()",  emf.equals(other));
+        assertTrue("class, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
+
+        // Different pattern
+        other = new ExtendedMessageFormat("X" + pattern, Locale.US, fmtRegistry);
+        assertFalse("pattern, equals()",   emf.equals(other));
+        assertFalse("pattern, hashcode()", emf.hashCode() == other.hashCode());
+
+        // Different registry
+        other = new ExtendedMessageFormat(pattern, Locale.US, otherRegitry);
+        assertFalse("registry, equals()",   emf.equals(other));
+        assertFalse("registry, hashcode()", emf.hashCode() == other.hashCode());
+
+        // Different Locale
+        other = new ExtendedMessageFormat(pattern, Locale.FRANCE, fmtRegistry);
+        assertFalse("locale, equals()",  emf.equals(other));
+        assertTrue("locale, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
+    }
+
+    /**
+     * Test a built in format for the specified Locales, plus <code>null</code> Locale.
+     * @param pattern MessageFormat pattern
+     * @param args MessageFormat arguments
+     * @param locales to test
+     */
+    private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
+        checkBuiltInFormat(pattern, null, args, locales);
+    }
+
+    /**
+     * Test a built in format for the specified Locales, plus <code>null</code> Locale.
+     * @param pattern MessageFormat pattern
+     * @param fmtRegistry FormatFactory registry to use
+     * @param args MessageFormat arguments
+     * @param locales to test
+     */
+    private void checkBuiltInFormat(final String pattern, final Map<String, ?> fmtRegistry, final Object[] args, final Locale[] locales) {
+        checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null);
+        for (final Locale locale : locales) {
+            checkBuiltInFormat(pattern, fmtRegistry, args, locale);
+        }
+    }
+
+    /**
+     * Create an ExtendedMessageFormat for the specified pattern and locale and check the
+     * formated output matches the expected result for the parameters.
+     * @param pattern string
+     * @param registryUnused map (currently unused)
+     * @param args Object[]
+     * @param locale Locale
+     */
+    private void checkBuiltInFormat(final String pattern, final Map<String, ?> registryUnused, final Object[] args, final Locale locale) {
+        final StringBuilder buffer = new StringBuilder();
+        buffer.append("Pattern=[");
+        buffer.append(pattern);
+        buffer.append("], locale=[");
+        buffer.append(locale);
+        buffer.append("]");
+        final MessageFormat mf = createMessageFormat(pattern, locale);
+        // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
+        ExtendedMessageFormat emf = null;
+        if (locale == null) {
+            emf = new ExtendedMessageFormat(pattern);
+        } else {
+            emf = new ExtendedMessageFormat(pattern, locale);
+        }
+        assertEquals("format "    + buffer.toString(), mf.format(args), emf.format(args));
+        assertEquals("toPattern " + buffer.toString(), mf.toPattern(), emf.toPattern());
+    }
+
+    /**
+     * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
+     * @param pattern string
+     * @param locale Locale
+     * @return MessageFormat
+     */
+    private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
+        final MessageFormat result = new MessageFormat(pattern);
+        if (locale != null) {
+            result.setLocale(locale);
+            result.applyPattern(pattern);
+        }
+        return result;
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSetFormatIsUnsupported() {
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+        emf.setFormat(0, new LowerCaseFormat());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSetFormatByArgumentIndexIsUnsupported() {
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+        emf.setFormatByArgumentIndex(0, new LowerCaseFormat());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSetFormatsIsUnsupported() {
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+        emf.setFormats(new Format[]{new LowerCaseFormat(), new UpperCaseFormat()});
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testSetFormatsByArgumentIndex() {
+        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
+        emf.setFormatsByArgumentIndex(new Format[]{new LowerCaseFormat(), new UpperCaseFormat()});
+    }
+
+    // ------------------------ Test Formats ------------------------
+
+    /**
+     * {@link Format} implementation which converts to lower case.
+     */
+    private static class LowerCaseFormat extends Format {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
+            return toAppendTo.append(((String)obj).toLowerCase());
+        }
+        @Override
+        public Object parseObject(final String source, final ParsePosition pos) {throw new UnsupportedOperationException();}
+    }
+
+    /**
+     * {@link Format} implementation which converts to upper case.
+     */
+    private static class UpperCaseFormat extends Format {
+        private static final long serialVersionUID = 1L;
+
+        @Override
+        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
+            return toAppendTo.append(((String)obj).toUpperCase());
+        }
+        @Override
+        public Object parseObject(final String source, final ParsePosition pos) {throw new UnsupportedOperationException();}
+    }
+
+
+    // ------------------------ Test Format Factories ---------------
+    /**
+     * {@link FormatFactory} implementation for lower case format.
+     */
+    private static class LowerCaseFormatFactory implements FormatFactory {
+        private static final Format LOWER_INSTANCE = new LowerCaseFormat();
+        @Override
+        public Format getFormat(final String name, final String arguments, final Locale locale) {
+            return LOWER_INSTANCE;
+        }
+    }
+    /**
+     * {@link FormatFactory} implementation for upper case format.
+     */
+    private static class UpperCaseFormatFactory implements FormatFactory {
+        private static final Format UPPER_INSTANCE = new UpperCaseFormat();
+        @Override
+        public Format getFormat(final String name, final String arguments, final Locale locale) {
+            return UPPER_INSTANCE;
+        }
+    }
+    /**
+     * {@link FormatFactory} implementation to override date format "short" to "default".
+     */
+    private static class OverrideShortDateFormatFactory implements FormatFactory {
+        @Override
+        public Format getFormat(final String name, final String arguments, final Locale locale) {
+            return !"short".equals(arguments) ? null
+                    : locale == null ? DateFormat
+                            .getDateInstance(DateFormat.DEFAULT) : DateFormat
+                            .getDateInstance(DateFormat.DEFAULT, locale);
+        }
+    }
+
+    /**
+     * Alternative ExtendedMessageFormat impl.
+     */
+    private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
+        private static final long serialVersionUID = 1L;
+
+        public OtherExtendedMessageFormat(final String pattern, final Locale locale,
+                final Map<String, ? extends FormatFactory> registry) {
+            super(pattern, locale, registry);
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/FormattableUtilsTest.java b/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
new file mode 100644
index 0000000..c7feb38
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/FormattableUtilsTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import static java.util.FormattableFlags.LEFT_JUSTIFY;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Formattable;
+import java.util.Formatter;
+
+import org.junit.Test;
+
+/**
+ * Unit tests {@link FormattableUtils}.
+ */
+public class FormattableUtilsTest {
+
+    @Test
+    public void testPublicConstructorExists() {
+        new FormattableUtils();
+    }
+
+    @Test
+    public void testSimplestFormat() {
+        final Formattable formattable = new SimplestFormattable("foo");
+
+        assertEquals("foo",  FormattableUtils.toString(formattable));
+    }
+
+    @Test
+    public void testDefaultAppend() {
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1).toString());
+        assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2).toString());
+        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1).toString());
+        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1).toString());
+        assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2).toString());
+        assertEquals("   fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2).toString());
+        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1).toString());
+        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1).toString());
+        assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2).toString());
+        assertEquals("fo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2).toString());
+    }
+
+    @Test
+    public void testAlternatePadCharacter() {
+        final char pad='_';
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, pad).toString());
+        assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, pad).toString());
+        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, pad).toString());
+        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, pad).toString());
+        assertEquals("_fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, pad).toString());
+        assertEquals("___fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, pad).toString());
+        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, pad).toString());
+        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, pad).toString());
+        assertEquals("fo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, pad).toString());
+        assertEquals("fo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, pad).toString());
+    }
+
+    @Test
+    public void testEllipsis() {
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "*").toString());
+        assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "*").toString());
+        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "*").toString());
+        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "*").toString());
+        assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "*").toString());
+        assertEquals("   f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "*").toString());
+        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "*").toString());
+        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "*").toString());
+        assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "*").toString());
+        assertEquals("f*   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "*").toString());
+
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "+*").toString());
+        assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "+*").toString());
+        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "+*").toString());
+        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "+*").toString());
+        assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "+*").toString());
+        assertEquals("   +*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "+*").toString());
+        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "+*").toString());
+        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "+*").toString());
+        assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "+*").toString());
+        assertEquals("+*   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "+*").toString());
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testIllegalEllipsis() {
+        FormattableUtils.append("foo", new Formatter(), 0, -1, 1, "xx");
+    }
+
+    @Test
+    public void testAlternatePadCharAndEllipsis() {
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "*").toString());
+        assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "*").toString());
+        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "*").toString());
+        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "*").toString());
+        assertEquals("_f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "*").toString());
+        assertEquals("___f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "*").toString());
+        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString());
+        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString());
+        assertEquals("f*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString());
+        assertEquals("f*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString());
+
+        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "+*").toString());
+        assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "+*").toString());
+        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "+*").toString());
+        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "+*").toString());
+        assertEquals("_+*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "+*").toString());
+        assertEquals("___+*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "+*").toString());
+        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString());
+        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString());
+        assertEquals("+*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString());
+        assertEquals("+*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString());
+    }
+
+    static class SimplestFormattable implements Formattable {
+        private final String text;
+
+        SimplestFormattable(final String text) {
+            this.text = text;
+        }
+
+        @Override
+        public void formatTo(Formatter formatter, int flags, int width, int precision) {
+            formatter.format(text);
+        }
+    };
+
+
+}


[11/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/AlphabetConverterTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/AlphabetConverterTest.java b/src/test/java/org/apache/commons/text/beta/AlphabetConverterTest.java
deleted file mode 100644
index 88e5926..0000000
--- a/src/test/java/org/apache/commons/text/beta/AlphabetConverterTest.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-
-/**
- * Unit tests for {@link AlphabetConverter}.
- */
-public class AlphabetConverterTest {
-
-    private static Character[] lower_case_english = {' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
-    private static Character[] english_and_numbers = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',' ' };
-    private static Character[] lower_case_english_and_numbers = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ' };
-    private static Character[] numbers = {'0','1','2','3','4','5','6','7','8','9'};
-    private static Character[] binary = {'0','1'};
-    private static Character[] hebrew = {'_', ' ', '\u05e7','\u05e8','\u05d0','\u05d8','\u05d5','\u05df','\u05dd','\u05e4','\u05e9','\u05d3','\u05d2','\u05db','\u05e2','\u05d9','\u05d7','\u05dc','\u05da','\u05e3','\u05d6','\u05e1','\u05d1','\u05d4','\u05e0','\u05de','\u05e6','\u05ea','\u05e5'};
-    private static Character[] empty = {};
-
-    private static Integer[] unicode = {32,35395,35397,36302,36291,35203,35201,35215,35219,35268,97,98,99,100,101,102,103,104,105,106,107,108,109,110,1001,1002,1003,1004,1005};
-    private static Integer[] lower_case_english_codepoints = {32,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};
-    private static Integer[] doNotEncodePoints = {32,97,98,99}; // space, a, b, c
-    
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-    
-    @Test
-    public void encodeFailureTest() throws UnsupportedEncodingException {
-        thrown.expect(UnsupportedEncodingException.class);
-        thrown.expectMessage("Couldn't find encoding for '3'");
-        test(binary, numbers, empty, "3");
-    }
-
-    @Test
-    public void binaryTest() throws UnsupportedEncodingException {
-        test(binary, numbers, empty, "0", "1", "10", "11");
-        test(numbers, binary, empty, "12345", "0");
-        test(lower_case_english, binary, empty, "abc", "a");
-    }
-
-    @Test
-    public void hebrewTest() throws UnsupportedEncodingException {
-        test(hebrew, binary, empty, "\u05d0", "\u05e2", "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
-        test(hebrew, numbers, empty, "\u05d0", "\u05e2", "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
-        test(numbers, hebrew, empty, "123456789", "1", "5");
-        test(lower_case_english, hebrew, empty, "this is a test");
-    }
-
-    @Test
-    public void doNotEncodeTest() throws UnsupportedEncodingException {
-        test(english_and_numbers, lower_case_english_and_numbers, lower_case_english, "1", "456", "abc", "ABC", "this will not be converted but THIS WILL");
-        test(english_and_numbers, lower_case_english_and_numbers, numbers, "1", "456", "abc", "ABC", "this will be converted but 12345 and this will be");
-    }
-
-    private AlphabetConverter createJavadocExample() {
-        final Character[] original = {'a','b','c','d'};
-        final Character[] encoding = {'0','1','d'};
-        final Character[] doNotEncode = {'d'};
-        
-        return AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode);
-    }
-    
-    /*
-     * Test example in javadocs for consistency
-     */
-    @Test
-    public void javadocExampleTest() throws UnsupportedEncodingException {
-        final AlphabetConverter ac = createJavadocExample();
-        
-        Assert.assertEquals("00", ac.encode("a"));
-        Assert.assertEquals("01", ac.encode("b"));
-        Assert.assertEquals("0d", ac.encode("c"));
-        Assert.assertEquals("d", ac.encode("d"));
-        Assert.assertEquals("00010dd", ac.encode("abcd"));
-    }
-
-    @Test
-    public void unexpectedEndwhileDecodingTest() throws UnsupportedEncodingException {
-        final String toDecode = "00d01d0";
-        
-        thrown.expect(UnsupportedEncodingException.class);
-        thrown.expectMessage("Unexpected end of string while decoding " + toDecode);
-
-        final AlphabetConverter ac = createJavadocExample();
-        ac.decode(toDecode);
-    }
-
-    @Test
-    public void unexpectedStringWhileDecodingTest() throws UnsupportedEncodingException {
-        final String toDecode = "00XX";
-        
-        thrown.expect(UnsupportedEncodingException.class);
-        thrown.expectMessage("Unexpected string without decoding (XX) in " + toDecode);
-
-        final AlphabetConverter ac = createJavadocExample();
-        ac.decode(toDecode);
-    }
-
-    /*
-     * Test constructor from code points
-     */
-    @Test
-    public void unicodeTest() throws UnsupportedEncodingException {
-        final AlphabetConverter ac = AlphabetConverter.createConverter(unicode, lower_case_english_codepoints, doNotEncodePoints);
-        
-        Assert.assertEquals(2, ac.getEncodedCharLength());
-        
-        final String original = "\u8a43\u8a45 \u8dce ab \u8dc3 c \u8983";
-        final String encoded = ac.encode(original);
-        final String decoded = ac.decode(encoded);
-        
-        Assert.assertEquals("Encoded '" + original + "' into '" + encoded + "', but decoded into '" + decoded + "'", original, decoded);
-    }
-
-    @Test
-    public void noEncodingLettersTest() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 0");
-
-        AlphabetConverter.createConverterFromChars(english_and_numbers, numbers, numbers);
-    }
-
-    @Test
-    public void onlyOneEncodingLettersTest() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 1");
-
-        final Character[] numbersPlusUnderscore = Arrays.copyOf(numbers, numbers.length + 1);
-        numbersPlusUnderscore[numbersPlusUnderscore.length -1] = '_';
-
-        AlphabetConverter.createConverterFromChars(english_and_numbers, numbersPlusUnderscore, numbers);
-    }
-
-    @Test
-    public void missingDoNotEncodeLettersFromEncodingTest() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Can not use 'do not encode' list because encoding alphabet does not contain");
-
-        AlphabetConverter.createConverterFromChars(english_and_numbers, lower_case_english, numbers);
-    }
-
-    @Test
-    public void missingDoNotEncodeLettersFromOriginalTest() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Can not use 'do not encode' list because original alphabet does not contain");
-
-        AlphabetConverter.createConverterFromChars(lower_case_english, english_and_numbers, numbers);
-    }
-
-    private void test(final Character[] originalChars, final Character[] encodingChars, final Character[] doNotEncodeChars, final String... strings) throws UnsupportedEncodingException {
-        
-        final AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originalChars, encodingChars, doNotEncodeChars);
-        
-        final AlphabetConverter reconstructedAlphabetConverter = AlphabetConverter.createConverterFromMap(ac.getOriginalToEncoded());
-        
-        Assert.assertEquals(ac, reconstructedAlphabetConverter);
-        Assert.assertEquals(ac.hashCode(), reconstructedAlphabetConverter.hashCode());
-        Assert.assertEquals(ac.toString(), reconstructedAlphabetConverter.toString());
-        Assert.assertEquals(null, ac.encode(null)); // test null conversions
-        Assert.assertEquals("", ac.encode("")); // test empty conversion
-
-        // test all the trial strings
-        for (final String s : strings) {
-            final String encoded = ac.encode(s);
-
-            // test that only encoding chars are used
-            final List<Character> originalEncodingChars = Arrays.asList(encodingChars);
-            for (int i = 0; i < encoded.length(); i++) {
-                Assert.assertTrue(originalEncodingChars.contains(encoded.charAt(i)));
-            }
-
-            final String decoded = ac.decode(encoded);
-
-            // test that only the original alphabet is used after decoding
-            final List<Character> originalCharsList = Arrays.asList(originalChars);
-            for (int i = 0; i < decoded.length(); i++) {
-                Assert.assertTrue(originalCharsList.contains(decoded.charAt(i)));
-            }
-            
-            Assert.assertEquals("Encoded '" + s + "' into '" + encoded + "', but decoded into '" + decoded + "'", s, decoded);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/CharacterPredicatesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/CharacterPredicatesTest.java b/src/test/java/org/apache/commons/text/beta/CharacterPredicatesTest.java
deleted file mode 100644
index 7e5d24e..0000000
--- a/src/test/java/org/apache/commons/text/beta/CharacterPredicatesTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests for {@link CharacterPredicates}.
- */
-public class CharacterPredicatesTest {
-
-    @Test
-    public void testLetters() throws Exception {
-        assertTrue(CharacterPredicates.LETTERS.test('a'));
-        assertTrue(CharacterPredicates.LETTERS.test('Z'));
-
-        assertFalse(CharacterPredicates.LETTERS.test('1'));
-        assertFalse(CharacterPredicates.LETTERS.test('?'));
-        assertFalse(CharacterPredicates.LETTERS.test('@'));
-    }
-
-    @Test
-    public void testDigits() {
-        assertTrue(CharacterPredicates.DIGITS.test('0'));
-        assertTrue(CharacterPredicates.DIGITS.test('9'));
-
-        assertFalse(CharacterPredicates.DIGITS.test('-'));
-        assertFalse(CharacterPredicates.DIGITS.test('.'));
-        assertFalse(CharacterPredicates.DIGITS.test('L'));
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/CompositeFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/CompositeFormatTest.java b/src/test/java/org/apache/commons/text/beta/CompositeFormatTest.java
deleted file mode 100644
index a96a098..0000000
--- a/src/test/java/org/apache/commons/text/beta/CompositeFormatTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-import java.text.FieldPosition;
-import java.text.Format;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-
-/**
- * Unit tests for {@link CompositeFormat}.
- */
-public class CompositeFormatTest {
-
-    /**
-     * Ensures that the parse/format separation is correctly maintained. 
-     */
-    @Test
-    public void testCompositeFormat() {
-
-        final Format parser = new Format() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-                throw new UnsupportedOperationException("Not implemented");
-            }
-
-            @Override
-            public Object parseObject(final String source, final ParsePosition pos) {
-                return null;    // do nothing
-            }
-        };
-
-        final Format formatter = new Format() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-                return null;    // do nothing
-            }
-
-            @Override
-            public Object parseObject(final String source, final ParsePosition pos) {
-                throw new UnsupportedOperationException("Not implemented");
-            }
-        };
-
-        final CompositeFormat composite = new CompositeFormat(parser, formatter);
-
-        composite.parseObject("", null);
-        composite.format(new Object(), new StringBuffer(), null);
-        assertEquals( "Parser get method incorrectly implemented", parser, composite.getParser() );
-        assertEquals( "Formatter get method incorrectly implemented", formatter, composite.getFormatter() );
-    }
-
-    @Test
-    public void testUsage() throws Exception {
-        final Format f1 = new SimpleDateFormat("MMddyyyy", Locale.ENGLISH);
-        final Format f2 = new SimpleDateFormat("MMMM d, yyyy", Locale.ENGLISH);
-        final CompositeFormat c = new CompositeFormat(f1, f2);
-        final String testString = "January 3, 2005";
-        assertEquals(testString, c.format(c.parseObject("01032005")));
-        assertEquals(testString, c.reformat("01032005"));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/ExtendedMessageFormatTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/ExtendedMessageFormatTest.java b/src/test/java/org/apache/commons/text/beta/ExtendedMessageFormatTest.java
deleted file mode 100644
index 0c47b2a..0000000
--- a/src/test/java/org/apache/commons/text/beta/ExtendedMessageFormatTest.java
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import org.junit.Test;
-import org.junit.Before;
-import static org.junit.Assert.*;
-
-import java.text.DateFormat;
-import java.text.FieldPosition;
-import java.text.Format;
-import java.text.MessageFormat;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Test case for {@link ExtendedMessageFormat}.
- */
-public class ExtendedMessageFormatTest {
-
-    private final Map<String, FormatFactory> registry = new HashMap<>();
-
-    @Before
-    public void setUp() throws Exception {
-        registry.put("lower", new LowerCaseFormatFactory());
-        registry.put("upper", new UpperCaseFormatFactory());
-    }
-
-    /**
-     * Test extended formats.
-     */
-    @Test
-    public void testExtendedFormats() {
-        final String pattern = "Lower: {0,lower} Upper: {1,upper}";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals("TOPATTERN", pattern, emf.toPattern());
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "bar"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"Foo", "Bar"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "BAR"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"FOO", "bar"}));
-        assertEquals("Lower: foo Upper: BAR", emf.format(new Object[] {"foo", "BAR"}));
-    }
-
-    /**
-     * Test Bug LANG-477 - out of memory error with escaped quote
-     */
-    @Test
-    public void testEscapedQuote_LANG_477() {
-        final String pattern = "it''s a {0,lower} 'test'!";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals("it's a dummy test!", emf.format(new Object[] {"DUMMY"}));
-    }
-
-    /**
-     * Test Bug LANG-917 - IndexOutOfBoundsException and/or infinite loop when using a choice pattern
-     */
-    @Test
-    public void testEmbeddedPatternInChoice() {
-        final String pattern = "Hi {0,lower}, got {1,choice,0#none|1#one|1<{1,number}}, {2,upper}!";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals(emf.format(new Object[] {"there", 3, "great"}), "Hi there, got 3, GREAT!");
-    }
-
-    /**
-     * Test Bug LANG-948 - Exception while using ExtendedMessageFormat and escaping braces
-     */
-    @Test
-    public void testEscapedBraces_LANG_948() {
-        // message without placeholder because braces are escaped by quotes 
-        final String pattern = "Message without placeholders '{}'";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-        assertEquals("Message without placeholders {}", emf.format(new Object[] {"DUMMY"}));
-
-        // message with placeholder because quotes are escaped by quotes 
-        final String pattern2 = "Message with placeholder ''{0}''";
-        final ExtendedMessageFormat emf2 = new ExtendedMessageFormat(pattern2, registry);
-        assertEquals("Message with placeholder 'DUMMY'", emf2.format(new Object[] {"DUMMY"}));
-    }
-
-    /**
-     * Test extended and built in formats.
-     */
-    @Test
-    public void testExtendedAndBuiltInFormats() {
-        final Calendar cal = Calendar.getInstance();
-        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
-        final Object[] args = new Object[] {"John Doe", cal.getTime(), Double.valueOf("12345.67")};
-        final String builtinsPattern = "DOB: {1,date,short} Salary: {2,number,currency}";
-        final String extendedPattern = "Name: {0,upper} ";
-        final String pattern = extendedPattern + builtinsPattern;
-
-        final HashSet<Locale> testLocales = new HashSet<>();
-        testLocales.addAll(Arrays.asList(DateFormat.getAvailableLocales()));
-        testLocales.retainAll(Arrays.asList(NumberFormat.getAvailableLocales()));
-        testLocales.add(null);
-
-        for (final Locale locale : testLocales) {
-            final MessageFormat builtins = createMessageFormat(builtinsPattern, locale);
-            final String expectedPattern = extendedPattern + builtins.toPattern();
-            DateFormat df = null;
-            NumberFormat nf = null;
-            ExtendedMessageFormat emf = null;
-            if (locale == null) {
-                df = DateFormat.getDateInstance(DateFormat.SHORT);
-                nf = NumberFormat.getCurrencyInstance();
-                emf = new ExtendedMessageFormat(pattern, registry);
-            } else {
-                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
-                nf = NumberFormat.getCurrencyInstance(locale);
-                emf = new ExtendedMessageFormat(pattern, locale, registry);
-            }
-            final StringBuilder expected = new StringBuilder();
-            expected.append("Name: ");
-            expected.append(args[0].toString().toUpperCase());
-            expected.append(" DOB: ");
-            expected.append(df.format(args[1]));
-            expected.append(" Salary: ");
-            expected.append(nf.format(args[2]));
-            assertEquals("pattern comparison for locale " + locale, expectedPattern, emf.toPattern());
-            assertEquals(String.valueOf(locale), expected.toString(), emf.format(args));
-        }
-    }
-
-//    /**
-//     * Test extended formats with choice format.
-//     *
-//     * NOTE: FAILING - currently sub-formats not supported
-//     */
-//    public void testExtendedWithChoiceFormat() {
-//        String pattern = "Choice: {0,choice,1.0#{1,lower}|2.0#{1,upper}}";
-//        ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, registry);
-//        assertPatterns(null, pattern, emf.toPattern());
-//        try {
-//            assertEquals("one", emf.format(new Object[] {Integer.valueOf(1), "ONE"}));
-//            assertEquals("TWO", emf.format(new Object[] {Integer.valueOf(2), "two"}));
-//        } catch (IllegalArgumentException e) {
-//            // currently sub-formats not supported
-//        }
-//    }
-
-//    /**
-//     * Test mixed extended and built-in formats with choice format.
-//     *
-//     * NOTE: FAILING - currently sub-formats not supported
-//     */
-//    public void testExtendedAndBuiltInWithChoiceFormat() {
-//        String pattern = "Choice: {0,choice,1.0#{0} {1,lower} {2,number}|2.0#{0} {1,upper} {2,number,currency}}";
-//        Object[] lowArgs  = new Object[] {Integer.valueOf(1), "Low",  Double.valueOf("1234.56")};
-//        Object[] highArgs = new Object[] {Integer.valueOf(2), "High", Double.valueOf("9876.54")};
-//        Locale[] availableLocales = ChoiceFormat.getAvailableLocales();
-//        Locale[] testLocales = new Locale[availableLocales.length + 1];
-//        testLocales[0] = null;
-//        System.arraycopy(availableLocales, 0, testLocales, 1, availableLocales.length);
-//        for (int i = 0; i < testLocales.length; i++) {
-//            NumberFormat nf = null;
-//            NumberFormat cf = null;
-//            ExtendedMessageFormat emf = null;
-//            if (testLocales[i] == null) {
-//                nf = NumberFormat.getNumberInstance();
-//                cf = NumberFormat.getCurrencyInstance();
-//                emf = new ExtendedMessageFormat(pattern, registry);
-//            } else {
-//                nf = NumberFormat.getNumberInstance(testLocales[i]);
-//                cf = NumberFormat.getCurrencyInstance(testLocales[i]);
-//                emf = new ExtendedMessageFormat(pattern, testLocales[i], registry);
-//            }
-//            assertPatterns(null, pattern, emf.toPattern());
-//            try {
-//                String lowExpected = lowArgs[0] + " low "    + nf.format(lowArgs[2]);
-//                String highExpected = highArgs[0] + " HIGH "  + cf.format(highArgs[2]);
-//                assertEquals(lowExpected,  emf.format(lowArgs));
-//                assertEquals(highExpected, emf.format(highArgs));
-//            } catch (IllegalArgumentException e) {
-//                // currently sub-formats not supported
-//            }
-//        }
-//    }
-
-    /**
-     * Test the built in choice format.
-     */
-    @Test
-    public void testBuiltInChoiceFormat() {
-        final Object[] values = new Number[] {Integer.valueOf(1), Double.valueOf("2.2"), Double.valueOf("1234.5")};
-        String choicePattern = null;
-        final Locale[] availableLocales = NumberFormat.getAvailableLocales();
-
-        choicePattern = "{0,choice,1#One|2#Two|3#Many {0,number}}";
-        for (final Object value : values) {
-            checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
-        }
-
-        choicePattern = "{0,choice,1#''One''|2#\"Two\"|3#''{Many}'' {0,number}}";
-        for (final Object value : values) {
-            checkBuiltInFormat(value + ": " + choicePattern, new Object[] {value}, availableLocales);
-        }
-    }
-
-    /**
-     * Test the built in date/time formats
-     */
-    @Test
-    public void testBuiltInDateTimeFormat() {
-        final Calendar cal = Calendar.getInstance();
-        cal.set(2007, Calendar.JANUARY, 23, 18, 33, 05);
-        final Object[] args = new Object[] {cal.getTime()};
-        final Locale[] availableLocales = DateFormat.getAvailableLocales();
-
-        checkBuiltInFormat("1: {0,date,short}",    args, availableLocales);
-        checkBuiltInFormat("2: {0,date,medium}",   args, availableLocales);
-        checkBuiltInFormat("3: {0,date,long}",     args, availableLocales);
-        checkBuiltInFormat("4: {0,date,full}",     args, availableLocales);
-        checkBuiltInFormat("5: {0,date,d MMM yy}", args, availableLocales);
-        checkBuiltInFormat("6: {0,time,short}",    args, availableLocales);
-        checkBuiltInFormat("7: {0,time,medium}",   args, availableLocales);
-        checkBuiltInFormat("8: {0,time,long}",     args, availableLocales);
-        checkBuiltInFormat("9: {0,time,full}",     args, availableLocales);
-        checkBuiltInFormat("10: {0,time,HH:mm}",   args, availableLocales);
-        checkBuiltInFormat("11: {0,date}",         args, availableLocales);
-        checkBuiltInFormat("12: {0,time}",         args, availableLocales);
-    }
-
-    @Test
-    public void testOverriddenBuiltinFormat() {
-        final Calendar cal = Calendar.getInstance();
-        cal.set(2007, Calendar.JANUARY, 23);
-        final Object[] args = new Object[] {cal.getTime()};
-        final Locale[] availableLocales = DateFormat.getAvailableLocales();
-        final Map<String, ? extends FormatFactory> dateRegistry = Collections.singletonMap("date", new OverrideShortDateFormatFactory());
-
-        //check the non-overridden builtins:
-        checkBuiltInFormat("1: {0,date}", dateRegistry,          args, availableLocales);
-        checkBuiltInFormat("2: {0,date,medium}", dateRegistry,   args, availableLocales);
-        checkBuiltInFormat("3: {0,date,long}", dateRegistry,     args, availableLocales);
-        checkBuiltInFormat("4: {0,date,full}", dateRegistry,     args, availableLocales);
-        checkBuiltInFormat("5: {0,date,d MMM yy}", dateRegistry, args, availableLocales);
-
-        //check the overridden format:
-        for (int i = -1; i < availableLocales.length; i++) {
-            final Locale locale = i < 0 ? null : availableLocales[i];
-            final MessageFormat dateDefault = createMessageFormat("{0,date}", locale);
-            final String pattern = "{0,date,short}";
-            final ExtendedMessageFormat dateShort = new ExtendedMessageFormat(pattern, locale, dateRegistry);
-            assertEquals("overridden date,short format", dateDefault.format(args), dateShort.format(args));
-            assertEquals("overridden date,short pattern", pattern, dateShort.toPattern());
-        }
-    }
-
-    /**
-     * Test the built in number formats.
-     */
-    @Test
-    public void testBuiltInNumberFormat() {
-        final Object[] args = new Object[] {Double.valueOf("6543.21")};
-        final Locale[] availableLocales = NumberFormat.getAvailableLocales();
-        checkBuiltInFormat("1: {0,number}",            args, availableLocales);
-        checkBuiltInFormat("2: {0,number,integer}",    args, availableLocales);
-        checkBuiltInFormat("3: {0,number,currency}",   args, availableLocales);
-        checkBuiltInFormat("4: {0,number,percent}",    args, availableLocales);
-        checkBuiltInFormat("5: {0,number,00000.000}",  args, availableLocales);
-    }
-
-    /**
-     * Test equals() and hashcode.
-     */
-    @Test
-    public void testEqualsHashcode() {
-        final Map<String, ? extends FormatFactory> fmtRegistry = Collections.singletonMap("testfmt", new LowerCaseFormatFactory());
-        final Map<String, ? extends FormatFactory> otherRegitry = Collections.singletonMap("testfmt", new UpperCaseFormatFactory());
-
-        final String pattern = "Pattern: {0,testfmt}";
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
-
-        ExtendedMessageFormat other = null;
-
-        // Same object
-        assertTrue("same, equals()",   emf.equals(emf));
-        assertTrue("same, hashcode()", emf.hashCode() == emf.hashCode());
-
-        assertFalse("null, equals", emf.equals(null));
-
-        // Equal Object
-        other = new ExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
-        assertTrue("equal, equals()",   emf.equals(other));
-        assertTrue("equal, hashcode()", emf.hashCode() == other.hashCode());
-
-        // Different Class
-        other = new OtherExtendedMessageFormat(pattern, Locale.US, fmtRegistry);
-        assertFalse("class, equals()",  emf.equals(other));
-        assertTrue("class, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
-
-        // Different pattern
-        other = new ExtendedMessageFormat("X" + pattern, Locale.US, fmtRegistry);
-        assertFalse("pattern, equals()",   emf.equals(other));
-        assertFalse("pattern, hashcode()", emf.hashCode() == other.hashCode());
-
-        // Different registry
-        other = new ExtendedMessageFormat(pattern, Locale.US, otherRegitry);
-        assertFalse("registry, equals()",   emf.equals(other));
-        assertFalse("registry, hashcode()", emf.hashCode() == other.hashCode());
-
-        // Different Locale
-        other = new ExtendedMessageFormat(pattern, Locale.FRANCE, fmtRegistry);
-        assertFalse("locale, equals()",  emf.equals(other));
-        assertTrue("locale, hashcode()", emf.hashCode() == other.hashCode()); // same hashcode
-    }
-
-    /**
-     * Test a built in format for the specified Locales, plus <code>null</code> Locale.
-     * @param pattern MessageFormat pattern
-     * @param args MessageFormat arguments
-     * @param locales to test
-     */
-    private void checkBuiltInFormat(final String pattern, final Object[] args, final Locale[] locales) {
-        checkBuiltInFormat(pattern, null, args, locales);
-    }
-
-    /**
-     * Test a built in format for the specified Locales, plus <code>null</code> Locale.
-     * @param pattern MessageFormat pattern
-     * @param fmtRegistry FormatFactory registry to use
-     * @param args MessageFormat arguments
-     * @param locales to test
-     */
-    private void checkBuiltInFormat(final String pattern, final Map<String, ?> fmtRegistry, final Object[] args, final Locale[] locales) {
-        checkBuiltInFormat(pattern, fmtRegistry, args, (Locale) null);
-        for (final Locale locale : locales) {
-            checkBuiltInFormat(pattern, fmtRegistry, args, locale);
-        }
-    }
-
-    /**
-     * Create an ExtendedMessageFormat for the specified pattern and locale and check the
-     * formated output matches the expected result for the parameters.
-     * @param pattern string
-     * @param registryUnused map (currently unused)
-     * @param args Object[]
-     * @param locale Locale
-     */
-    private void checkBuiltInFormat(final String pattern, final Map<String, ?> registryUnused, final Object[] args, final Locale locale) {
-        final StringBuilder buffer = new StringBuilder();
-        buffer.append("Pattern=[");
-        buffer.append(pattern);
-        buffer.append("], locale=[");
-        buffer.append(locale);
-        buffer.append("]");
-        final MessageFormat mf = createMessageFormat(pattern, locale);
-        // System.out.println(buffer + ", result=[" + mf.format(args) +"]");
-        ExtendedMessageFormat emf = null;
-        if (locale == null) {
-            emf = new ExtendedMessageFormat(pattern);
-        } else {
-            emf = new ExtendedMessageFormat(pattern, locale);
-        }
-        assertEquals("format "    + buffer.toString(), mf.format(args), emf.format(args));
-        assertEquals("toPattern " + buffer.toString(), mf.toPattern(), emf.toPattern());
-    }
-
-    /**
-     * Replace MessageFormat(String, Locale) constructor (not available until JDK 1.4).
-     * @param pattern string
-     * @param locale Locale
-     * @return MessageFormat
-     */
-    private MessageFormat createMessageFormat(final String pattern, final Locale locale) {
-        final MessageFormat result = new MessageFormat(pattern);
-        if (locale != null) {
-            result.setLocale(locale);
-            result.applyPattern(pattern);
-        }
-        return result;
-    }
-
-    @Test(expected = UnsupportedOperationException.class)
-    public void testSetFormatIsUnsupported() {
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-        emf.setFormat(0, new LowerCaseFormat());
-    }
-
-    @Test(expected = UnsupportedOperationException.class)
-    public void testSetFormatByArgumentIndexIsUnsupported() {
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-        emf.setFormatByArgumentIndex(0, new LowerCaseFormat());
-    }
-
-    @Test(expected = UnsupportedOperationException.class)
-    public void testSetFormatsIsUnsupported() {
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-        emf.setFormats(new Format[]{new LowerCaseFormat(), new UpperCaseFormat()});
-    }
-
-    @Test(expected = UnsupportedOperationException.class)
-    public void testSetFormatsByArgumentIndex() {
-        final ExtendedMessageFormat emf = new ExtendedMessageFormat("");
-        emf.setFormatsByArgumentIndex(new Format[]{new LowerCaseFormat(), new UpperCaseFormat()});
-    }
-
-    // ------------------------ Test Formats ------------------------
-
-    /**
-     * {@link Format} implementation which converts to lower case.
-     */
-    private static class LowerCaseFormat extends Format {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-            return toAppendTo.append(((String)obj).toLowerCase());
-        }
-        @Override
-        public Object parseObject(final String source, final ParsePosition pos) {throw new UnsupportedOperationException();}
-    }
-
-    /**
-     * {@link Format} implementation which converts to upper case.
-     */
-    private static class UpperCaseFormat extends Format {
-        private static final long serialVersionUID = 1L;
-
-        @Override
-        public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
-            return toAppendTo.append(((String)obj).toUpperCase());
-        }
-        @Override
-        public Object parseObject(final String source, final ParsePosition pos) {throw new UnsupportedOperationException();}
-    }
-
-
-    // ------------------------ Test Format Factories ---------------
-    /**
-     * {@link FormatFactory} implementation for lower case format.
-     */
-    private static class LowerCaseFormatFactory implements FormatFactory {
-        private static final Format LOWER_INSTANCE = new LowerCaseFormat();
-        @Override
-        public Format getFormat(final String name, final String arguments, final Locale locale) {
-            return LOWER_INSTANCE;
-        }
-    }
-    /**
-     * {@link FormatFactory} implementation for upper case format.
-     */
-    private static class UpperCaseFormatFactory implements FormatFactory {
-        private static final Format UPPER_INSTANCE = new UpperCaseFormat();
-        @Override
-        public Format getFormat(final String name, final String arguments, final Locale locale) {
-            return UPPER_INSTANCE;
-        }
-    }
-    /**
-     * {@link FormatFactory} implementation to override date format "short" to "default".
-     */
-    private static class OverrideShortDateFormatFactory implements FormatFactory {
-        @Override
-        public Format getFormat(final String name, final String arguments, final Locale locale) {
-            return !"short".equals(arguments) ? null
-                    : locale == null ? DateFormat
-                            .getDateInstance(DateFormat.DEFAULT) : DateFormat
-                            .getDateInstance(DateFormat.DEFAULT, locale);
-        }
-    }
-
-    /**
-     * Alternative ExtendedMessageFormat impl.
-     */
-    private static class OtherExtendedMessageFormat extends ExtendedMessageFormat {
-        private static final long serialVersionUID = 1L;
-
-        public OtherExtendedMessageFormat(final String pattern, final Locale locale,
-                final Map<String, ? extends FormatFactory> registry) {
-            super(pattern, locale, registry);
-        }
-        
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/FormattableUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/FormattableUtilsTest.java b/src/test/java/org/apache/commons/text/beta/FormattableUtilsTest.java
deleted file mode 100644
index 6192373..0000000
--- a/src/test/java/org/apache/commons/text/beta/FormattableUtilsTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import static java.util.FormattableFlags.LEFT_JUSTIFY;
-import static org.junit.Assert.assertEquals;
-
-import java.util.Formattable;
-import java.util.Formatter;
-
-import org.junit.Test;
-
-/**
- * Unit tests {@link FormattableUtils}.
- */
-public class FormattableUtilsTest {
-
-    @Test
-    public void testPublicConstructorExists() {
-        new FormattableUtils();
-    }
-
-    @Test
-    public void testSimplestFormat() {
-        final Formattable formattable = new SimplestFormattable("foo");
-
-        assertEquals("foo",  FormattableUtils.toString(formattable));
-    }
-
-    @Test
-    public void testDefaultAppend() {
-        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1).toString());
-        assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2).toString());
-        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1).toString());
-        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1).toString());
-        assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2).toString());
-        assertEquals("   fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2).toString());
-        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1).toString());
-        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1).toString());
-        assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2).toString());
-        assertEquals("fo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2).toString());
-    }
-
-    @Test
-    public void testAlternatePadCharacter() {
-        final char pad='_';
-        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, pad).toString());
-        assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, pad).toString());
-        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, pad).toString());
-        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, pad).toString());
-        assertEquals("_fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, pad).toString());
-        assertEquals("___fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, pad).toString());
-        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, pad).toString());
-        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, pad).toString());
-        assertEquals("fo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, pad).toString());
-        assertEquals("fo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, pad).toString());
-    }
-
-    @Test
-    public void testEllipsis() {
-        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "*").toString());
-        assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "*").toString());
-        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "*").toString());
-        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "*").toString());
-        assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "*").toString());
-        assertEquals("   f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "*").toString());
-        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "*").toString());
-        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "*").toString());
-        assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "*").toString());
-        assertEquals("f*   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "*").toString());
-
-        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "+*").toString());
-        assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "+*").toString());
-        assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "+*").toString());
-        assertEquals("   foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "+*").toString());
-        assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "+*").toString());
-        assertEquals("   +*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "+*").toString());
-        assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "+*").toString());
-        assertEquals("foo   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "+*").toString());
-        assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "+*").toString());
-        assertEquals("+*   ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "+*").toString());
-    }
-
-    @Test(expected=IllegalArgumentException.class)
-    public void testIllegalEllipsis() {
-        FormattableUtils.append("foo", new Formatter(), 0, -1, 1, "xx");
-    }
-
-    @Test
-    public void testAlternatePadCharAndEllipsis() {
-        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "*").toString());
-        assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "*").toString());
-        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "*").toString());
-        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "*").toString());
-        assertEquals("_f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "*").toString());
-        assertEquals("___f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "*").toString());
-        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString());
-        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString());
-        assertEquals("f*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString());
-        assertEquals("f*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString());
-
-        assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "+*").toString());
-        assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "+*").toString());
-        assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "+*").toString());
-        assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "+*").toString());
-        assertEquals("_+*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "+*").toString());
-        assertEquals("___+*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "+*").toString());
-        assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString());
-        assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString());
-        assertEquals("+*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString());
-        assertEquals("+*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString());
-    }
-
-    static class SimplestFormattable implements Formattable {
-        private final String text;
-
-        SimplestFormattable(final String text) {
-            this.text = text;
-        }
-
-        @Override
-        public void formatTo(Formatter formatter, int flags, int width, int precision) {
-            formatter.format(text);
-        }
-    };
-
-
-}


[39/50] [abbrv] [text] TEXT-65: adding line to changes.xml

Posted by ch...@apache.org.
TEXT-65: adding line to changes.xml


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/89347419
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/89347419
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/89347419

Branch: refs/heads/release
Commit: 893474192e765e379ccb8b572145d2738529cc2b
Parents: 1063a8d
Author: Rob Tompkins <ch...@apache.org>
Authored: Fri Feb 17 08:40:23 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Fri Feb 17 08:40:23 2017 -0500

----------------------------------------------------------------------
 src/changes/changes.xml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/89347419/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 6a567ec..94db412 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -46,7 +46,8 @@ The <action> type attribute can be add,update,fix,remove.
   <body>
 
   <release version="TBA" date="TBA" description="TBA">
-  <action issue="TEXT-63" type="fix" dev="sebb">Mutable fields should be private</action>
+    <action issue="TEXT-65" type="fix" dev="chtompki">Fixing the 200 checkstyle errors present in 1.0-beta-1</action>
+    <action issue="TEXT-63" type="fix" dev="sebb">Mutable fields should be private</action>
   </release>
 
   <release version="1.0-beta-1" date="2017-01-30" description="First release (beta) of Commons Text">


[26/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/StrTokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrTokenizer.java b/src/main/java/org/apache/commons/text/StrTokenizer.java
new file mode 100644
index 0000000..8186f37
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/StrTokenizer.java
@@ -0,0 +1,1118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Tokenizes a string based based on delimiters (separators)
+ * and supporting quoting and ignored character concepts.
+ * <p>
+ * This class can split a String into many smaller strings. It aims
+ * to do a similar job to {@link java.util.StringTokenizer StringTokenizer},
+ * however it offers much more control and flexibility including implementing
+ * the <code>ListIterator</code> interface. By default, it is set up
+ * like <code>StringTokenizer</code>.
+ * <p>
+ * The input String is split into a number of <i>tokens</i>.
+ * Each token is separated from the next String by a <i>delimiter</i>.
+ * One or more delimiter characters must be specified.
+ * <p>
+ * Each token may be surrounded by quotes.
+ * The <i>quote</i> matcher specifies the quote character(s).
+ * A quote may be escaped within a quoted section by duplicating itself.
+ * <p>
+ * Between each token and the delimiter are potentially characters that need trimming.
+ * The <i>trimmer</i> matcher specifies these characters.
+ * One usage might be to trim whitespace characters.
+ * <p>
+ * At any point outside the quotes there might potentially be invalid characters.
+ * The <i>ignored</i> matcher specifies these characters to be removed.
+ * One usage might be to remove new line characters.
+ * <p>
+ * Empty tokens may be removed or returned as null.
+ * <pre>
+ * "a,b,c"         - Three tokens "a","b","c"   (comma delimiter)
+ * " a, b , c "    - Three tokens "a","b","c"   (default CSV processing trims whitespace)
+ * "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
+ * </pre>
+ * <p>
+ *
+ * This tokenizer has the following properties and options:
+ *
+ * <table summary="Tokenizer Properties">
+ *  <tr>
+ *   <th>Property</th><th>Type</th><th>Default</th>
+ *  </tr>
+ *  <tr>
+ *   <td>delim</td><td>CharSetMatcher</td><td>{ \t\n\r\f}</td>
+ *  </tr>
+ *  <tr>
+ *   <td>quote</td><td>NoneMatcher</td><td>{}</td>
+ *  </tr>
+ *  <tr>
+ *   <td>ignore</td><td>NoneMatcher</td><td>{}</td>
+ *  </tr>
+ *  <tr>
+ *   <td>emptyTokenAsNull</td><td>boolean</td><td>false</td>
+ *  </tr>
+ *  <tr>
+ *   <td>ignoreEmptyTokens</td><td>boolean</td><td>true</td>
+ *  </tr>
+ * </table>
+ *
+ * @since 1.0
+ */
+public class StrTokenizer implements ListIterator<String>, Cloneable {
+
+    private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE;
+    private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE;
+    static {
+        CSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
+        CSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.commaMatcher());
+        CSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
+        CSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
+        CSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
+        CSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
+        CSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
+
+        TSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
+        TSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.tabMatcher());
+        TSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
+        TSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
+        TSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
+        TSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
+        TSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
+    }
+
+    /** The text to work on. */
+    private char chars[];
+    /** The parsed tokens */
+    private String tokens[];
+    /** The current iteration position */
+    private int tokenPos;
+
+    /** The delimiter matcher */
+    private StrMatcher delimMatcher = StrMatcher.splitMatcher();
+    /** The quote matcher */
+    private StrMatcher quoteMatcher = StrMatcher.noneMatcher();
+    /** The ignored matcher */
+    private StrMatcher ignoredMatcher = StrMatcher.noneMatcher();
+    /** The trimmer matcher */
+    private StrMatcher trimmerMatcher = StrMatcher.noneMatcher();
+
+    /** Whether to return empty tokens as null */
+    private boolean emptyAsNull = false;
+    /** Whether to ignore empty tokens */
+    private boolean ignoreEmptyTokens = true;
+
+    //-----------------------------------------------------------------------
+
+    /**
+     * Returns a clone of <code>CSV_TOKENIZER_PROTOTYPE</code>.
+     *
+     * @return a clone of <code>CSV_TOKENIZER_PROTOTYPE</code>.
+     */
+    private static StrTokenizer getCSVClone() {
+        return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone();
+    }
+
+    /**
+     * Gets a new tokenizer instance which parses Comma Separated Value strings
+     * initializing it with the given input.  The default for CSV processing
+     * will be trim whitespace from both ends (which can be overridden with
+     * the setTrimmer method).
+     * <p>
+     * You must call a "reset" method to set the string which you want to parse.
+     * @return a new tokenizer instance which parses Comma Separated Value strings
+     */
+    public static StrTokenizer getCSVInstance() {
+        return getCSVClone();
+    }
+
+    /**
+     * Gets a new tokenizer instance which parses Comma Separated Value strings
+     * initializing it with the given input.  The default for CSV processing
+     * will be trim whitespace from both ends (which can be overridden with
+     * the setTrimmer method).
+     *
+     * @param input  the text to parse
+     * @return a new tokenizer instance which parses Comma Separated Value strings
+     */
+    public static StrTokenizer getCSVInstance(final String input) {
+        final StrTokenizer tok = getCSVClone();
+        tok.reset(input);
+        return tok;
+    }
+
+    /**
+     * Gets a new tokenizer instance which parses Comma Separated Value strings
+     * initializing it with the given input.  The default for CSV processing
+     * will be trim whitespace from both ends (which can be overridden with
+     * the setTrimmer method).
+     *
+     * @param input  the text to parse
+     * @return a new tokenizer instance which parses Comma Separated Value strings
+     */
+    public static StrTokenizer getCSVInstance(final char[] input) {
+        final StrTokenizer tok = getCSVClone();
+        tok.reset(input);
+        return tok;
+    }
+
+    /**
+     * Returns a clone of <code>TSV_TOKENIZER_PROTOTYPE</code>.
+     *
+     * @return a clone of <code>TSV_TOKENIZER_PROTOTYPE</code>.
+     */
+    private static StrTokenizer getTSVClone() {
+        return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone();
+    }
+
+
+    /**
+     * Gets a new tokenizer instance which parses Tab Separated Value strings.
+     * The default for CSV processing will be trim whitespace from both ends
+     * (which can be overridden with the setTrimmer method).
+     * <p>
+     * You must call a "reset" method to set the string which you want to parse.
+     * @return a new tokenizer instance which parses Tab Separated Value strings.
+     */
+    public static StrTokenizer getTSVInstance() {
+        return getTSVClone();
+    }
+
+    /**
+     * Gets a new tokenizer instance which parses Tab Separated Value strings.
+     * The default for CSV processing will be trim whitespace from both ends
+     * (which can be overridden with the setTrimmer method).
+     * @param input  the string to parse
+     * @return a new tokenizer instance which parses Tab Separated Value strings.
+     */
+    public static StrTokenizer getTSVInstance(final String input) {
+        final StrTokenizer tok = getTSVClone();
+        tok.reset(input);
+        return tok;
+    }
+
+    /**
+     * Gets a new tokenizer instance which parses Tab Separated Value strings.
+     * The default for CSV processing will be trim whitespace from both ends
+     * (which can be overridden with the setTrimmer method).
+     * @param input  the string to parse
+     * @return a new tokenizer instance which parses Tab Separated Value strings.
+     */
+    public static StrTokenizer getTSVInstance(final char[] input) {
+        final StrTokenizer tok = getTSVClone();
+        tok.reset(input);
+        return tok;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructs a tokenizer splitting on space, tab, newline and formfeed
+     * as per StringTokenizer, but with no text to tokenize.
+     * <p>
+     * This constructor is normally used with {@link #reset(String)}.
+     */
+    public StrTokenizer() {
+        super();
+        this.chars = null;
+    }
+
+    /**
+     * Constructs a tokenizer splitting on space, tab, newline and formfeed
+     * as per StringTokenizer.
+     *
+     * @param input  the string which is to be parsed
+     */
+    public StrTokenizer(final String input) {
+        super();
+        if (input != null) {
+            chars = input.toCharArray();
+        } else {
+            chars = null;
+        }
+    }
+
+    /**
+     * Constructs a tokenizer splitting on the specified delimiter character.
+     *
+     * @param input  the string which is to be parsed
+     * @param delim  the field delimiter character
+     */
+    public StrTokenizer(final String input, final char delim) {
+        this(input);
+        setDelimiterChar(delim);
+    }
+
+    /**
+     * Constructs a tokenizer splitting on the specified delimiter string.
+     *
+     * @param input  the string which is to be parsed
+     * @param delim  the field delimiter string
+     */
+    public StrTokenizer(final String input, final String delim) {
+        this(input);
+        setDelimiterString(delim);
+    }
+
+    /**
+     * Constructs a tokenizer splitting using the specified delimiter matcher.
+     *
+     * @param input  the string which is to be parsed
+     * @param delim  the field delimiter matcher
+     */
+    public StrTokenizer(final String input, final StrMatcher delim) {
+        this(input);
+        setDelimiterMatcher(delim);
+    }
+
+    /**
+     * Constructs a tokenizer splitting on the specified delimiter character
+     * and handling quotes using the specified quote character.
+     *
+     * @param input  the string which is to be parsed
+     * @param delim  the field delimiter character
+     * @param quote  the field quoted string character
+     */
+    public StrTokenizer(final String input, final char delim, final char quote) {
+        this(input, delim);
+        setQuoteChar(quote);
+    }
+
+    /**
+     * Constructs a tokenizer splitting using the specified delimiter matcher
+     * and handling quotes using the specified quote matcher.
+     *
+     * @param input  the string which is to be parsed
+     * @param delim  the field delimiter matcher
+     * @param quote  the field quoted string matcher
+     */
+    public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) {
+        this(input, delim);
+        setQuoteMatcher(quote);
+    }
+
+    /**
+     * Constructs a tokenizer splitting on space, tab, newline and formfeed
+     * as per StringTokenizer.
+     *
+     * @param input  the string which is to be parsed, not cloned
+     */
+    public StrTokenizer(final char[] input) {
+        super();
+        if (input == null) {
+            this.chars = null;
+        } else {
+            this.chars = input.clone();
+        }
+    }
+
+    /**
+     * Constructs a tokenizer splitting on the specified character.
+     *
+     * @param input  the string which is to be parsed, not cloned
+     * @param delim the field delimiter character
+     */
+    public StrTokenizer(final char[] input, final char delim) {
+        this(input);
+        setDelimiterChar(delim);
+    }
+
+    /**
+     * Constructs a tokenizer splitting on the specified string.
+     *
+     * @param input  the string which is to be parsed, not cloned
+     * @param delim the field delimiter string
+     */
+    public StrTokenizer(final char[] input, final String delim) {
+        this(input);
+        setDelimiterString(delim);
+    }
+
+    /**
+     * Constructs a tokenizer splitting using the specified delimiter matcher.
+     *
+     * @param input  the string which is to be parsed, not cloned
+     * @param delim  the field delimiter matcher
+     */
+    public StrTokenizer(final char[] input, final StrMatcher delim) {
+        this(input);
+        setDelimiterMatcher(delim);
+    }
+
+    /**
+     * Constructs a tokenizer splitting on the specified delimiter character
+     * and handling quotes using the specified quote character.
+     *
+     * @param input  the string which is to be parsed, not cloned
+     * @param delim  the field delimiter character
+     * @param quote  the field quoted string character
+     */
+    public StrTokenizer(final char[] input, final char delim, final char quote) {
+        this(input, delim);
+        setQuoteChar(quote);
+    }
+
+    /**
+     * Constructs a tokenizer splitting using the specified delimiter matcher
+     * and handling quotes using the specified quote matcher.
+     *
+     * @param input  the string which is to be parsed, not cloned
+     * @param delim  the field delimiter character
+     * @param quote  the field quoted string character
+     */
+    public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) {
+        this(input, delim);
+        setQuoteMatcher(quote);
+    }
+
+    // API
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of tokens found in the String.
+     *
+     * @return the number of matched tokens
+     */
+    public int size() {
+        checkTokenized();
+        return tokens.length;
+    }
+
+    /**
+     * Gets the next token from the String.
+     * Equivalent to {@link #next()} except it returns null rather than
+     * throwing {@link NoSuchElementException} when no tokens remain.
+     *
+     * @return the next sequential token, or null when no more tokens are found
+     */
+    public String nextToken() {
+        if (hasNext()) {
+            return tokens[tokenPos++];
+        }
+        return null;
+    }
+
+    /**
+     * Gets the previous token from the String.
+     *
+     * @return the previous sequential token, or null when no more tokens are found
+     */
+    public String previousToken() {
+        if (hasPrevious()) {
+            return tokens[--tokenPos];
+        }
+        return null;
+    }
+
+    /**
+     * Gets a copy of the full token list as an independent modifiable array.
+     *
+     * @return the tokens as a String array
+     */
+    public String[] getTokenArray() {
+        checkTokenized();
+        return tokens.clone();
+    }
+
+    /**
+     * Gets a copy of the full token list as an independent modifiable list.
+     *
+     * @return the tokens as a String array
+     */
+    public List<String> getTokenList() {
+        checkTokenized();
+        final List<String> list = new ArrayList<>(tokens.length);
+        for (final String element : tokens) {
+            list.add(element);
+        }
+        return list;
+    }
+
+    /**
+     * Resets this tokenizer, forgetting all parsing and iteration already completed.
+     * <p>
+     * This method allows the same tokenizer to be reused for the same String.
+     *
+     * @return this, to enable chaining
+     */
+    public StrTokenizer reset() {
+        tokenPos = 0;
+        tokens = null;
+        return this;
+    }
+
+    /**
+     * Reset this tokenizer, giving it a new input string to parse.
+     * In this manner you can re-use a tokenizer with the same settings
+     * on multiple input lines.
+     *
+     * @param input  the new string to tokenize, null sets no text to parse
+     * @return this, to enable chaining
+     */
+    public StrTokenizer reset(final String input) {
+        reset();
+        if (input != null) {
+            this.chars = input.toCharArray();
+        } else {
+            this.chars = null;
+        }
+        return this;
+    }
+
+    /**
+     * Reset this tokenizer, giving it a new input string to parse.
+     * In this manner you can re-use a tokenizer with the same settings
+     * on multiple input lines.
+     *
+     * @param input  the new character array to tokenize, not cloned, null sets no text to parse
+     * @return this, to enable chaining
+     */
+    public StrTokenizer reset(final char[] input) {
+        reset();
+        if (input != null) {
+            this.chars = input.clone();
+        } else {
+            this.chars = null;
+        }
+        return this;
+    }
+
+    // ListIterator
+    //-----------------------------------------------------------------------
+    /**
+     * Checks whether there are any more tokens.
+     *
+     * @return true if there are more tokens
+     */
+    @Override
+    public boolean hasNext() {
+        checkTokenized();
+        return tokenPos < tokens.length;
+    }
+
+    /**
+     * Gets the next token.
+     *
+     * @return the next String token
+     * @throws NoSuchElementException if there are no more elements
+     */
+    @Override
+    public String next() {
+        if (hasNext()) {
+            return tokens[tokenPos++];
+        }
+        throw new NoSuchElementException();
+    }
+
+    /**
+     * Gets the index of the next token to return.
+     *
+     * @return the next token index
+     */
+    @Override
+    public int nextIndex() {
+        return tokenPos;
+    }
+
+    /**
+     * Checks whether there are any previous tokens that can be iterated to.
+     *
+     * @return true if there are previous tokens
+     */
+    @Override
+    public boolean hasPrevious() {
+        checkTokenized();
+        return tokenPos > 0;
+    }
+
+    /**
+     * Gets the token previous to the last returned token.
+     *
+     * @return the previous token
+     */
+    @Override
+    public String previous() {
+        if (hasPrevious()) {
+            return tokens[--tokenPos];
+        }
+        throw new NoSuchElementException();
+    }
+
+    /**
+     * Gets the index of the previous token.
+     *
+     * @return the previous token index
+     */
+    @Override
+    public int previousIndex() {
+        return tokenPos - 1;
+    }
+
+    /**
+     * Unsupported ListIterator operation.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("remove() is unsupported");
+    }
+
+    /**
+     * Unsupported ListIterator operation.
+     * @param obj this parameter ignored.
+     * @throws UnsupportedOperationException always
+     */
+    @Override
+    public void set(final String obj) {
+        throw new UnsupportedOperationException("set() is unsupported");
+    }
+
+    /**
+     * Unsupported ListIterator operation.
+     * @param obj this parameter ignored.
+     * @throws UnsupportedOperationException always
+     */
+    @Override
+    public void add(final String obj) {
+        throw new UnsupportedOperationException("add() is unsupported");
+    }
+
+    // Implementation
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if tokenization has been done, and if not then do it.
+     */
+    private void checkTokenized() {
+        if (tokens == null) {
+            if (chars == null) {
+                // still call tokenize as subclass may do some work
+                final List<String> split = tokenize(null, 0, 0);
+                tokens = split.toArray(new String[split.size()]);
+            } else {
+                final List<String> split = tokenize(chars, 0, chars.length);
+                tokens = split.toArray(new String[split.size()]);
+            }
+        }
+    }
+
+    /**
+     * Internal method to performs the tokenization.
+     * <p>
+     * Most users of this class do not need to call this method. This method
+     * will be called automatically by other (public) methods when required.
+     * <p>
+     * This method exists to allow subclasses to add code before or after the
+     * tokenization. For example, a subclass could alter the character array,
+     * offset or count to be parsed, or call the tokenizer multiple times on
+     * multiple strings. It is also be possible to filter the results.
+     * <p>
+     * <code>StrTokenizer</code> will always pass a zero offset and a count
+     * equal to the length of the array to this method, however a subclass
+     * may pass other values, or even an entirely different array.
+     *
+     * @param srcChars  the character array being tokenized, may be null
+     * @param offset  the start position within the character array, must be valid
+     * @param count  the number of characters to tokenize, must be valid
+     * @return the modifiable list of String tokens, unmodifiable if null array or zero count
+     */
+    protected List<String> tokenize(final char[] srcChars, final int offset, final int count) {
+        if (srcChars == null || count == 0) {
+            return Collections.emptyList();
+        }
+        final StrBuilder buf = new StrBuilder();
+        final List<String> tokenList = new ArrayList<>();
+        int pos = offset;
+
+        // loop around the entire buffer
+        while (pos >= 0 && pos < count) {
+            // find next token
+            pos = readNextToken(srcChars, pos, count, buf, tokenList);
+
+            // handle case where end of string is a delimiter
+            if (pos >= count) {
+                addToken(tokenList, "");
+            }
+        }
+        return tokenList;
+    }
+
+    /**
+     * Adds a token to a list, paying attention to the parameters we've set.
+     *
+     * @param list  the list to add to
+     * @param tok  the token to add
+     */
+    private void addToken(final List<String> list, String tok) {
+        if (tok == null || tok.length() == 0) {
+            if (isIgnoreEmptyTokens()) {
+                return;
+            }
+            if (isEmptyTokenAsNull()) {
+                tok = null;
+            }
+        }
+        list.add(tok);
+    }
+
+    /**
+     * Reads character by character through the String to get the next token.
+     *
+     * @param srcChars  the character array being tokenized
+     * @param start  the first character of field
+     * @param len  the length of the character array being tokenized
+     * @param workArea  a temporary work area
+     * @param tokenList  the list of parsed tokens
+     * @return the starting position of the next field (the character
+     *  immediately after the delimiter), or -1 if end of string found
+     */
+    private int readNextToken(final char[] srcChars, int start, final int len, final StrBuilder workArea, final List<String> tokenList) {
+        // skip all leading whitespace, unless it is the
+        // field delimiter or the quote character
+        while (start < len) {
+            final int removeLen = Math.max(
+                    getIgnoredMatcher().isMatch(srcChars, start, start, len),
+                    getTrimmerMatcher().isMatch(srcChars, start, start, len));
+            if (removeLen == 0 ||
+                getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0 ||
+                getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) {
+                break;
+            }
+            start += removeLen;
+        }
+
+        // handle reaching end
+        if (start >= len) {
+            addToken(tokenList, "");
+            return -1;
+        }
+
+        // handle empty token
+        final int delimLen = getDelimiterMatcher().isMatch(srcChars, start, start, len);
+        if (delimLen > 0) {
+            addToken(tokenList, "");
+            return start + delimLen;
+        }
+
+        // handle found token
+        final int quoteLen = getQuoteMatcher().isMatch(srcChars, start, start, len);
+        if (quoteLen > 0) {
+            return readWithQuotes(srcChars, start + quoteLen, len, workArea, tokenList, start, quoteLen);
+        }
+        return readWithQuotes(srcChars, start, len, workArea, tokenList, 0, 0);
+    }
+
+    /**
+     * Reads a possibly quoted string token.
+     *
+     * @param srcChars  the character array being tokenized
+     * @param start  the first character of field
+     * @param len  the length of the character array being tokenized
+     * @param workArea  a temporary work area
+     * @param tokenList  the list of parsed tokens
+     * @param quoteStart  the start position of the matched quote, 0 if no quoting
+     * @param quoteLen  the length of the matched quote, 0 if no quoting
+     * @return the starting position of the next field (the character
+     *  immediately after the delimiter, or if end of string found,
+     *  then the length of string
+     */
+    private int readWithQuotes(final char[] srcChars, final int start, final int len, final StrBuilder workArea,
+                               final List<String> tokenList, final int quoteStart, final int quoteLen) {
+        // Loop until we've found the end of the quoted
+        // string or the end of the input
+        workArea.clear();
+        int pos = start;
+        boolean quoting = quoteLen > 0;
+        int trimStart = 0;
+
+        while (pos < len) {
+            // quoting mode can occur several times throughout a string
+            // we must switch between quoting and non-quoting until we
+            // encounter a non-quoted delimiter, or end of string
+            if (quoting) {
+                // In quoting mode
+
+                // If we've found a quote character, see if it's
+                // followed by a second quote.  If so, then we need
+                // to actually put the quote character into the token
+                // rather than end the token.
+                if (isQuote(srcChars, pos, len, quoteStart, quoteLen)) {
+                    if (isQuote(srcChars, pos + quoteLen, len, quoteStart, quoteLen)) {
+                        // matched pair of quotes, thus an escaped quote
+                        workArea.append(srcChars, pos, quoteLen);
+                        pos += quoteLen * 2;
+                        trimStart = workArea.size();
+                        continue;
+                    }
+
+                    // end of quoting
+                    quoting = false;
+                    pos += quoteLen;
+                    continue;
+                }
+
+                // copy regular character from inside quotes
+                workArea.append(srcChars[pos++]);
+                trimStart = workArea.size();
+
+            } else {
+                // Not in quoting mode
+
+                // check for delimiter, and thus end of token
+                final int delimLen = getDelimiterMatcher().isMatch(srcChars, pos, start, len);
+                if (delimLen > 0) {
+                    // return condition when end of token found
+                    addToken(tokenList, workArea.substring(0, trimStart));
+                    return pos + delimLen;
+                }
+
+                // check for quote, and thus back into quoting mode
+                if (quoteLen > 0 && isQuote(srcChars, pos, len, quoteStart, quoteLen)) {
+                    quoting = true;
+                    pos += quoteLen;
+                    continue;
+                }
+
+                // check for ignored (outside quotes), and ignore
+                final int ignoredLen = getIgnoredMatcher().isMatch(srcChars, pos, start, len);
+                if (ignoredLen > 0) {
+                    pos += ignoredLen;
+                    continue;
+                }
+
+                // check for trimmed character
+                // don't yet know if its at the end, so copy to workArea
+                // use trimStart to keep track of trim at the end
+                final int trimmedLen = getTrimmerMatcher().isMatch(srcChars, pos, start, len);
+                if (trimmedLen > 0) {
+                    workArea.append(srcChars, pos, trimmedLen);
+                    pos += trimmedLen;
+                    continue;
+                }
+
+                // copy regular character from outside quotes
+                workArea.append(srcChars[pos++]);
+                trimStart = workArea.size();
+            }
+        }
+
+        // return condition when end of string found
+        addToken(tokenList, workArea.substring(0, trimStart));
+        return -1;
+    }
+
+    /**
+     * Checks if the characters at the index specified match the quote
+     * already matched in readNextToken().
+     *
+     * @param srcChars  the character array being tokenized
+     * @param pos  the position to check for a quote
+     * @param len  the length of the character array being tokenized
+     * @param quoteStart  the start position of the matched quote, 0 if no quoting
+     * @param quoteLen  the length of the matched quote, 0 if no quoting
+     * @return true if a quote is matched
+     */
+    private boolean isQuote(final char[] srcChars, final int pos, final int len, final int quoteStart, final int quoteLen) {
+        for (int i = 0; i < quoteLen; i++) {
+            if (pos + i >= len || srcChars[pos + i] != srcChars[quoteStart + i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // Delimiter
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the field delimiter matcher.
+     *
+     * @return the delimiter matcher in use
+     */
+    public StrMatcher getDelimiterMatcher() {
+        return this.delimMatcher;
+    }
+
+    /**
+     * Sets the field delimiter matcher.
+     * <p>
+     * The delimitier is used to separate one token from another.
+     *
+     * @param delim  the delimiter matcher to use
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setDelimiterMatcher(final StrMatcher delim) {
+        if (delim == null) {
+            this.delimMatcher = StrMatcher.noneMatcher();
+        } else {
+            this.delimMatcher = delim;
+        }
+        return this;
+    }
+
+    /**
+     * Sets the field delimiter character.
+     *
+     * @param delim  the delimiter character to use
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setDelimiterChar(final char delim) {
+        return setDelimiterMatcher(StrMatcher.charMatcher(delim));
+    }
+
+    /**
+     * Sets the field delimiter string.
+     *
+     * @param delim  the delimiter string to use
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setDelimiterString(final String delim) {
+        return setDelimiterMatcher(StrMatcher.stringMatcher(delim));
+    }
+
+    // Quote
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the quote matcher currently in use.
+     * <p>
+     * The quote character is used to wrap data between the tokens.
+     * This enables delimiters to be entered as data.
+     * The default value is '"' (double quote).
+     *
+     * @return the quote matcher in use
+     */
+    public StrMatcher getQuoteMatcher() {
+        return quoteMatcher;
+    }
+
+    /**
+     * Set the quote matcher to use.
+     * <p>
+     * The quote character is used to wrap data between the tokens.
+     * This enables delimiters to be entered as data.
+     *
+     * @param quote  the quote matcher to use, null ignored
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setQuoteMatcher(final StrMatcher quote) {
+        if (quote != null) {
+            this.quoteMatcher = quote;
+        }
+        return this;
+    }
+
+    /**
+     * Sets the quote character to use.
+     * <p>
+     * The quote character is used to wrap data between the tokens.
+     * This enables delimiters to be entered as data.
+     *
+     * @param quote  the quote character to use
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setQuoteChar(final char quote) {
+        return setQuoteMatcher(StrMatcher.charMatcher(quote));
+    }
+
+    // Ignored
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ignored character matcher.
+     * <p>
+     * These characters are ignored when parsing the String, unless they are
+     * within a quoted region.
+     * The default value is not to ignore anything.
+     *
+     * @return the ignored matcher in use
+     */
+    public StrMatcher getIgnoredMatcher() {
+        return ignoredMatcher;
+    }
+
+    /**
+     * Set the matcher for characters to ignore.
+     * <p>
+     * These characters are ignored when parsing the String, unless they are
+     * within a quoted region.
+     *
+     * @param ignored  the ignored matcher to use, null ignored
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) {
+        if (ignored != null) {
+            this.ignoredMatcher = ignored;
+        }
+        return this;
+    }
+
+    /**
+     * Set the character to ignore.
+     * <p>
+     * This character is ignored when parsing the String, unless it is
+     * within a quoted region.
+     *
+     * @param ignored  the ignored character to use
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setIgnoredChar(final char ignored) {
+        return setIgnoredMatcher(StrMatcher.charMatcher(ignored));
+    }
+
+    // Trimmer
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the trimmer character matcher.
+     * <p>
+     * These characters are trimmed off on each side of the delimiter
+     * until the token or quote is found.
+     * The default value is not to trim anything.
+     *
+     * @return the trimmer matcher in use
+     */
+    public StrMatcher getTrimmerMatcher() {
+        return trimmerMatcher;
+    }
+
+    /**
+     * Sets the matcher for characters to trim.
+     * <p>
+     * These characters are trimmed off on each side of the delimiter
+     * until the token or quote is found.
+     *
+     * @param trimmer  the trimmer matcher to use, null ignored
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) {
+        if (trimmer != null) {
+            this.trimmerMatcher = trimmer;
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets whether the tokenizer currently returns empty tokens as null.
+     * The default for this property is false.
+     *
+     * @return true if empty tokens are returned as null
+     */
+    public boolean isEmptyTokenAsNull() {
+        return this.emptyAsNull;
+    }
+
+    /**
+     * Sets whether the tokenizer should return empty tokens as null.
+     * The default for this property is false.
+     *
+     * @param emptyAsNull  whether empty tokens are returned as null
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) {
+        this.emptyAsNull = emptyAsNull;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets whether the tokenizer currently ignores empty tokens.
+     * The default for this property is true.
+     *
+     * @return true if empty tokens are not returned
+     */
+    public boolean isIgnoreEmptyTokens() {
+        return ignoreEmptyTokens;
+    }
+
+    /**
+     * Sets whether the tokenizer should ignore and not return empty tokens.
+     * The default for this property is true.
+     *
+     * @param ignoreEmptyTokens  whether empty tokens are not returned
+     * @return this, to enable chaining
+     */
+    public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) {
+        this.ignoreEmptyTokens = ignoreEmptyTokens;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the String content that the tokenizer is parsing.
+     *
+     * @return the string content being parsed
+     */
+    public String getContent() {
+        if (chars == null) {
+            return null;
+        }
+        return new String(chars);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a new instance of this Tokenizer. The new instance is reset so
+     * that it will be at the start of the token list.
+     * If a {@link CloneNotSupportedException} is caught, return <code>null</code>.
+     * 
+     * @return a new instance of this Tokenizer which has been reset.
+     */
+    @Override
+    public Object clone() {
+        try {
+            return cloneReset();
+        } catch (final CloneNotSupportedException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Creates a new instance of this Tokenizer. The new instance is reset so that
+     * it will be at the start of the token list.
+     * 
+     * @return a new instance of this Tokenizer which has been reset.
+     * @throws CloneNotSupportedException if there is a problem cloning
+     */
+    Object cloneReset() throws CloneNotSupportedException {
+        // this method exists to enable 100% test coverage
+        final StrTokenizer cloned = (StrTokenizer) super.clone();
+        if (cloned.chars != null) {
+            cloned.chars = cloned.chars.clone();
+        }
+        cloned.reset();
+        return cloned;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the String content that the tokenizer is parsing.
+     *
+     * @return the string content being parsed
+     */
+    @Override
+    public String toString() {
+        if (tokens == null) {
+            return "StrTokenizer[not tokenized yet]";
+        }
+        return "StrTokenizer" + getTokenList();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/StringEscapeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StringEscapeUtils.java b/src/main/java/org/apache/commons/text/StringEscapeUtils.java
new file mode 100644
index 0000000..aa6b071
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/StringEscapeUtils.java
@@ -0,0 +1,959 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.translate.AggregateTranslator;
+import org.apache.commons.text.translate.CharSequenceTranslator;
+import org.apache.commons.text.translate.CsvTranslators;
+import org.apache.commons.text.translate.EntityArrays;
+import org.apache.commons.text.translate.JavaUnicodeEscaper;
+import org.apache.commons.text.translate.LookupTranslator;
+import org.apache.commons.text.translate.NumericEntityEscaper;
+import org.apache.commons.text.translate.NumericEntityUnescaper;
+import org.apache.commons.text.translate.OctalUnescaper;
+import org.apache.commons.text.translate.SingleLookupTranslator;
+import org.apache.commons.text.translate.UnicodeUnescaper;
+import org.apache.commons.text.translate.UnicodeUnpairedSurrogateRemover;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>Escapes and unescapes {@code String}s for
+ * Java, Java Script, HTML and XML.</p>
+ *
+ * <p>#ThreadSafe#</p>
+ *
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Lang 3.5.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class StringEscapeUtils {
+
+    /* ESCAPE TRANSLATORS */
+
+    /**
+     * Translator object for escaping Java.
+     *
+     * While {@link #escapeJava(String)} is the expected method of use, this
+     * object allows the Java escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_JAVA;
+    static {
+        Map<CharSequence, CharSequence> escapeJavaMap = new HashMap<>();
+        escapeJavaMap.put("\"", "\\\"");
+        escapeJavaMap.put("\\", "\\\\");
+        ESCAPE_JAVA = new AggregateTranslator(
+                new LookupTranslator(Collections.unmodifiableMap(escapeJavaMap)),
+                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
+                JavaUnicodeEscaper.outsideOf(32, 0x7f)
+        );
+    }
+
+    /**
+     * Translator object for escaping EcmaScript/JavaScript.
+     *
+     * While {@link #escapeEcmaScript(String)} is the expected method of use, this
+     * object allows the EcmaScript escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_ECMASCRIPT;
+    static {
+        Map<CharSequence, CharSequence> escapeEcmaScriptMap = new HashMap<>();
+        escapeEcmaScriptMap.put("'", "\\'");
+        escapeEcmaScriptMap.put("\"", "\\\"");
+        escapeEcmaScriptMap.put("\\", "\\\\");
+        escapeEcmaScriptMap.put("/", "\\/");
+        ESCAPE_ECMASCRIPT = new AggregateTranslator(
+                new LookupTranslator(Collections.unmodifiableMap(escapeEcmaScriptMap)),
+                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
+                JavaUnicodeEscaper.outsideOf(32, 0x7f)
+        );
+    }
+
+    /**
+     * Translator object for escaping Json.
+     *
+     * While {@link #escapeJson(String)} is the expected method of use, this
+     * object allows the Json escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_JSON;
+    static {
+        Map<CharSequence, CharSequence> escapeJsonMap = new HashMap<>();
+        escapeJsonMap.put("\"", "\\\"");
+        escapeJsonMap.put("\\", "\\\\");
+        escapeJsonMap.put("/", "\\/");
+        ESCAPE_JSON = new AggregateTranslator(
+                new LookupTranslator(Collections.unmodifiableMap(escapeJsonMap)),
+                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
+                JavaUnicodeEscaper.outsideOf(32, 0x7f)
+        );
+    }
+
+    /**
+     * Translator object for escaping XML 1.0.
+     *
+     * While {@link #escapeXml10(String)} is the expected method of use, this
+     * object allows the XML escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_XML10;
+    static {
+        Map<CharSequence, CharSequence> escapeXml10Map = new HashMap<>();
+        escapeXml10Map.put("\u0000", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0001", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0002", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0003", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0004", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0005", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0006", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0007", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0008", StringUtils.EMPTY);
+        escapeXml10Map.put("\u000b", StringUtils.EMPTY);
+        escapeXml10Map.put("\u000c", StringUtils.EMPTY);
+        escapeXml10Map.put("\u000e", StringUtils.EMPTY);
+        escapeXml10Map.put("\u000f", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0010", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0011", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0012", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0013", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0014", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0015", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0016", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0017", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0018", StringUtils.EMPTY);
+        escapeXml10Map.put("\u0019", StringUtils.EMPTY);
+        escapeXml10Map.put("\u001a", StringUtils.EMPTY);
+        escapeXml10Map.put("\u001b", StringUtils.EMPTY);
+        escapeXml10Map.put("\u001c", StringUtils.EMPTY);
+        escapeXml10Map.put("\u001d", StringUtils.EMPTY);
+        escapeXml10Map.put("\u001e", StringUtils.EMPTY);
+        escapeXml10Map.put("\u001f", StringUtils.EMPTY);
+        escapeXml10Map.put("\ufffe", StringUtils.EMPTY);
+        escapeXml10Map.put("\uffff", StringUtils.EMPTY);
+        ESCAPE_XML10 = new AggregateTranslator(
+                new LookupTranslator(EntityArrays.BASIC_ESCAPE),
+                new LookupTranslator(EntityArrays.APOS_ESCAPE),
+                new LookupTranslator(Collections.unmodifiableMap(escapeXml10Map)),
+                NumericEntityEscaper.between(0x7f, 0x84),
+                NumericEntityEscaper.between(0x86, 0x9f),
+                new UnicodeUnpairedSurrogateRemover()
+        );
+    }
+
+    /**
+     * Translator object for escaping XML 1.1.
+     *
+     * While {@link #escapeXml11(String)} is the expected method of use, this
+     * object allows the XML escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_XML11;
+    static {
+        Map<CharSequence, CharSequence> escapeXml11Map = new HashMap<>();
+        escapeXml11Map.put("\u0000", StringUtils.EMPTY);
+        escapeXml11Map.put("\u000b", "&#11;");
+        escapeXml11Map.put("\u000c", "&#12;");
+        escapeXml11Map.put("\ufffe", StringUtils.EMPTY);
+        escapeXml11Map.put("\uffff", StringUtils.EMPTY);
+        ESCAPE_XML11 = new AggregateTranslator(
+                new LookupTranslator(EntityArrays.BASIC_ESCAPE),
+                new LookupTranslator(EntityArrays.APOS_ESCAPE),
+                new LookupTranslator(Collections.unmodifiableMap(escapeXml11Map)),
+                NumericEntityEscaper.between(0x1, 0x8),
+                NumericEntityEscaper.between(0xe, 0x1f),
+                NumericEntityEscaper.between(0x7f, 0x84),
+                NumericEntityEscaper.between(0x86, 0x9f),
+                new UnicodeUnpairedSurrogateRemover()
+        );
+    }
+
+    /**
+     * Translator object for escaping HTML version 3.0.
+     *
+     * While {@link #escapeHtml3(String)} is the expected method of use, this
+     * object allows the HTML escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_HTML3 =
+            new AggregateTranslator(
+                    new LookupTranslator(EntityArrays.BASIC_ESCAPE),
+                    new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE)
+            );
+
+    /**
+     * The improved translator object for escaping HTML version 3.0.
+     * The 'improved' part of this translator is that it checks if the html is already translated.
+     * This check prevents double, triple, or recursive translations.
+     *
+     * While {@link #escapeHtml3Once(String)} is the expected method of use, this
+     * object allows the HTML escaping functionality to be used
+     * as the foundation for a custom translator.
+     *
+     * Note that, multiple lookup tables should be passed to this translator
+     * instead of passing multiple instances of this translator to the
+     * AggregateTranslator. Because, a SingleLookupTranslator only checks the values of the
+     * lookup table passed to that instance while deciding whether a value is
+     * already translated or not.
+     */
+    public static final CharSequenceTranslator ESCAPE_HTML3_ONCE =
+            new SingleLookupTranslator(EntityArrays.BASIC_ESCAPE, EntityArrays.ISO8859_1_ESCAPE);
+
+
+    /**
+     * Translator object for escaping HTML version 4.0.
+     *
+     * While {@link #escapeHtml4(String)} is the expected method of use, this
+     * object allows the HTML escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_HTML4 =
+            new AggregateTranslator(
+                    new LookupTranslator(EntityArrays.BASIC_ESCAPE),
+                    new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE),
+                    new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE)
+            );
+
+    /**
+     * The improved translator object for escaping HTML version 4.0.
+     * The 'improved' part of this translator is that it checks if the html is already translated.
+     * This check prevents double, triple, or recursive translations.
+     *
+     * While {@link #escapeHtml4Once(String)} is the expected method of use, this
+     * object allows the HTML escaping functionality to be used
+     * as the foundation for a custom translator.
+     *
+     * Note that, multiple lookup tables should be passed to this translator
+     * instead of passing multiple instances of this translator to the
+     * AggregateTranslator. Because, a SingleLookupTranslator only checks the values of the
+     * lookup table passed to that instance while deciding whether a value is
+     * already translated or not.
+     */
+    public static final CharSequenceTranslator ESCAPE_HTML4_ONCE =
+            new SingleLookupTranslator(
+                    EntityArrays.BASIC_ESCAPE,
+                    EntityArrays.ISO8859_1_ESCAPE,
+                    EntityArrays.HTML40_EXTENDED_ESCAPE
+            );
+
+    /**
+     * Translator object for escaping individual Comma Separated Values.
+     *
+     * While {@link #escapeCsv(String)} is the expected method of use, this
+     * object allows the CSV escaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator ESCAPE_CSV = new CsvTranslators.CsvEscaper();
+
+    /**
+     * Translator object for escaping Shell command language.
+     *
+     * @see <a href="http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Language</a>
+     */
+    public static final CharSequenceTranslator ESCAPE_XSI;
+    static {
+        Map<CharSequence, CharSequence> escapeXsiMap = new HashMap<>();
+        escapeXsiMap.put("|", "\\|");
+        escapeXsiMap.put("&", "\\&");
+        escapeXsiMap.put(";", "\\;");
+        escapeXsiMap.put("<", "\\<");
+        escapeXsiMap.put(">", "\\>");
+        escapeXsiMap.put("(", "\\(");
+        escapeXsiMap.put(")", "\\)");
+        escapeXsiMap.put("$", "\\$");
+        escapeXsiMap.put("`", "\\`");
+        escapeXsiMap.put("\\", "\\\\");
+        escapeXsiMap.put("\"", "\\\"");
+        escapeXsiMap.put("'", "\\'");
+        escapeXsiMap.put(" ", "\\ ");
+        escapeXsiMap.put("\t", "\\\t");
+        escapeXsiMap.put("\r\n", "");
+        escapeXsiMap.put("\n", "");
+        escapeXsiMap.put("*", "\\*");
+        escapeXsiMap.put("?", "\\?");
+        escapeXsiMap.put("[", "\\[");
+        escapeXsiMap.put("#", "\\#");
+        escapeXsiMap.put("~", "\\~");
+        escapeXsiMap.put("=", "\\=");
+        escapeXsiMap.put("%", "\\%");
+        ESCAPE_XSI = new LookupTranslator(
+                Collections.unmodifiableMap(escapeXsiMap)
+        );
+    }
+
+    /* UNESCAPE TRANSLATORS */
+
+    /**
+     * Translator object for unescaping escaped Java.
+     *
+     * While {@link #unescapeJava(String)} is the expected method of use, this
+     * object allows the Java unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the Java (as per the compiler)?
+    public static final CharSequenceTranslator UNESCAPE_JAVA;
+    static {
+        Map<CharSequence, CharSequence> unescapeJavaMap = new HashMap<>();
+        unescapeJavaMap.put("\\\\", "\\");
+        unescapeJavaMap.put("\\\"", "\"");
+        unescapeJavaMap.put("\\'", "'");
+        unescapeJavaMap.put("\\", "");
+        UNESCAPE_JAVA = new AggregateTranslator(
+                new OctalUnescaper(),     // .between('\1', '\377'),
+                new UnicodeUnescaper(),
+                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE),
+                new LookupTranslator(Collections.unmodifiableMap(unescapeJavaMap))
+        );
+    }
+
+    /**
+     * Translator object for unescaping escaped EcmaScript.
+     *
+     * While {@link #unescapeEcmaScript(String)} is the expected method of use, this
+     * object allows the EcmaScript unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA;
+
+    /**
+     * Translator object for unescaping escaped Json.
+     *
+     * While {@link #unescapeJson(String)} is the expected method of use, this
+     * object allows the Json unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA;
+
+    /**
+     * Translator object for unescaping escaped HTML 3.0.
+     *
+     * While {@link #unescapeHtml3(String)} is the expected method of use, this
+     * object allows the HTML unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_HTML3 =
+            new AggregateTranslator(
+                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
+                    new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
+                    new NumericEntityUnescaper()
+            );
+
+    /**
+     * Translator object for unescaping escaped HTML 4.0.
+     *
+     * While {@link #unescapeHtml4(String)} is the expected method of use, this
+     * object allows the HTML unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_HTML4 =
+            new AggregateTranslator(
+                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
+                    new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
+                    new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE),
+                    new NumericEntityUnescaper()
+            );
+
+    /**
+     * Translator object for unescaping escaped XML.
+     *
+     * While {@link #unescapeXml(String)} is the expected method of use, this
+     * object allows the XML unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_XML =
+            new AggregateTranslator(
+                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
+                    new LookupTranslator(EntityArrays.APOS_UNESCAPE),
+                    new NumericEntityUnescaper()
+            );
+
+    /**
+     * Translator object for unescaping escaped Comma Separated Value entries.
+     *
+     * While {@link #unescapeCsv(String)} is the expected method of use, this
+     * object allows the CSV unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_CSV = new CsvTranslators.CsvUnescaper();
+
+    /**
+     * Translator object for unescaping escaped XSI Value entries.
+     *
+     * While {@link #unescapeXSI(String)}  is the expected method of use, this
+     * object allows the XSI unescaping functionality to be used
+     * as the foundation for a custom translator.
+     */
+    public static final CharSequenceTranslator UNESCAPE_XSI = new XsiUnescaper();
+
+    /**
+     * Translator object for unescaping backslash escaped entries.
+     */
+    static class XsiUnescaper extends CharSequenceTranslator {
+
+        /**
+         * Escaped backslash constant.
+         */
+        private static final char BACKSLASH = '\\';
+
+        @Override
+        public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+
+            if (index != 0) {
+                throw new IllegalStateException("XsiUnescaper should never reach the [1] index");
+            }
+
+            String s = input.toString();
+
+            int segmentStart = 0;
+            int searchOffset = 0;
+            while (true) {
+                int pos = s.indexOf(BACKSLASH, searchOffset);
+                if (pos == -1) {
+                    if (segmentStart < s.length()) {
+                        out.write(s.substring(segmentStart));
+                    }
+                    break;
+                }
+                if (pos > segmentStart) {
+                    out.write(s.substring(segmentStart, pos));
+                }
+                segmentStart = pos + 1;
+                searchOffset = pos + 2;
+            }
+
+            return Character.codePointCount(input, 0, input.length());
+        }
+    }
+
+    /* Helper functions */
+
+    /**
+     * <p>{@code StringEscapeUtils} instances should NOT be constructed in
+     * standard programming.</p>
+     *
+     * <p>Instead, the class should be used as:</p>
+     * <pre>StringEscapeUtils.escapeJava("foo");</pre>
+     *
+     * <p>This constructor is public to permit tools that require a JavaBean
+     * instance to operate.</p>
+     */
+    public StringEscapeUtils() {
+        super();
+    }
+
+    /**
+     * <p>Convenience wrapper for {@link java.lang.StringBuilder} providing escape methods.</p>
+     *
+     * <p>Example:</p>
+     * <pre>
+     * new Builder(ESCAPE_HTML4)
+     *      .append("&lt;p&gt;")
+     *      .escape("This is paragraph 1 and special chars like &amp; get escaped.")
+     *      .append("&lt;/p&gt;&lt;p&gt;")
+     *      .escape("This is paragraph 2 &amp; more...")
+     *      .append("&lt;/p&gt;")
+     *      .toString()
+     * </pre>
+     *
+     */
+    public static final class Builder {
+
+        /**
+         * StringBuilder to be used in the Builder class.
+         */
+        private final StringBuilder sb;
+
+        /**
+         * CharSequenceTranslator to be used in the Builder class.
+         */
+        private final CharSequenceTranslator translator;
+
+        /**
+         * Builder constructor.
+         *
+         * @param translator a CharSequenceTranslator.
+         */
+        private Builder(final CharSequenceTranslator translator) {
+            this.sb = new StringBuilder();
+            this.translator = translator;
+        }
+
+        /**
+         * <p>Escape {@code input} according to the given {@link CharSequenceTranslator}.</p>
+         *
+         * @param input the String to escape
+         * @return {@code this}, to enable chaining
+         */
+        public Builder escape(final String input) {
+            sb.append(translator.translate(input));
+            return this;
+        }
+
+        /**
+         * Literal append, no escaping being done.
+         *
+         * @param input the String to append
+         * @return {@code this}, to enable chaining
+         */
+        public Builder append(final String input) {
+            sb.append(input);
+            return this;
+        }
+
+        /**
+         * <p>Return the escaped string.</p>
+         *
+         * @return the escaped string
+         */
+        @Override
+        public String toString() {
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Get a {@link Builder}.
+     * @param translator the text translator
+     * @return {@link Builder}
+     */
+    public static StringEscapeUtils.Builder builder(final CharSequenceTranslator translator) {
+        return new Builder(translator);
+    }
+
+    // Java and JavaScript
+    //--------------------------------------------------------------------------
+    /**
+     * <p>Escapes the characters in a {@code String} using Java String rules.</p>
+     *
+     * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
+     *
+     * <p>So a tab becomes the characters {@code '\\'} and
+     * {@code 't'}.</p>
+     *
+     * <p>The only difference between Java strings and JavaScript strings
+     * is that in JavaScript, a single quote and forward-slash (/) are escaped.</p>
+     *
+     * <p>Example:</p>
+     * <pre>
+     * input string: He didn't say, "Stop!"
+     * output string: He didn't say, \"Stop!\"
+     * </pre>
+     *
+     * @param input  String to escape values in, may be null
+     * @return String with escaped values, {@code null} if null string input
+     */
+    public static final String escapeJava(final String input) {
+        return ESCAPE_JAVA.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using EcmaScript String rules.</p>
+     * <p>Escapes any values it finds into their EcmaScript String form.
+     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
+     *
+     * <p>So a tab becomes the characters {@code '\\'} and
+     * {@code 't'}.</p>
+     *
+     * <p>The only difference between Java strings and EcmaScript strings
+     * is that in EcmaScript, a single quote and forward-slash (/) are escaped.</p>
+     *
+     * <p>Note that EcmaScript is best known by the JavaScript and ActionScript dialects. </p>
+     *
+     * <p>Example:</p>
+     * <pre>
+     * input string: He didn't say, "Stop!"
+     * output string: He didn\'t say, \"Stop!\"
+     * </pre>
+     *
+     * <b>Security Note.</b> We only provide backslash escaping in this method. For example, {@code '\"'} has the output
+     * {@code '\\\"'} which could result in potential issues in the case where the string being escaped is being used
+     * in an HTML tag like {@code <select onmouseover="..." />}. If you wish to have more rigorous string escaping, you
+     * may consider the
+     * <a href="https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API_JAVA">ESAPI Libraries</a>.
+     * Further, you can view the <a href="https://github.com/esapi">ESAPI GitHub Org</a>.
+     *
+     * @param input  String to escape values in, may be null
+     * @return String with escaped values, {@code null} if null string input
+     */
+    public static final String escapeEcmaScript(final String input) {
+        return ESCAPE_ECMASCRIPT.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using Json String rules.</p>
+     * <p>Escapes any values it finds into their Json String form.
+     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
+     *
+     * <p>So a tab becomes the characters {@code '\\'} and
+     * {@code 't'}.</p>
+     *
+     * <p>The only difference between Java strings and Json strings
+     * is that in Json, forward-slash (/) is escaped.</p>
+     *
+     * <p>See http://www.ietf.org/rfc/rfc4627.txt for further details. </p>
+     *
+     * <p>Example:</p>
+     * <pre>
+     * input string: He didn't say, "Stop!"
+     * output string: He didn't say, \"Stop!\"
+     * </pre>
+     *
+     * @param input  String to escape values in, may be null
+     * @return String with escaped values, {@code null} if null string input
+     */
+    public static final String escapeJson(final String input) {
+        return ESCAPE_JSON.translate(input);
+    }
+
+    /**
+     * <p>Unescapes any Java literals found in the {@code String}.
+     * For example, it will turn a sequence of {@code '\'} and
+     * {@code 'n'} into a newline character, unless the {@code '\'}
+     * is preceded by another {@code '\'}.</p>
+     *
+     * @param input  the {@code String} to unescape, may be null
+     * @return a new unescaped {@code String}, {@code null} if null string input
+     */
+    public static final String unescapeJava(final String input) {
+        return UNESCAPE_JAVA.translate(input);
+    }
+
+    /**
+     * <p>Unescapes any EcmaScript literals found in the {@code String}.</p>
+     *
+     * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
+     * into a newline character, unless the {@code '\'} is preceded by another
+     * {@code '\'}.</p>
+     *
+     * @see #unescapeJava(String)
+     * @param input  the {@code String} to unescape, may be null
+     * @return A new unescaped {@code String}, {@code null} if null string input
+     */
+    public static final String unescapeEcmaScript(final String input) {
+        return UNESCAPE_ECMASCRIPT.translate(input);
+    }
+
+    /**
+     * <p>Unescapes any Json literals found in the {@code String}.</p>
+     *
+     * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
+     * into a newline character, unless the {@code '\'} is preceded by another
+     * {@code '\'}.</p>
+     *
+     * @see #unescapeJava(String)
+     * @param input  the {@code String} to unescape, may be null
+     * @return A new unescaped {@code String}, {@code null} if null string input
+     */
+    public static final String unescapeJson(final String input) {
+        return UNESCAPE_JSON.translate(input);
+    }
+
+    // HTML and XML
+    //--------------------------------------------------------------------------
+    /**
+     * <p>Escapes the characters in a {@code String} using HTML entities.</p>
+     *
+     * <p>
+     * For example:
+     * </p>
+     * <p><code>"bread" &amp; "butter"</code></p>
+     * becomes:
+     * <p>
+     * <code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code>.
+     * </p>
+     *
+     * <p>Supports all known HTML 4.0 entities, including funky accents.
+     * Note that the commonly used apostrophe escape character (&amp;apos;)
+     * is not a legal entity and so is not supported). </p>
+     *
+     * @param input  the {@code String} to escape, may be null
+     * @return a new escaped {@code String}, {@code null} if null string input
+     *
+     * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
+     * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
+     * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
+     * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
+     * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
+     */
+    public static final String escapeHtml4(final String input) {
+        return ESCAPE_HTML4.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using HTML entities.
+     * But escapes them only once. i.e. does not escape already escaped characters.</p>
+     *
+     * <p>
+     * For example:
+     * </p>
+     * <p><code>"bread" &amp; "butter"</code></p>
+     * becomes:
+     * <p>
+     * <code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code>.
+     * </p>
+     *
+     * <p>
+     * But:
+     * </p>
+     * <p><code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code></p>
+     * remains unaffected.
+     *
+     * <p>Supports all known HTML 4.0 entities, including funky accents.
+     * Note that the commonly used apostrophe escape character (&amp;apos;)
+     * is not a legal entity and so is not supported). </p>
+     *
+     * @param input  the {@code String} to escape, may be null
+     * @return a new escaped {@code String}, {@code null} if null string input
+     *
+     * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
+     * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
+     * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
+     * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
+     * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
+     */
+    public static final String escapeHtml4Once(final String input) {
+        return ESCAPE_HTML4_ONCE.translate(input);
+    }
+
+
+    /**
+     * <p>Escapes the characters in a {@code String} using HTML entities.</p>
+     * <p>Supports only the HTML 3.0 entities. </p>
+     *
+     * @param input  the {@code String} to escape, may be null
+     * @return a new escaped {@code String}, {@code null} if null string input
+     */
+    public static final String escapeHtml3(final String input) {
+        return ESCAPE_HTML3.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using HTML entities.
+     * But escapes them only once. i.e. does not escape already escaped characters.</p>
+     * <p>Supports only the HTML 3.0 entities. </p>
+     *
+     * @param input  the {@code String} to escape, may be null
+     * @return a new escaped {@code String}, {@code null} if null string input
+     */
+    public static final String escapeHtml3Once(final String input) {
+        return ESCAPE_HTML3_ONCE.translate(input);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Unescapes a string containing entity escapes to a string
+     * containing the actual Unicode characters corresponding to the
+     * escapes. Supports HTML 4.0 entities.</p>
+     *
+     * <p>For example, the string {@code "&lt;Fran&ccedil;ais&gt;"}
+     * will become {@code "<Fran\ufffdais>"}</p>
+     *
+     * <p>If an entity is unrecognized, it is left alone, and inserted
+     * verbatim into the result string. e.g. {@code "&gt;&zzzz;x"} will
+     * become {@code ">&zzzz;x"}.</p>
+     *
+     * @param input  the {@code String} to unescape, may be null
+     * @return a new unescaped {@code String}, {@code null} if null string input
+     */
+    public static final String unescapeHtml4(final String input) {
+        return UNESCAPE_HTML4.translate(input);
+    }
+
+    /**
+     * <p>Unescapes a string containing entity escapes to a string
+     * containing the actual Unicode characters corresponding to the
+     * escapes. Supports only HTML 3.0 entities.</p>
+     *
+     * @param input  the {@code String} to unescape, may be null
+     * @return a new unescaped {@code String}, {@code null} if null string input
+     */
+    public static final String unescapeHtml3(final String input) {
+        return UNESCAPE_HTML3.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using XML entities.</p>
+     *
+     * <p>For example: {@code "bread" & "butter"} =&gt;
+     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
+     * </p>
+     *
+     * <p>Note that XML 1.0 is a text-only format: it cannot represent control
+     * characters or unpaired Unicode surrogate codepoints, even after escaping.
+     * {@code escapeXml10} will remove characters that do not fit in the
+     * following ranges:</p>
+     *
+     * <p>{@code #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}</p>
+     *
+     * <p>Though not strictly necessary, {@code escapeXml10} will escape
+     * characters in the following ranges:</p>
+     *
+     * <p>{@code [#x7F-#x84] | [#x86-#x9F]}</p>
+     *
+     * <p>The returned string can be inserted into a valid XML 1.0 or XML 1.1
+     * document. If you want to allow more non-text characters in an XML 1.1
+     * document, use {@link #escapeXml11(String)}.</p>
+     *
+     * @param input  the {@code String} to escape, may be null
+     * @return a new escaped {@code String}, {@code null} if null string input
+     * @see #unescapeXml(java.lang.String)
+     */
+    public static String escapeXml10(final String input) {
+        return ESCAPE_XML10.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using XML entities.</p>
+     *
+     * <p>For example: {@code "bread" & "butter"} =&gt;
+     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
+     * </p>
+     *
+     * <p>XML 1.1 can represent certain control characters, but it cannot represent
+     * the null byte or unpaired Unicode surrogate codepoints, even after escaping.
+     * {@code escapeXml11} will remove characters that do not fit in the following
+     * ranges:</p>
+     *
+     * <p>{@code [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}</p>
+     *
+     * <p>{@code escapeXml11} will escape characters in the following ranges:</p>
+     *
+     * <p>{@code [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]}</p>
+     *
+     * <p>The returned string can be inserted into a valid XML 1.1 document. Do not
+     * use it for XML 1.0 documents.</p>
+     *
+     * @param input  the {@code String} to escape, may be null
+     * @return a new escaped {@code String}, {@code null} if null string input
+     * @see #unescapeXml(java.lang.String)
+     */
+    public static String escapeXml11(final String input) {
+        return ESCAPE_XML11.translate(input);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * <p>Unescapes a string containing XML entity escapes to a string
+     * containing the actual Unicode characters corresponding to the
+     * escapes.</p>
+     *
+     * <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
+     * Does not support DTDs or external entities.</p>
+     *
+     * <p>Note that numerical \\u Unicode codes are unescaped to their respective
+     *    Unicode characters. This may change in future releases. </p>
+     *
+     * @param input  the {@code String} to unescape, may be null
+     * @return a new unescaped {@code String}, {@code null} if null string input
+     * @see #escapeXml10(String)
+     * @see #escapeXml11(String)
+     */
+    public static final String unescapeXml(final String input) {
+        return UNESCAPE_XML.translate(input);
+    }
+
+    //-----------------------------------------------------------------------
+
+    /**
+     * <p>Returns a {@code String} value for a CSV column enclosed in double quotes,
+     * if required.</p>
+     *
+     * <p>If the value contains a comma, newline or double quote, then the
+     *    String value is returned enclosed in double quotes.</p>
+     *
+     * <p>Any double quote characters in the value are escaped with another double quote.</p>
+     *
+     * <p>If the value does not contain a comma, newline or double quote, then the
+     *    String value is returned unchanged.</p>
+     *
+     * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
+     * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
+     *
+     * @param input the input CSV column String, may be null
+     * @return the input String, enclosed in double quotes if the value contains a comma,
+     * newline or double quote, {@code null} if null string input
+     */
+    public static final String escapeCsv(final String input) {
+        return ESCAPE_CSV.translate(input);
+    }
+
+    /**
+     * <p>Returns a {@code String} value for an unescaped CSV column. </p>
+     *
+     * <p>If the value is enclosed in double quotes, and contains a comma, newline
+     *    or double quote, then quotes are removed.
+     * </p>
+     *
+     * <p>Any double quote escaped characters (a pair of double quotes) are unescaped
+     *    to just one double quote. </p>
+     *
+     * <p>If the value is not enclosed in double quotes, or is and does not contain a
+     *    comma, newline or double quote, then the String value is returned unchanged.</p>
+     *
+     * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
+     * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
+     *
+     * @param input the input CSV column String, may be null
+     * @return the input String, with enclosing double quotes removed and embedded double
+     * quotes unescaped, {@code null} if null string input
+     */
+    public static final String unescapeCsv(final String input) {
+        return UNESCAPE_CSV.translate(input);
+    }
+
+    /**
+     * <p>Escapes the characters in a {@code String} using XSI rules.</p>
+     *
+     * <p><b>Beware!</b> In most cases you don't want to escape shell commands but use multi-argument
+     * methods provided by {@link java.lang.ProcessBuilder} or {@link java.lang.Runtime#exec(String[])}
+     * instead.</p>
+     *
+     * <p>Example:</p>
+     * <pre>
+     * input string: He didn't say, "Stop!"
+     * output string: He\ didn\'t\ say,\ \"Stop!\"
+     * </pre>
+     *
+     * @see <a href="http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Language</a>
+     * @param input  String to escape values in, may be null
+     * @return String with escaped values, {@code null} if null string input
+     */
+    public static final String escapeXSI(final String input) {
+        return ESCAPE_XSI.translate(input);
+    }
+
+    /**
+     * <p>Unescapes the characters in a {@code String} using XSI rules.</p>
+     *
+     * @see StringEscapeUtils#escapeXSI(String)
+     * @param input  the {@code String} to unescape, may be null
+     * @return a new unescaped {@code String}, {@code null} if null string input
+     */
+    public static final String unescapeXSI(final String input) {
+        return UNESCAPE_XSI.translate(input);
+    }
+
+}


[37/50] [abbrv] [text] TEXT-65: created TEXT-67 removing TODO

Posted by ch...@apache.org.
TEXT-65: created TEXT-67 removing TODO


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/5842b23a
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/5842b23a
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/5842b23a

Branch: refs/heads/release
Commit: 5842b23a7231c9707f1373e80850959b2033f139
Parents: b2b4c21
Author: Rob Tompkins <ch...@apache.org>
Authored: Fri Feb 17 08:28:33 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Fri Feb 17 08:28:33 2017 -0500

----------------------------------------------------------------------
 .../org/apache/commons/text/translate/NumericEntityUnescaper.java   | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/5842b23a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
index 6060cf8..e8f59c6 100644
--- a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
@@ -35,7 +35,6 @@ public class NumericEntityUnescaper extends CharSequenceTranslator {
     public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
 
     /** EnumSet of OPTIONS, given from the constructor. */
-    // TODO: Create an OptionsSet class to hide some of the conditional logic below
     private final EnumSet<OPTION> options;
 
     /**


[10/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StrBuilderAppendInsertTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StrBuilderAppendInsertTest.java b/src/test/java/org/apache/commons/text/beta/StrBuilderAppendInsertTest.java
deleted file mode 100644
index 2c5900d..0000000
--- a/src/test/java/org/apache/commons/text/beta/StrBuilderAppendInsertTest.java
+++ /dev/null
@@ -1,1605 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-import java.text.DecimalFormatSymbols;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-
-/**
- * Unit tests for {@link StrBuilder}.
- */
-public class StrBuilderAppendInsertTest {
-
-    /** The system line separator. */
-    private static final String SEP = System.lineSeparator();
-
-    /** Test subclass of Object, with a toString method. */
-    private static final Object FOO = new Object() {
-        @Override
-        public String toString() {
-            return "foo";
-        }
-    };
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendNewLine() {
-        StrBuilder sb = new StrBuilder("---");
-        sb.appendNewLine().append("+++");
-        assertEquals("---" + SEP + "+++", sb.toString());
-        
-        sb = new StrBuilder("---");
-        sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine();
-        assertEquals("---#" + SEP, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendWithNullText() {
-        final StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL");
-        assertEquals("", sb.toString());
-
-        sb.appendNull();
-        assertEquals("NULL", sb.toString());
-
-        sb.append((Object) null);
-        assertEquals("NULLNULL", sb.toString());
-
-        sb.append(FOO);
-        assertEquals("NULLNULLfoo", sb.toString());
-
-        sb.append((String) null);
-        assertEquals("NULLNULLfooNULL", sb.toString());
-
-        sb.append("");
-        assertEquals("NULLNULLfooNULL", sb.toString());
-
-        sb.append("bar");
-        assertEquals("NULLNULLfooNULLbar", sb.toString());
-
-        sb.append((StringBuffer) null);
-        assertEquals("NULLNULLfooNULLbarNULL", sb.toString());
-
-        sb.append(new StringBuffer("baz"));
-        assertEquals("NULLNULLfooNULLbarNULLbaz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_Object() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendNull();
-        assertEquals("", sb.toString());
-
-        sb.append((Object) null);
-        assertEquals("", sb.toString());
-
-        sb.append(FOO);
-        assertEquals("foo", sb.toString());
-
-        sb.append((StringBuffer) null);
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuffer("baz"));
-        assertEquals("foobaz", sb.toString());
-
-        sb.append(new StrBuilder("yes"));
-        assertEquals("foobazyes", sb.toString());
-
-        sb.append((CharSequence) "Seq");
-        assertEquals("foobazyesSeq", sb.toString());
-
-        sb.append(new StringBuilder("bld")); // Check it supports StringBuilder
-        assertEquals("foobazyesSeqbld", sb.toString());
-    }
-    
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_StringBuilder() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new StringBuilder("foo"));
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuilder(""));
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuilder("bar"));
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_String() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append("foo");
-        assertEquals("foo", sb.toString());
-
-        sb.append("");
-        assertEquals("foo", sb.toString());
-
-        sb.append("bar");
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_String_int_int() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null, 0, 1);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append("foo", 0, 3);
-        assertEquals("foo", sb.toString());
-
-        try {
-            sb.append("bar", -1, 1);
-            fail("append(char[], -1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append("bar", 3, 1);
-            fail("append(char[], 3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append("bar", 1, -1);
-            fail("append(char[],, -1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append("bar", 1, 3);
-            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append("bar", -1, 3);
-            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append("bar", 4, 0);
-            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.append("bar", 3, 0);
-        assertEquals("foo", sb.toString());
-
-        sb.append("abcbardef", 3, 3);
-        assertEquals("foobar", sb.toString());
-
-        sb.append( (CharSequence)"abcbardef", 4, 3);
-        assertEquals("foobarard", sb.toString());
-    }
-    
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_StringBuilder_int_int() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((String) null, 0, 1);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new StringBuilder("foo"), 0, 3);
-        assertEquals("foo", sb.toString());
-
-        try {
-            sb.append(new StringBuilder("bar"), -1, 1);
-            fail("append(StringBuilder, -1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuilder("bar"), 3, 1);
-            fail("append(StringBuilder, 3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuilder("bar"), 1, -1);
-            fail("append(StringBuilder,, -1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuilder("bar"), 1, 3);
-            fail("append(StringBuilder, 1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuilder("bar"), -1, 3);
-            fail("append(StringBuilder, -1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuilder("bar"), 4, 0);
-            fail("append(StringBuilder, 4, 0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.append(new StringBuilder("bar"), 3, 0);
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuilder("abcbardef"), 3, 3);
-        assertEquals("foobar", sb.toString());
-
-        sb.append( new StringBuilder("abcbardef"), 4, 3);
-        assertEquals("foobarard", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_StringBuffer() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((StringBuffer) null);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new StringBuffer("foo"));
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuffer(""));
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuffer("bar"));
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_StringBuffer_int_int() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((StringBuffer) null, 0, 1);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new StringBuffer("foo"), 0, 3);
-        assertEquals("foo", sb.toString());
-
-        try {
-            sb.append(new StringBuffer("bar"), -1, 1);
-            fail("append(char[], -1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuffer("bar"), 3, 1);
-            fail("append(char[], 3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuffer("bar"), 1, -1);
-            fail("append(char[],, -1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuffer("bar"), 1, 3);
-            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuffer("bar"), -1, 3);
-            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StringBuffer("bar"), 4, 0);
-            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.append(new StringBuffer("bar"), 3, 0);
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StringBuffer("abcbardef"), 3, 3);
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_StrBuilder() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((StrBuilder) null);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new StrBuilder("foo"));
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StrBuilder(""));
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StrBuilder("bar"));
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_StrBuilder_int_int() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((StrBuilder) null, 0, 1);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new StrBuilder("foo"), 0, 3);
-        assertEquals("foo", sb.toString());
-
-        try {
-            sb.append(new StrBuilder("bar"), -1, 1);
-            fail("append(char[], -1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StrBuilder("bar"), 3, 1);
-            fail("append(char[], 3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StrBuilder("bar"), 1, -1);
-            fail("append(char[],, -1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StrBuilder("bar"), 1, 3);
-            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StrBuilder("bar"), -1, 3);
-            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new StrBuilder("bar"), 4, 0);
-            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.append(new StrBuilder("bar"), 3, 0);
-        assertEquals("foo", sb.toString());
-
-        sb.append(new StrBuilder("abcbardef"), 3, 3);
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_CharArray() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((char[]) null);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new char[0]);
-        assertEquals("", sb.toString());
-
-        sb.append(new char[]{'f', 'o', 'o'});
-        assertEquals("foo", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_CharArray_int_int() {
-        StrBuilder sb = new StrBuilder();
-        sb.setNullText("NULL").append((char[]) null, 0, 1);
-        assertEquals("NULL", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append(new char[]{'f', 'o', 'o'}, 0, 3);
-        assertEquals("foo", sb.toString());
-
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, -1, 1);
-            fail("append(char[], -1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 3, 1);
-            fail("append(char[], 3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 1, -1);
-            fail("append(char[],, -1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 1, 3);
-            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, -1, 3);
-            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.append(new char[]{'b', 'a', 'r'}, 4, 0);
-            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.append(new char[]{'b', 'a', 'r'}, 3, 0);
-        assertEquals("foo", sb.toString());
-
-        sb.append(new char[]{'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 3);
-        assertEquals("foobar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_Boolean() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append(true);
-        assertEquals("true", sb.toString());
-
-        sb.append(false);
-        assertEquals("truefalse", sb.toString());
-
-        sb.append('!');
-        assertEquals("truefalse!", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_PrimitiveNumber() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append(0);
-        assertEquals("0", sb.toString());
-
-        sb.append(1L);
-        assertEquals("01", sb.toString());
-
-        sb.append(2.3f);
-        assertEquals("012.3", sb.toString());
-
-        sb.append(4.5d);
-        assertEquals("012.34.5", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_FormattedString() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final String str) {
-                count[0]++;
-                return super.append(str);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln("Hello %s", "Alice");
-        assertEquals("Hello Alice" + SEP, sb.toString());
-        assertEquals(2, count[0]);  // appendNewLine() calls append(String)
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_Object() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendln((Object) null);
-        assertEquals("" + SEP, sb.toString());
-
-        sb.appendln(FOO);
-        assertEquals(SEP + "foo" + SEP, sb.toString());
-
-        sb.appendln(Integer.valueOf(6));
-        assertEquals(SEP + "foo" + SEP + "6" + SEP, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_String() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final String str) {
-                count[0]++;
-                return super.append(str);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln("foo");
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(2, count[0]);  // appendNewLine() calls append(String)
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_String_int_int() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final String str, final int startIndex, final int length) {
-                count[0]++;
-                return super.append(str, startIndex, length);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln("foo", 0, 3);
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_StringBuffer() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final StringBuffer str) {
-                count[0]++;
-                return super.append(str);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln(new StringBuffer("foo"));
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_StringBuilder() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final StringBuilder str) {
-                count[0]++;
-                return super.append(str);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln(new StringBuilder("foo"));
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_StringBuffer_int_int() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
-                count[0]++;
-                return super.append(str, startIndex, length);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln(new StringBuffer("foo"), 0, 3);
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_StringBuilder_int_int() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
-                count[0]++;
-                return super.append(str, startIndex, length);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln(new StringBuilder("foo"), 0, 3);
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_StrBuilder() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final StrBuilder str) {
-                count[0]++;
-                return super.append(str);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln(new StrBuilder("foo"));
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_StrBuilder_int_int() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
-                count[0]++;
-                return super.append(str, startIndex, length);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln(new StrBuilder("foo"), 0, 3);
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_CharArray() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final char[] str) {
-                count[0]++;
-                return super.append(str);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln("foo".toCharArray());
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_CharArray_int_int() {
-        final int[] count = new int[2];
-        final StrBuilder sb = new StrBuilder() {
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public StrBuilder append(final char[] str, final int startIndex, final int length) {
-                count[0]++;
-                return super.append(str, startIndex, length);
-            }
-            @Override
-            public StrBuilder appendNewLine() {
-                count[1]++;
-                return super.appendNewLine();
-            }
-        };
-        sb.appendln("foo".toCharArray(), 0, 3);
-        assertEquals("foo" + SEP, sb.toString());
-        assertEquals(1, count[0]);
-        assertEquals(1, count[1]);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_Boolean() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendln(true);
-        assertEquals("true" + SEP, sb.toString());
-        
-        sb.clear();
-        sb.appendln(false);
-        assertEquals("false" + SEP, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendln_PrimitiveNumber() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendln(0);
-        assertEquals("0" + SEP, sb.toString());
-        
-        sb.clear();
-        sb.appendln(1L);
-        assertEquals("1" + SEP, sb.toString());
-        
-        sb.clear();
-        sb.appendln(2.3f);
-        assertEquals("2.3" + SEP, sb.toString());
-        
-        sb.clear();
-        sb.appendln(4.5d);
-        assertEquals("4.5" + SEP, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendPadding() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append("foo");
-        assertEquals("foo", sb.toString());
-
-        sb.appendPadding(-1, '-');
-        assertEquals("foo", sb.toString());
-
-        sb.appendPadding(0, '-');
-        assertEquals("foo", sb.toString());
-
-        sb.appendPadding(1, '-');
-        assertEquals("foo-", sb.toString());
-
-        sb.appendPadding(16, '-');
-        assertEquals(20, sb.length());
-        //            12345678901234567890
-        assertEquals("foo-----------------", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadLeft() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadLeft("foo", -1, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 0, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 1, '-');
-        assertEquals("o", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 2, '-');
-        assertEquals("oo", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 3, '-');
-        assertEquals("foo", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 4, '-');
-        assertEquals("-foo", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft("foo", 10, '-');
-        assertEquals(10, sb.length());
-        //            1234567890
-        assertEquals("-------foo", sb.toString());
-
-        sb.clear();
-        sb.setNullText("null");
-        sb.appendFixedWidthPadLeft(null, 5, '-');
-        assertEquals("-null", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadLeft_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadLeft(123, -1, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 0, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 1, '-');
-        assertEquals("3", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 2, '-');
-        assertEquals("23", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 3, '-');
-        assertEquals("123", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 4, '-');
-        assertEquals("-123", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadLeft(123, 10, '-');
-        assertEquals(10, sb.length());
-        //            1234567890
-        assertEquals("-------123", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadRight() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadRight("foo", -1, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 0, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 1, '-');
-        assertEquals("f", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 2, '-');
-        assertEquals("fo", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 3, '-');
-        assertEquals("foo", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 4, '-');
-        assertEquals("foo-", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight("foo", 10, '-');
-        assertEquals(10, sb.length());
-        //            1234567890
-        assertEquals("foo-------", sb.toString());
-
-        sb.clear();
-        sb.setNullText("null");
-        sb.appendFixedWidthPadRight(null, 5, '-');
-        assertEquals("null-", sb.toString());
-    }
-
-    // See: http://issues.apache.org/jira/browse/LANG-299
-    @Test
-    public void testLang299() {
-        final StrBuilder sb = new StrBuilder(1);
-        sb.appendFixedWidthPadRight("foo", 1, '-');
-        assertEquals("f", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendFixedWidthPadRight_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadRight(123, -1, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 0, '-');
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 1, '-');
-        assertEquals("1", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 2, '-');
-        assertEquals("12", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 3, '-');
-        assertEquals("123", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 4, '-');
-        assertEquals("123-", sb.toString());
-
-        sb.clear();
-        sb.appendFixedWidthPadRight(123, 10, '-');
-        assertEquals(10, sb.length());
-        //            1234567890
-        assertEquals("123-------", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppend_FormattedString() {
-        StrBuilder sb;
-
-        sb = new StrBuilder();
-        sb.append("Hi", (Object[]) null);
-        assertEquals("Hi", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append("Hi", "Alice");
-        assertEquals("Hi", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append("Hi %s", "Alice");
-        assertEquals("Hi Alice", sb.toString());
-
-        sb = new StrBuilder();
-        sb.append("Hi %s %,d", "Alice", 5000);
-        // group separator depends on system locale
-        final char groupingSeparator = DecimalFormatSymbols.getInstance().getGroupingSeparator();
-        final String expected = "Hi Alice 5" + groupingSeparator + "000";
-        assertEquals(expected, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendAll_Array() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendAll((Object[]) null);
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendAll(new Object[0]);
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendAll(new Object[]{"foo", "bar", "baz"});
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.appendAll("foo", "bar", "baz");
-        assertEquals("foobarbaz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendAll_Collection() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendAll((Collection<?>) null);
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendAll(Collections.EMPTY_LIST);
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}));
-        assertEquals("foobarbaz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendAll_Iterator() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendAll((Iterator<?>) null);
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendAll(Collections.EMPTY_LIST.iterator());
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator());
-        assertEquals("foobarbaz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendWithSeparators_Array() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendWithSeparators((Object[]) null, ",");
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(new Object[0], ",");
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, ",");
-        assertEquals("foo,bar,baz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, null);
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
-        assertEquals("foo,,baz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendWithSeparators_Collection() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendWithSeparators((Collection<?>) null, ",");
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Collections.EMPTY_LIST, ",");
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}), ",");
-        assertEquals("foo,bar,baz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}), null);
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}), ",");
-        assertEquals("foo,,baz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendWithSeparators_Iterator() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendWithSeparators((Iterator<?>) null, ",");
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Collections.EMPTY_LIST.iterator(), ",");
-        assertEquals("", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator(), ",");
-        assertEquals("foo,bar,baz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator(), null);
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}).iterator(), ",");
-        assertEquals("foo,,baz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendWithSeparatorsWithNullText() {
-        final StrBuilder sb = new StrBuilder();
-        sb.setNullText("null");
-        sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
-        assertEquals("foo,null,baz", sb.toString());
-
-        sb.clear();
-        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}), ",");
-        assertEquals("foo,null,baz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_String() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(",");  // no effect
-        assertEquals("", sb.toString());
-        sb.append("foo");
-        assertEquals("foo", sb.toString());
-        sb.appendSeparator(",");
-        assertEquals("foo,", sb.toString());
-    }
-    
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_String_String() {
-        final StrBuilder sb = new StrBuilder();
-        final String startSeparator = "order by ";
-        final String standardSeparator = ",";
-        final String foo = "foo";
-        sb.appendSeparator(null, null);
-        assertEquals("", sb.toString());
-        sb.appendSeparator(standardSeparator, null);
-        assertEquals("", sb.toString());
-        sb.appendSeparator(standardSeparator, startSeparator); 
-        assertEquals(startSeparator, sb.toString());
-        sb.appendSeparator(null, null); 
-        assertEquals(startSeparator, sb.toString());
-        sb.appendSeparator(null, startSeparator); 
-        assertEquals(startSeparator, sb.toString());
-        sb.append(foo);
-        assertEquals(startSeparator + foo, sb.toString());
-        sb.appendSeparator(standardSeparator, startSeparator);
-        assertEquals(startSeparator + foo + standardSeparator, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_char() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(',');  // no effect
-        assertEquals("", sb.toString());
-        sb.append("foo");
-        assertEquals("foo", sb.toString());
-        sb.appendSeparator(',');
-        assertEquals("foo,", sb.toString());
-    }
-    @Test
-    public void testAppendSeparator_char_char() {
-        final StrBuilder sb = new StrBuilder();
-        final char startSeparator = ':';
-        final char standardSeparator = ',';
-        final String foo = "foo";
-        sb.appendSeparator(standardSeparator, startSeparator);  // no effect
-        assertEquals(String.valueOf(startSeparator), sb.toString());
-        sb.append(foo);
-        assertEquals(String.valueOf(startSeparator) + foo, sb.toString());
-        sb.appendSeparator(standardSeparator, startSeparator);
-        assertEquals(String.valueOf(startSeparator) + foo + standardSeparator, sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_String_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(",", 0);  // no effect
-        assertEquals("", sb.toString());
-        sb.append("foo");
-        assertEquals("foo", sb.toString());
-        sb.appendSeparator(",", 1);
-        assertEquals("foo,", sb.toString());
-        
-        sb.appendSeparator(",", -1);  // no effect
-        assertEquals("foo,", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendSeparator_char_int() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendSeparator(',', 0);  // no effect
-        assertEquals("", sb.toString());
-        sb.append("foo");
-        assertEquals("foo", sb.toString());
-        sb.appendSeparator(',', 1);
-        assertEquals("foo,", sb.toString());
-        
-        sb.appendSeparator(',', -1);  // no effect
-        assertEquals("foo,", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testInsert() {
-
-        final StrBuilder sb = new StrBuilder();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, FOO);
-            fail("insert(-1, Object) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, FOO);
-            fail("insert(7, Object) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, (Object) null);
-        assertEquals("barbaz", sb.toString());
-
-        sb.insert(0, FOO);
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, "foo");
-            fail("insert(-1, String) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, "foo");
-            fail("insert(7, String) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, (String) null);
-        assertEquals("barbaz", sb.toString());
-
-        sb.insert(0, "foo");
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, new char[]{'f', 'o', 'o'});
-            fail("insert(-1, char[]) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, new char[]{'f', 'o', 'o'});
-            fail("insert(7, char[]) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, (char[]) null);
-        assertEquals("barbaz", sb.toString());
-
-        sb.insert(0, new char[0]);
-        assertEquals("barbaz", sb.toString());
-
-        sb.insert(0, new char[]{'f', 'o', 'o'});
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
-            fail("insert(-1, char[], 3, 3) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
-            fail("insert(7, char[], 3, 3) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, (char[]) null, 0, 0);
-        assertEquals("barbaz", sb.toString());
-
-        sb.insert(0, new char[0], 0, 0);
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, -1, 3);
-            fail("insert(0, char[], -1, 3) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 10, 3);
-            fail("insert(0, char[], 10, 3) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, -1);
-            fail("insert(0, char[], 0, -1) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 10);
-            fail("insert(0, char[], 0, 10) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 0);
-        assertEquals("barbaz", sb.toString());
-
-        sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
-        assertEquals("foobarbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, true);
-            fail("insert(-1, boolean) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, true);
-            fail("insert(7, boolean) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, true);
-        assertEquals("truebarbaz", sb.toString());
-
-        sb.insert(0, false);
-        assertEquals("falsetruebarbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, '!');
-            fail("insert(-1, char) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, '!');
-            fail("insert(7, char) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, '!');
-        assertEquals("!barbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, 0);
-            fail("insert(-1, int) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, 0);
-            fail("insert(7, int) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, '0');
-        assertEquals("0barbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, 1L);
-            fail("insert(-1, long) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, 1L);
-            fail("insert(7, long) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, 1L);
-        assertEquals("1barbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, 2.3F);
-            fail("insert(-1, float) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, 2.3F);
-            fail("insert(7, float) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, 2.3F);
-        assertEquals("2.3barbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, 4.5D);
-            fail("insert(-1, double) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, 4.5D);
-            fail("insert(7, double) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, 4.5D);
-        assertEquals("4.5barbaz", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testInsertWithNullText() {
-        final StrBuilder sb = new StrBuilder();
-        sb.setNullText("null");
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, FOO);
-            fail("insert(-1, Object) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, FOO);
-            fail("insert(7, Object) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, (Object) null);
-        assertEquals("nullbarbaz", sb.toString());
-
-        sb.insert(0, FOO);
-        assertEquals("foonullbarbaz", sb.toString());
-
-        sb.clear();
-        sb.append("barbaz");
-        assertEquals("barbaz", sb.toString());
-
-        try {
-            sb.insert(-1, "foo");
-            fail("insert(-1, String) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        try {
-            sb.insert(7, "foo");
-            fail("insert(7, String) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.insert(0, (String) null);
-        assertEquals("nullbarbaz", sb.toString());
-
-        sb.insert(0, "foo");
-        assertEquals("foonullbarbaz", sb.toString());
-
-        sb.insert(0, (char[]) null);
-        assertEquals("nullfoonullbarbaz", sb.toString());
-
-        sb.insert(0, (char[]) null, 0, 0);
-        assertEquals("nullnullfoonullbarbaz", sb.toString());
-    }
-}


[24/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/StrBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StrBuilder.java b/src/main/java/org/apache/commons/text/beta/StrBuilder.java
deleted file mode 100644
index 5043fd6..0000000
--- a/src/main/java/org/apache/commons/text/beta/StrBuilder.java
+++ /dev/null
@@ -1,3092 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Serializable;
-import java.io.Writer;
-import java.nio.CharBuffer;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Builds a string from constituent parts providing a more flexible and powerful API
- * than StringBuffer.
- * <p>
- * The main differences from StringBuffer/StringBuilder are:
- * </p>
- * <ul>
- * <li>Not synchronized</li>
- * <li>Not final</li>
- * <li>Subclasses have direct access to character array</li>
- * <li>Additional methods
- *  <ul>
- *   <li>appendWithSeparators - adds an array of values, with a separator</li>
- *   <li>appendPadding - adds a length padding characters</li>
- *   <li>appendFixedLength - adds a fixed width field to the builder</li>
- *   <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
- *   <li>delete - delete char or string</li>
- *   <li>replace - search and replace for a char or string</li>
- *   <li>leftString/rightString/midString - substring without exceptions</li>
- *   <li>contains - whether the builder contains a char or string</li>
- *   <li>size/clear/isEmpty - collections style API methods</li>
- *  </ul>
- * </li>
- * <li>Views
- *  <ul>
- *   <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
- *   <li>asReader - uses the internal buffer as the source of a Reader</li>
- *   <li>asWriter - allows a Writer to write directly to the internal buffer</li>
- *  </ul>
- * </li>
- * </ul>
- * <p>
- * The aim has been to provide an API that mimics very closely what StringBuffer
- * provides, but with additional methods. It should be noted that some edge cases,
- * with invalid indices or null input, have been altered - see individual methods.
- * The biggest of these changes is that by default, null will not output the text
- * 'null'. This can be controlled by a property, {@link #setNullText(String)}.
- * </p>
- *
- * @since 1.0
- *
- */
-public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
-
-    /**
-     * The extra capacity for new builders.
-     */
-    static final int CAPACITY = 32;
-
-    /**
-     * Required for serialization support.
-     *
-     * @see java.io.Serializable
-     */
-    private static final long serialVersionUID = 7628716375283629643L;
-
-    /** Internal data storage. */
-    char[] buffer; // package-protected for test code use only
-    /** Current size of the buffer. */
-    private int size;
-    /** The new line. */
-    private String newLine;
-    /** The null text. */
-    private String nullText;
-
-    //-----------------------------------------------------------------------
-    /**
-     * Constructor that creates an empty builder initial capacity 32 characters.
-     */
-    public StrBuilder() {
-        this(CAPACITY);
-    }
-
-    /**
-     * Constructor that creates an empty builder the specified initial capacity.
-     *
-     * @param initialCapacity  the initial capacity, zero or less will be converted to 32
-     */
-    public StrBuilder(int initialCapacity) {
-        super();
-        if (initialCapacity <= 0) {
-            initialCapacity = CAPACITY;
-        }
-        buffer = new char[initialCapacity];
-    }
-
-    /**
-     * Constructor that creates a builder from the string, allocating
-     * 32 extra characters for growth.
-     *
-     * @param str  the string to copy, null treated as blank string
-     */
-    public StrBuilder(final String str) {
-        super();
-        if (str == null) {
-            buffer = new char[CAPACITY];
-        } else {
-            buffer = new char[str.length() + CAPACITY];
-            append(str);
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the text to be appended when a new line is added.
-     *
-     * @return the new line text, null means use system default
-     */
-    public String getNewLineText() {
-        return newLine;
-    }
-
-    /**
-     * Sets the text to be appended when a new line is added.
-     *
-     * @param newLine  the new line text, null means use system default
-     * @return this, to enable chaining
-     */
-    public StrBuilder setNewLineText(final String newLine) {
-        this.newLine = newLine;
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the text to be appended when null is added.
-     *
-     * @return the null text, null means no append
-     */
-    public String getNullText() {
-        return nullText;
-    }
-
-    /**
-     * Sets the text to be appended when null is added.
-     *
-     * @param nullText  the null text, null means no append
-     * @return this, to enable chaining
-     */
-    public StrBuilder setNullText(String nullText) {
-        if (nullText != null && nullText.isEmpty()) {
-            nullText = null;
-        }
-        this.nullText = nullText;
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the length of the string builder.
-     *
-     * @return the length
-     */
-    @Override
-    public int length() {
-        return size;
-    }
-
-    /**
-     * Updates the length of the builder by either dropping the last characters
-     * or adding filler of Unicode zero.
-     *
-     * @param length  the length to set to, must be zero or positive
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the length is negative
-     */
-    public StrBuilder setLength(final int length) {
-        if (length < 0) {
-            throw new StringIndexOutOfBoundsException(length);
-        }
-        if (length < size) {
-            size = length;
-        } else if (length > size) {
-            ensureCapacity(length);
-            final int oldEnd = size;
-            final int newEnd = length;
-            size = length;
-            for (int i = oldEnd; i < newEnd; i++) {
-                buffer[i] = '\0';
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the current size of the internal character array buffer.
-     *
-     * @return the capacity
-     */
-    public int capacity() {
-        return buffer.length;
-    }
-
-    /**
-     * Checks the capacity and ensures that it is at least the size specified.
-     *
-     * @param capacity  the capacity to ensure
-     * @return this, to enable chaining
-     */
-    public StrBuilder ensureCapacity(final int capacity) {
-        if (capacity > buffer.length) {
-            final char[] old = buffer;
-            buffer = new char[capacity * 2];
-            System.arraycopy(old, 0, buffer, 0, size);
-        }
-        return this;
-    }
-
-    /**
-     * Minimizes the capacity to the actual length of the string.
-     *
-     * @return this, to enable chaining
-     */
-    public StrBuilder minimizeCapacity() {
-        if (buffer.length > length()) {
-            final char[] old = buffer;
-            buffer = new char[length()];
-            System.arraycopy(old, 0, buffer, 0, size);
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the length of the string builder.
-     * <p>
-     * This method is the same as {@link #length()} and is provided to match the
-     * API of Collections.
-     *
-     * @return the length
-     */
-    public int size() {
-        return size;
-    }
-
-    /**
-     * Checks is the string builder is empty (convenience Collections API style method).
-     * <p>
-     * This method is the same as checking {@link #length()} and is provided to match the
-     * API of Collections.
-     *
-     * @return <code>true</code> if the size is <code>0</code>.
-     */
-    public boolean isEmpty() {
-        return size == 0;
-    }
-
-    /**
-     * Clears the string builder (convenience Collections API style method).
-     * <p>
-     * This method does not reduce the size of the internal character buffer.
-     * To do that, call <code>clear()</code> followed by {@link #minimizeCapacity()}.
-     * <p>
-     * This method is the same as {@link #setLength(int)} called with zero
-     * and is provided to match the API of Collections.
-     *
-     * @return this, to enable chaining
-     */
-    public StrBuilder clear() {
-        size = 0;
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the character at the specified index.
-     *
-     * @see #setCharAt(int, char)
-     * @see #deleteCharAt(int)
-     * @param index  the index to retrieve, must be valid
-     * @return the character at the index
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    @Override
-    public char charAt(final int index) {
-        if (index < 0 || index >= length()) {
-            throw new StringIndexOutOfBoundsException(index);
-        }
-        return buffer[index];
-    }
-
-    /**
-     * Sets the character at the specified index.
-     *
-     * @see #charAt(int)
-     * @see #deleteCharAt(int)
-     * @param index  the index to set
-     * @param ch  the new character
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder setCharAt(final int index, final char ch) {
-        if (index < 0 || index >= length()) {
-            throw new StringIndexOutOfBoundsException(index);
-        }
-        buffer[index] = ch;
-        return this;
-    }
-
-    /**
-     * Deletes the character at the specified index.
-     *
-     * @see #charAt(int)
-     * @see #setCharAt(int, char)
-     * @param index  the index to delete
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder deleteCharAt(final int index) {
-        if (index < 0 || index >= size) {
-            throw new StringIndexOutOfBoundsException(index);
-        }
-        deleteImpl(index, index + 1, 1);
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Copies the builder's character array into a new character array.
-     *
-     * @return a new array that represents the contents of the builder
-     */
-    public char[] toCharArray() {
-        if (size == 0) {
-            return new char[0];
-        }
-        final char[] chars = new char[size];
-        System.arraycopy(buffer, 0, chars, 0, size);
-        return chars;
-    }
-
-    /**
-     * Copies part of the builder's character array into a new character array.
-     *
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param endIndex  the end index, exclusive, must be valid except that
-     *  if too large it is treated as end of string
-     * @return a new array that holds part of the contents of the builder
-     * @throws IndexOutOfBoundsException if startIndex is invalid,
-     *  or if endIndex is invalid (but endIndex greater than size is valid)
-     */
-    public char[] toCharArray(final int startIndex, int endIndex) {
-        endIndex = validateRange(startIndex, endIndex);
-        final int len = endIndex - startIndex;
-        if (len == 0) {
-            return new char[0];
-        }
-        final char[] chars = new char[len];
-        System.arraycopy(buffer, startIndex, chars, 0, len);
-        return chars;
-    }
-
-    /**
-     * Copies the character array into the specified array.
-     *
-     * @param destination  the destination array, null will cause an array to be created
-     * @return the input array, unless that was null or too small
-     */
-    public char[] getChars(char[] destination) {
-        final int len = length();
-        if (destination == null || destination.length < len) {
-            destination = new char[len];
-        }
-        System.arraycopy(buffer, 0, destination, 0, len);
-        return destination;
-    }
-
-    /**
-     * Copies the character array into the specified array.
-     *
-     * @param startIndex  first index to copy, inclusive, must be valid
-     * @param endIndex  last index, exclusive, must be valid
-     * @param destination  the destination array, must not be null or too small
-     * @param destinationIndex  the index to start copying in destination
-     * @throws NullPointerException if the array is null
-     * @throws IndexOutOfBoundsException if any index is invalid
-     */
-    public void getChars(final int startIndex,
-                         final int endIndex,
-                         final char[] destination,
-                         final int destinationIndex) {
-        if (startIndex < 0) {
-            throw new StringIndexOutOfBoundsException(startIndex);
-        }
-        if (endIndex < 0 || endIndex > length()) {
-            throw new StringIndexOutOfBoundsException(endIndex);
-        }
-        if (startIndex > endIndex) {
-            throw new StringIndexOutOfBoundsException("end < start");
-        }
-        System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * If possible, reads chars from the provided {@link Readable} directly into underlying
-     * character buffer without making extra copies.
-     *
-     * @param readable  object to read from
-     * @return the number of characters read
-     * @throws IOException if an I/O error occurs
-     *
-     * @see #appendTo(Appendable)
-     */
-    public int readFrom(final Readable readable) throws IOException {
-        final int oldSize = size;
-        if (readable instanceof Reader) {
-            final Reader r = (Reader) readable;
-            ensureCapacity(size + 1);
-            int read;
-            while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
-                size += read;
-                ensureCapacity(size + 1);
-            }
-        } else if (readable instanceof CharBuffer) {
-            final CharBuffer cb = (CharBuffer) readable;
-            final int remaining = cb.remaining();
-            ensureCapacity(size + remaining);
-            cb.get(buffer, size, remaining);
-            size += remaining;
-        } else {
-            while (true) {
-                ensureCapacity(size + 1);
-                final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
-                final int read = readable.read(buf);
-                if (read == -1) {
-                    break;
-                }
-                size += read;
-            }
-        }
-        return size - oldSize;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends the new line string to this string builder.
-     * <p>
-     * The new line string can be altered using {@link #setNewLineText(String)}.
-     * This might be used to force the output to always use Unix line endings
-     * even when on Windows.
-     *
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendNewLine() {
-        if (newLine == null)  {
-            append(System.getProperty("line.separator"));
-            return this;
-        }
-        return append(newLine);
-    }
-
-    /**
-     * Appends the text representing <code>null</code> to this string builder.
-     *
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendNull() {
-        if (nullText == null)  {
-            return this;
-        }
-        return append(nullText);
-    }
-
-    /**
-     * Appends an object to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param obj  the object to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final Object obj) {
-        if (obj == null) {
-            return appendNull();
-        }
-        if (obj instanceof CharSequence) {
-            return append((CharSequence) obj);
-        }
-        return append(obj.toString());
-    }
-
-    /**
-     * Appends a CharSequence to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param seq  the CharSequence to append
-     * @return this, to enable chaining
-     */
-    @Override
-    public StrBuilder append(final CharSequence seq) {
-        if (seq == null) {
-            return appendNull();
-        }
-        if (seq instanceof StrBuilder) {
-            return append((StrBuilder) seq);
-        }
-        if (seq instanceof StringBuilder) {
-            return append((StringBuilder) seq);
-        }
-        if (seq instanceof StringBuffer) {
-            return append((StringBuffer) seq);
-        }
-        if (seq instanceof CharBuffer) {
-            return append((CharBuffer) seq);
-        }
-        return append(seq.toString());
-    }
-
-    /**
-     * Appends part of a CharSequence to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param seq  the CharSequence to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    @Override
-    public StrBuilder append(final CharSequence seq, final int startIndex, final int length) {
-        if (seq == null) {
-            return appendNull();
-        }
-        return append(seq.toString(), startIndex, length);
-    }
-
-    /**
-     * Appends a string to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final String str) {
-        if (str == null) {
-            return appendNull();
-        }
-        final int strLen = str.length();
-        if (strLen > 0) {
-            final int len = length();
-            ensureCapacity(len + strLen);
-            str.getChars(0, strLen, buffer, len);
-            size += strLen;
-        }
-        return this;
-    }
-
-
-    /**
-     * Appends part of a string to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final String str, final int startIndex, final int length) {
-        if (str == null) {
-            return appendNull();
-        }
-        if (startIndex < 0 || startIndex > str.length()) {
-            throw new StringIndexOutOfBoundsException("startIndex must be valid");
-        }
-        if (length < 0 || (startIndex + length) > str.length()) {
-            throw new StringIndexOutOfBoundsException("length must be valid");
-        }
-        if (length > 0) {
-            final int len = length();
-            ensureCapacity(len + length);
-            str.getChars(startIndex, startIndex + length, buffer, len);
-            size += length;
-        }
-        return this;
-    }
-
-    /**
-     * Calls {@link String#format(String, Object...)} and appends the result.
-     *
-     * @param format the format string
-     * @param objs the objects to use in the format string
-     * @return {@code this} to enable chaining
-     * @see String#format(String, Object...)
-     */
-    public StrBuilder append(final String format, final Object... objs) {
-        return append(String.format(format, objs));
-    }
-
-    /**
-     * Appends the contents of a char buffer to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param buf  the char buffer to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final CharBuffer buf) {
-        if (buf == null) {
-            return appendNull();
-        }
-        if (buf.hasArray()) {
-            final int length = buf.remaining();
-            final int len = length();
-            ensureCapacity(len + length);
-            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length);
-            size += length;
-        } else {
-            append(buf.toString());
-        }
-        return this;
-    }
-
-    /**
-     * Appends the contents of a char buffer to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param buf  the char buffer to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) {
-        if (buf == null) {
-            return appendNull();
-        }
-        if (buf.hasArray()) {
-            final int totalLength = buf.remaining();
-            if (startIndex < 0 || startIndex > totalLength) {
-                throw new StringIndexOutOfBoundsException("startIndex must be valid");
-            }
-            if (length < 0 || (startIndex + length) > totalLength) {
-                throw new StringIndexOutOfBoundsException("length must be valid");
-            }
-            final int len = length();
-            ensureCapacity(len + length);
-            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length);
-            size += length;
-        } else {
-            append(buf.toString(), startIndex, length);
-        }
-        return this;
-    }
-
-    /**
-     * Appends a string buffer to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string buffer to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final StringBuffer str) {
-        if (str == null) {
-            return appendNull();
-        }
-        final int strLen = str.length();
-        if (strLen > 0) {
-            final int len = length();
-            ensureCapacity(len + strLen);
-            str.getChars(0, strLen, buffer, len);
-            size += strLen;
-        }
-        return this;
-    }
-
-    /**
-     * Appends part of a string buffer to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
-        if (str == null) {
-            return appendNull();
-        }
-        if (startIndex < 0 || startIndex > str.length()) {
-            throw new StringIndexOutOfBoundsException("startIndex must be valid");
-        }
-        if (length < 0 || (startIndex + length) > str.length()) {
-            throw new StringIndexOutOfBoundsException("length must be valid");
-        }
-        if (length > 0) {
-            final int len = length();
-            ensureCapacity(len + length);
-            str.getChars(startIndex, startIndex + length, buffer, len);
-            size += length;
-        }
-        return this;
-    }
-
-    /**
-     * Appends a StringBuilder to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str the StringBuilder to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final StringBuilder str) {
-        if (str == null) {
-            return appendNull();
-        }
-        final int strLen = str.length();
-        if (strLen > 0) {
-            final int len = length();
-            ensureCapacity(len + strLen);
-            str.getChars(0, strLen, buffer, len);
-            size += strLen;
-        }
-        return this;
-    }
-
-    /**
-     * Appends part of a StringBuilder to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str the StringBuilder to append
-     * @param startIndex the start index, inclusive, must be valid
-     * @param length the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
-        if (str == null) {
-            return appendNull();
-        }
-        if (startIndex < 0 || startIndex > str.length()) {
-            throw new StringIndexOutOfBoundsException("startIndex must be valid");
-        }
-        if (length < 0 || (startIndex + length) > str.length()) {
-            throw new StringIndexOutOfBoundsException("length must be valid");
-        }
-        if (length > 0) {
-            final int len = length();
-            ensureCapacity(len + length);
-            str.getChars(startIndex, startIndex + length, buffer, len);
-            size += length;
-        }
-        return this;
-    }
-
-    /**
-     * Appends another string builder to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string builder to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final StrBuilder str) {
-        if (str == null) {
-            return appendNull();
-        }
-        final int strLen = str.length();
-        if (strLen > 0) {
-            final int len = length();
-            ensureCapacity(len + strLen);
-            System.arraycopy(str.buffer, 0, buffer, len, strLen);
-            size += strLen;
-        }
-        return this;
-    }
-
-    /**
-     * Appends part of a string builder to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
-        if (str == null) {
-            return appendNull();
-        }
-        if (startIndex < 0 || startIndex > str.length()) {
-            throw new StringIndexOutOfBoundsException("startIndex must be valid");
-        }
-        if (length < 0 || (startIndex + length) > str.length()) {
-            throw new StringIndexOutOfBoundsException("length must be valid");
-        }
-        if (length > 0) {
-            final int len = length();
-            ensureCapacity(len + length);
-            str.getChars(startIndex, startIndex + length, buffer, len);
-            size += length;
-        }
-        return this;
-    }
-
-    /**
-     * Appends a char array to the string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param chars  the char array to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final char[] chars) {
-        if (chars == null) {
-            return appendNull();
-        }
-        final int strLen = chars.length;
-        if (strLen > 0) {
-            final int len = length();
-            ensureCapacity(len + strLen);
-            System.arraycopy(chars, 0, buffer, len, strLen);
-            size += strLen;
-        }
-        return this;
-    }
-
-    /**
-     * Appends a char array to the string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param chars  the char array to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final char[] chars, final int startIndex, final int length) {
-        if (chars == null) {
-            return appendNull();
-        }
-        if (startIndex < 0 || startIndex > chars.length) {
-            throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
-        }
-        if (length < 0 || (startIndex + length) > chars.length) {
-            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
-        }
-        if (length > 0) {
-            final int len = length();
-            ensureCapacity(len + length);
-            System.arraycopy(chars, startIndex, buffer, len, length);
-            size += length;
-        }
-        return this;
-    }
-
-    /**
-     * Appends a boolean value to the string builder.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final boolean value) {
-        if (value) {
-            ensureCapacity(size + 4);
-            buffer[size++] = 't';
-            buffer[size++] = 'r';
-            buffer[size++] = 'u';
-            buffer[size++] = 'e';
-        } else {
-            ensureCapacity(size + 5);
-            buffer[size++] = 'f';
-            buffer[size++] = 'a';
-            buffer[size++] = 'l';
-            buffer[size++] = 's';
-            buffer[size++] = 'e';
-        }
-        return this;
-    }
-
-    /**
-     * Appends a char value to the string builder.
-     *
-     * @param ch  the value to append
-     * @return this, to enable chaining
-     */
-    @Override
-    public StrBuilder append(final char ch) {
-        final int len = length();
-        ensureCapacity(len + 1);
-        buffer[size++] = ch;
-        return this;
-    }
-
-    /**
-     * Appends an int value to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final int value) {
-        return append(String.valueOf(value));
-    }
-
-    /**
-     * Appends a long value to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final long value) {
-        return append(String.valueOf(value));
-    }
-
-    /**
-     * Appends a float value to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final float value) {
-        return append(String.valueOf(value));
-    }
-
-    /**
-     * Appends a double value to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder append(final double value) {
-        return append(String.valueOf(value));
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends an object followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param obj  the object to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final Object obj) {
-        return append(obj).appendNewLine();
-    }
-
-    /**
-     * Appends a string followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final String str) {
-        return append(str).appendNewLine();
-    }
-
-    /**
-     * Appends part of a string followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final String str, final int startIndex, final int length) {
-        return append(str, startIndex, length).appendNewLine();
-    }
-
-    /**
-     * Calls {@link String#format(String, Object...)} and appends the result.
-     *
-     * @param format the format string
-     * @param objs the objects to use in the format string
-     * @return {@code this} to enable chaining
-     * @see String#format(String, Object...)
-     */
-    public StrBuilder appendln(final String format, final Object... objs) {
-        return append(format, objs).appendNewLine();
-    }
-
-    /**
-     * Appends a string buffer followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string buffer to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final StringBuffer str) {
-        return append(str).appendNewLine();
-    }
-
-    /**
-     * Appends a string builder followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string builder to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final StringBuilder str) {
-        return append(str).appendNewLine();
-    }
-
-    /**
-     * Appends part of a string builder followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string builder to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
-        return append(str, startIndex, length).appendNewLine();
-    }
-
-    /**
-     * Appends part of a string buffer followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
-        return append(str, startIndex, length).appendNewLine();
-    }
-
-    /**
-     * Appends another string builder followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string builder to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final StrBuilder str) {
-        return append(str).appendNewLine();
-    }
-
-    /**
-     * Appends part of a string builder followed by a new line to this string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param str  the string to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) {
-        return append(str, startIndex, length).appendNewLine();
-    }
-
-    /**
-     * Appends a char array followed by a new line to the string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param chars  the char array to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final char[] chars) {
-        return append(chars).appendNewLine();
-    }
-
-    /**
-     * Appends a char array followed by a new line to the string builder.
-     * Appending null will call {@link #appendNull()}.
-     *
-     * @param chars  the char array to append
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param length  the length to append, must be valid
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final char[] chars, final int startIndex, final int length) {
-        return append(chars, startIndex, length).appendNewLine();
-    }
-
-    /**
-     * Appends a boolean value followed by a new line to the string builder.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final boolean value) {
-        return append(value).appendNewLine();
-    }
-
-    /**
-     * Appends a char value followed by a new line to the string builder.
-     *
-     * @param ch  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final char ch) {
-        return append(ch).appendNewLine();
-    }
-
-    /**
-     * Appends an int value followed by a new line to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final int value) {
-        return append(value).appendNewLine();
-    }
-
-    /**
-     * Appends a long value followed by a new line to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final long value) {
-        return append(value).appendNewLine();
-    }
-
-    /**
-     * Appends a float value followed by a new line to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final float value) {
-        return append(value).appendNewLine();
-    }
-
-    /**
-     * Appends a double value followed by a new line to the string builder using <code>String.valueOf</code>.
-     *
-     * @param value  the value to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendln(final double value) {
-        return append(value).appendNewLine();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends each item in an array to the builder without any separators.
-     * Appending a null array will have no effect.
-     * Each object is appended using {@link #append(Object)}.
-     *
-     * @param <T>  the element type
-     * @param array  the array to append
-     * @return this, to enable chaining
-     */
-    public <T> StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
-        /*
-         * @SuppressWarnings used to hide warning about vararg usage. We cannot
-         * use @SafeVarargs, since this method is not final. Using @SupressWarnings
-         * is fine, because it isn't inherited by subclasses, so each subclass must
-         * vouch for itself whether its use of 'array' is safe.
-         */
-        if (array != null && array.length > 0) {
-            for (final Object element : array) {
-                append(element);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Appends each item in an iterable to the builder without any separators.
-     * Appending a null iterable will have no effect.
-     * Each object is appended using {@link #append(Object)}.
-     *
-     * @param iterable  the iterable to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendAll(final Iterable<?> iterable) {
-        if (iterable != null) {
-            for (final Object o : iterable) {
-                append(o);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Appends each item in an iterator to the builder without any separators.
-     * Appending a null iterator will have no effect.
-     * Each object is appended using {@link #append(Object)}.
-     *
-     * @param it  the iterator to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendAll(final Iterator<?> it) {
-        if (it != null) {
-            while (it.hasNext()) {
-                append(it.next());
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends an array placing separators between each value, but
-     * not before the first or after the last.
-     * Appending a null array will have no effect.
-     * Each object is appended using {@link #append(Object)}.
-     *
-     * @param array  the array to append
-     * @param separator  the separator to use, null means no separator
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
-        if (array != null && array.length > 0) {
-            final String sep = Objects.toString(separator, "");
-            append(array[0]);
-            for (int i = 1; i < array.length; i++) {
-                append(sep);
-                append(array[i]);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Appends an iterable placing separators between each value, but
-     * not before the first or after the last.
-     * Appending a null iterable will have no effect.
-     * Each object is appended using {@link #append(Object)}.
-     *
-     * @param iterable  the iterable to append
-     * @param separator  the separator to use, null means no separator
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
-        if (iterable != null) {
-            final String sep = Objects.toString(separator, "");
-            final Iterator<?> it = iterable.iterator();
-            while (it.hasNext()) {
-                append(it.next());
-                if (it.hasNext()) {
-                    append(sep);
-                }
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Appends an iterator placing separators between each value, but
-     * not before the first or after the last.
-     * Appending a null iterator will have no effect.
-     * Each object is appended using {@link #append(Object)}.
-     *
-     * @param it  the iterator to append
-     * @param separator  the separator to use, null means no separator
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
-        if (it != null) {
-            final String sep = Objects.toString(separator, "");
-            while (it.hasNext()) {
-                append(it.next());
-                if (it.hasNext()) {
-                    append(sep);
-                }
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends a separator if the builder is currently non-empty.
-     * Appending a null separator will have no effect.
-     * The separator is appended using {@link #append(String)}.
-     * <p>
-     * This method is useful for adding a separator each time around the
-     * loop except the first.
-     * <pre>
-     * for (Iterator it = list.iterator(); it.hasNext(); ) {
-     *   appendSeparator(",");
-     *   append(it.next());
-     * }
-     * </pre>
-     * Note that for this simple example, you should use
-     * {@link #appendWithSeparators(Iterable, String)}.
-     *
-     * @param separator  the separator to use, null means no separator
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendSeparator(final String separator) {
-        return appendSeparator(separator, null);
-    }
-
-    /**
-     * Appends one of both separators to the StrBuilder.
-     * If the builder is currently empty it will append the defaultIfEmpty-separator
-     * Otherwise it will append the standard-separator
-     *
-     * Appending a null separator will have no effect.
-     * The separator is appended using {@link #append(String)}.
-     * <p>
-     * This method is for example useful for constructing queries
-     * <pre>
-     * StrBuilder whereClause = new StrBuilder();
-     * if(searchCommand.getPriority() != null) {
-     *  whereClause.appendSeparator(" and", " where");
-     *  whereClause.append(" priority = ?")
-     * }
-     * if(searchCommand.getComponent() != null) {
-     *  whereClause.appendSeparator(" and", " where");
-     *  whereClause.append(" component = ?")
-     * }
-     * selectClause.append(whereClause)
-     * </pre>
-     *
-     * @param standard the separator if builder is not empty, null means no separator
-     * @param defaultIfEmpty the separator if builder is empty, null means no separator
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
-        final String str = isEmpty() ? defaultIfEmpty : standard;
-        if (str != null) {
-            append(str);
-        }
-        return this;
-    }
-
-    /**
-     * Appends a separator if the builder is currently non-empty.
-     * The separator is appended using {@link #append(char)}.
-     * <p>
-     * This method is useful for adding a separator each time around the
-     * loop except the first.
-     * <pre>
-     * for (Iterator it = list.iterator(); it.hasNext(); ) {
-     *   appendSeparator(',');
-     *   append(it.next());
-     * }
-     * </pre>
-     * Note that for this simple example, you should use
-     * {@link #appendWithSeparators(Iterable, String)}.
-     *
-     * @param separator  the separator to use
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendSeparator(final char separator) {
-        if (size() > 0) {
-            append(separator);
-        }
-        return this;
-    }
-
-    /**
-     * Append one of both separators to the builder
-     * If the builder is currently empty it will append the defaultIfEmpty-separator
-     * Otherwise it will append the standard-separator
-     *
-     * The separator is appended using {@link #append(char)}.
-     * @param standard the separator if builder is not empty
-     * @param defaultIfEmpty the separator if builder is empty
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
-        if (size() > 0) {
-            append(standard);
-        } else {
-            append(defaultIfEmpty);
-        }
-        return this;
-    }
-    /**
-     * Appends a separator to the builder if the loop index is greater than zero.
-     * Appending a null separator will have no effect.
-     * The separator is appended using {@link #append(String)}.
-     * <p>
-     * This method is useful for adding a separator each time around the
-     * loop except the first.
-     * </p>
-     * <pre>
-     * for (int i = 0; i &lt; list.size(); i++) {
-     *   appendSeparator(",", i);
-     *   append(list.get(i));
-     * }
-     * </pre>
-     * Note that for this simple example, you should use
-     * {@link #appendWithSeparators(Iterable, String)}.
-     *
-     * @param separator  the separator to use, null means no separator
-     * @param loopIndex  the loop index
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendSeparator(final String separator, final int loopIndex) {
-        if (separator != null && loopIndex > 0) {
-            append(separator);
-        }
-        return this;
-    }
-
-    /**
-     * Appends a separator to the builder if the loop index is greater than zero.
-     * The separator is appended using {@link #append(char)}.
-     * <p>
-     * This method is useful for adding a separator each time around the
-     * loop except the first.
-     * </p>
-     * <pre>
-     * for (int i = 0; i &lt; list.size(); i++) {
-     *   appendSeparator(",", i);
-     *   append(list.get(i));
-     * }
-     * </pre>
-     * Note that for this simple example, you should use
-     * {@link #appendWithSeparators(Iterable, String)}.
-     *
-     * @param separator  the separator to use
-     * @param loopIndex  the loop index
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendSeparator(final char separator, final int loopIndex) {
-        if (loopIndex > 0) {
-            append(separator);
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends the pad character to the builder the specified number of times.
-     *
-     * @param length  the length to append, negative means no append
-     * @param padChar  the character to append
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendPadding(final int length, final char padChar) {
-        if (length >= 0) {
-            ensureCapacity(size + length);
-            for (int i = 0; i < length; i++) {
-                buffer[size++] = padChar;
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Appends an object to the builder padding on the left to a fixed width.
-     * The <code>toString</code> of the object is used.
-     * If the object is larger than the length, the left hand side is lost.
-     * If the object is null, the null text value is used.
-     *
-     * @param obj  the object to append, null uses null text
-     * @param width  the fixed field width, zero or negative has no effect
-     * @param padChar  the pad character to use
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
-        if (width > 0) {
-            ensureCapacity(size + width);
-            String str = (obj == null ? getNullText() : obj.toString());
-            if (str == null) {
-                str = "";
-            }
-            final int strLen = str.length();
-            if (strLen >= width) {
-                str.getChars(strLen - width, strLen, buffer, size);
-            } else {
-                final int padLen = width - strLen;
-                for (int i = 0; i < padLen; i++) {
-                    buffer[size + i] = padChar;
-                }
-                str.getChars(0, strLen, buffer, size + padLen);
-            }
-            size += width;
-        }
-        return this;
-    }
-
-    /**
-     * Appends an object to the builder padding on the left to a fixed width.
-     * The <code>String.valueOf</code> of the <code>int</code> value is used.
-     * If the formatted value is larger than the length, the left hand side is lost.
-     *
-     * @param value  the value to append
-     * @param width  the fixed field width, zero or negative has no effect
-     * @param padChar  the pad character to use
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
-        return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
-    }
-
-    /**
-     * Appends an object to the builder padding on the right to a fixed length.
-     * The <code>toString</code> of the object is used.
-     * If the object is larger than the length, the right hand side is lost.
-     * If the object is null, null text value is used.
-     *
-     * @param obj  the object to append, null uses null text
-     * @param width  the fixed field width, zero or negative has no effect
-     * @param padChar  the pad character to use
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
-        if (width > 0) {
-            ensureCapacity(size + width);
-            String str = (obj == null ? getNullText() : obj.toString());
-            if (str == null) {
-                str = "";
-            }
-            final int strLen = str.length();
-            if (strLen >= width) {
-                str.getChars(0, width, buffer, size);
-            } else {
-                final int padLen = width - strLen;
-                str.getChars(0, strLen, buffer, size);
-                for (int i = 0; i < padLen; i++) {
-                    buffer[size + strLen + i] = padChar;
-                }
-            }
-            size += width;
-        }
-        return this;
-    }
-
-    /**
-     * Appends an object to the builder padding on the right to a fixed length.
-     * The <code>String.valueOf</code> of the <code>int</code> value is used.
-     * If the object is larger than the length, the right hand side is lost.
-     *
-     * @param value  the value to append
-     * @param width  the fixed field width, zero or negative has no effect
-     * @param padChar  the pad character to use
-     * @return this, to enable chaining
-     */
-    public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
-        return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Inserts the string representation of an object into this builder.
-     * Inserting null will use the stored null text value.
-     *
-     * @param index  the index to add at, must be valid
-     * @param obj  the object to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final Object obj) {
-        if (obj == null) {
-            return insert(index, nullText);
-        }
-        return insert(index, obj.toString());
-    }
-
-    /**
-     * Inserts the string into this builder.
-     * Inserting null will use the stored null text value.
-     *
-     * @param index  the index to add at, must be valid
-     * @param str  the string to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, String str) {
-        validateIndex(index);
-        if (str == null) {
-            str = nullText;
-        }
-        if (str != null) {
-            final int strLen = str.length();
-            if (strLen > 0) {
-                final int newSize = size + strLen;
-                ensureCapacity(newSize);
-                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
-                size = newSize;
-                str.getChars(0, strLen, buffer, index);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Inserts the character array into this builder.
-     * Inserting null will use the stored null text value.
-     *
-     * @param index  the index to add at, must be valid
-     * @param chars  the char array to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final char[] chars) {
-        validateIndex(index);
-        if (chars == null) {
-            return insert(index, nullText);
-        }
-        final int len = chars.length;
-        if (len > 0) {
-            ensureCapacity(size + len);
-            System.arraycopy(buffer, index, buffer, index + len, size - index);
-            System.arraycopy(chars, 0, buffer, index, len);
-            size += len;
-        }
-        return this;
-    }
-
-    /**
-     * Inserts part of the character array into this builder.
-     * Inserting null will use the stored null text value.
-     *
-     * @param index  the index to add at, must be valid
-     * @param chars  the char array to insert
-     * @param offset  the offset into the character array to start at, must be valid
-     * @param length  the length of the character array part to copy, must be positive
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if any index is invalid
-     */
-    public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
-        validateIndex(index);
-        if (chars == null) {
-            return insert(index, nullText);
-        }
-        if (offset < 0 || offset > chars.length) {
-            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
-        }
-        if (length < 0 || offset + length > chars.length) {
-            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
-        }
-        if (length > 0) {
-            ensureCapacity(size + length);
-            System.arraycopy(buffer, index, buffer, index + length, size - index);
-            System.arraycopy(chars, offset, buffer, index, length);
-            size += length;
-        }
-        return this;
-    }
-
-    /**
-     * Inserts the value into this builder.
-     *
-     * @param index  the index to add at, must be valid
-     * @param value  the value to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(int index, final boolean value) {
-        validateIndex(index);
-        if (value) {
-            ensureCapacity(size + 4);
-            System.arraycopy(buffer, index, buffer, index + 4, size - index);
-            buffer[index++] = 't';
-            buffer[index++] = 'r';
-            buffer[index++] = 'u';
-            buffer[index] = 'e';
-            size += 4;
-        } else {
-            ensureCapacity(size + 5);
-            System.arraycopy(buffer, index, buffer, index + 5, size - index);
-            buffer[index++] = 'f';
-            buffer[index++] = 'a';
-            buffer[index++] = 'l';
-            buffer[index++] = 's';
-            buffer[index] = 'e';
-            size += 5;
-        }
-        return this;
-    }
-
-    /**
-     * Inserts the value into this builder.
-     *
-     * @param index  the index to add at, must be valid
-     * @param value  the value to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final char value) {
-        validateIndex(index);
-        ensureCapacity(size + 1);
-        System.arraycopy(buffer, index, buffer, index + 1, size - index);
-        buffer[index] = value;
-        size++;
-        return this;
-    }
-
-    /**
-     * Inserts the value into this builder.
-     *
-     * @param index  the index to add at, must be valid
-     * @param value  the value to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final int value) {
-        return insert(index, String.valueOf(value));
-    }
-
-    /**
-     * Inserts the value into this builder.
-     *
-     * @param index  the index to add at, must be valid
-     * @param value  the value to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final long value) {
-        return insert(index, String.valueOf(value));
-    }
-
-    /**
-     * Inserts the value into this builder.
-     *
-     * @param index  the index to add at, must be valid
-     * @param value  the value to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final float value) {
-        return insert(index, String.valueOf(value));
-    }
-
-    /**
-     * Inserts the value into this builder.
-     *
-     * @param index  the index to add at, must be valid
-     * @param value  the value to insert
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder insert(final int index, final double value) {
-        return insert(index, String.valueOf(value));
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Internal method to delete a range without validation.
-     *
-     * @param startIndex  the start index, must be valid
-     * @param endIndex  the end index (exclusive), must be valid
-     * @param len  the length, must be valid
-     * @throws IndexOutOfBoundsException if any index is invalid
-     */
-    private void deleteImpl(final int startIndex, final int endIndex, final int len) {
-        System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
-        size -= len;
-    }
-
-    /**
-     * Deletes the characters between the two specified indices.
-     *
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param endIndex  the end index, exclusive, must be valid except
-     *  that if too large it is treated as end of string
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder delete(final int startIndex, int endIndex) {
-        endIndex = validateRange(startIndex, endIndex);
-        final int len = endIndex - startIndex;
-        if (len > 0) {
-            deleteImpl(startIndex, endIndex, len);
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Deletes the character wherever it occurs in the builder.
-     *
-     * @param ch  the character to delete
-     * @return this, to enable chaining
-     */
-    public StrBuilder deleteAll(final char ch) {
-        for (int i = 0; i < size; i++) {
-            if (buffer[i] == ch) {
-                final int start = i;
-                while (++i < size) {
-                    if (buffer[i] != ch) {
-                        break;
-                    }
-                }
-                final int len = i - start;
-                deleteImpl(start, i, len);
-                i -= len;
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Deletes the character wherever it occurs in the builder.
-     *
-     * @param ch  the character to delete
-     * @return this, to enable chaining
-     */
-    public StrBuilder deleteFirst(final char ch) {
-        for (int i = 0; i < size; i++) {
-            if (buffer[i] == ch) {
-                deleteImpl(i, i + 1, 1);
-                break;
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Deletes the string wherever it occurs in the builder.
-     *
-     * @param str  the string to delete, null causes no action
-     * @return this, to enable chaining
-     */
-    public StrBuilder deleteAll(final String str) {
-        final int len = (str == null ? 0 : str.length());
-        if (len > 0) {
-            int index = indexOf(str, 0);
-            while (index >= 0) {
-                deleteImpl(index, index + len, len);
-                index = indexOf(str, index);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Deletes the string wherever it occurs in the builder.
-     *
-     * @param str  the string to delete, null causes no action
-     * @return this, to enable chaining
-     */
-    public StrBuilder deleteFirst(final String str) {
-        final int len = (str == null ? 0 : str.length());
-        if (len > 0) {
-            final int index = indexOf(str, 0);
-            if (index >= 0) {
-                deleteImpl(index, index + len, len);
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Deletes all parts of the builder that the matcher matches.
-     * <p>
-     * Matchers can be used to perform advanced deletion behaviour.
-     * For example you could write a matcher to delete all occurrences
-     * where the character 'a' is followed by a number.
-     *
-     * @param matcher  the matcher to use to find the deletion, null causes no action
-     * @return this, to enable chaining
-     */
-    public StrBuilder deleteAll(final StrMatcher matcher) {
-        return replace(matcher, null, 0, size, -1);
-    }
-
-    /**
-     * Deletes the first match within the builder using the specified matcher.
-     * <p>
-     * Matchers can be used to perform advanced deletion behaviour.
-     * For example you could write a matcher to delete
-     * where the character 'a' is followed by a number.
-     *
-     * @param matcher  the matcher to use to find the deletion, null causes no action
-     * @return this, to enable chaining
-     */
-    public StrBuilder deleteFirst(final StrMatcher matcher) {
-        return replace(matcher, null, 0, size, 1);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Internal method to delete a range without validation.
-     *
-     * @param startIndex  the start index, must be valid
-     * @param endIndex  the end index (exclusive), must be valid
-     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
-     * @param insertStr  the string to replace with, null means delete range
-     * @param insertLen  the length of the insert string, must be valid
-     * @throws IndexOutOfBoundsException if any index is invalid
-     */
-    private void replaceImpl(final int startIndex,
-                             final int endIndex,
-                             final int removeLen,
-                             final String insertStr,
-                             final int insertLen) {
-        final int newSize = size - removeLen + insertLen;
-        if (insertLen != removeLen) {
-            ensureCapacity(newSize);
-            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
-            size = newSize;
-        }
-        if (insertLen > 0) {
-            insertStr.getChars(0, insertLen, buffer, startIndex);
-        }
-    }
-
-    /**
-     * Replaces a portion of the string builder with another string.
-     * The length of the inserted string does not have to match the removed length.
-     *
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param endIndex  the end index, exclusive, must be valid except
-     *  that if too large it is treated as end of string
-     * @param replaceStr  the string to replace with, null means delete range
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
-        endIndex = validateRange(startIndex, endIndex);
-        final int insertLen = (replaceStr == null ? 0 : replaceStr.length());
-        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces the search character with the replace character
-     * throughout the builder.
-     *
-     * @param search  the search character
-     * @param replace  the replace character
-     * @return this, to enable chaining
-     */
-    public StrBuilder replaceAll(final char search, final char replace) {
-        if (search != replace) {
-            for (int i = 0; i < size; i++) {
-                if (buffer[i] == search) {
-                    buffer[i] = replace;
-                }
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Replaces the first instance of the search character with the
-     * replace character in the builder.
-     *
-     * @param search  the search character
-     * @param replace  the replace character
-     * @return this, to enable chaining
-     */
-    public StrBuilder replaceFirst(final char search, final char replace) {
-        if (search != replace) {
-            for (int i = 0; i < size; i++) {
-                if (buffer[i] == search) {
-                    buffer[i] = replace;
-                    break;
-                }
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces the search string with the replace string throughout the builder.
-     *
-     * @param searchStr  the search string, null causes no action to occur
-     * @param replaceStr  the replace string, null is equivalent to an empty string
-     * @return this, to enable chaining
-     */
-    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
-        final int searchLen = (searchStr == null ? 0 : searchStr.length());
-        if (searchLen > 0) {
-            final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
-            int index = indexOf(searchStr, 0);
-            while (index >= 0) {
-                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
-                index = indexOf(searchStr, index + replaceLen);
-            }
-        }
-        return this;
-    }
-
-    /**
-     * Replaces the first instance of the search string with the replace string.
-     *
-     * @param searchStr  the search string, null causes no action to occur
-     * @param replaceStr  the replace string, null is equivalent to an empty string
-     * @return this, to enable chaining
-     */
-    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
-        final int searchLen = (searchStr == null ? 0 : searchStr.length());
-        if (searchLen > 0) {
-            final int index = indexOf(searchStr, 0);
-            if (index >= 0) {
-                final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
-                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Replaces all matches within the builder with the replace string.
-     * <p>
-     * Matchers can be used to perform advanced replace behaviour.
-     * For example you could write a matcher to replace all occurrences
-     * where the character 'a' is followed by a number.
-     *
-     * @param matcher  the matcher to use to find the deletion, null causes no action
-     * @param replaceStr  the replace string, null is equivalent to an empty string
-     * @return this, to enable chaining
-     */
-    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
-        return replace(matcher, replaceStr, 0, size, -1);
-    }
-
-    /**
-     * Replaces the first match within the builder with the replace string.
-     * <p>
-     * Matchers can be used to perform advanced replace behaviour.
-     * For example you could write a matcher to replace
-     * where the character 'a' is followed by a number.
-     *
-     * @param matcher  the matcher to use to find the deletion, null causes no action
-     * @param replaceStr  the replace string, null is equivalent to an empty string
-     * @return this, to enable chaining
-     */
-    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
-        return replace(matcher, replaceStr, 0, size, 1);
-    }
-
-    // -----------------------------------------------------------------------
-    /**
-     * Advanced search and replaces within the builder using a matcher.
-     * <p>
-     * Matchers can be used to perform advanced behaviour.
-     * For example you could write a matcher to delete all occurrences
-     * where the character 'a' is followed by a number.
-     *
-     * @param matcher  the matcher to use to find the deletion, null causes no action
-     * @param replaceStr  the string to replace the match with, null is a delete
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param endIndex  the end index, exclusive, must be valid except
-     *  that if too large it is treated as end of string
-     * @param replaceCount  the number of times to replace, -1 for replace all
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if start index is invalid
-     */
-    public StrBuilder replace(
-            final StrMatcher matcher, final String replaceStr,
-            final int startIndex, int endIndex, final int replaceCount) {
-        endIndex = validateRange(startIndex, endIndex);
-        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
-    }
-
-    /**
-     * Replaces within the builder using a matcher.
-     * <p>
-     * Matchers can be used to perform advanced behaviour.
-     * For example you could write a matcher to delete all occurrences
-     * where the character 'a' is followed by a number.
-     *
-     * @param matcher  the matcher to use to find the deletion, null causes no action
-     * @param replaceStr  the string to replace the match with, null is a delete
-     * @param from  the start index, must be valid
-     * @param to  the end index (exclusive), must be valid
-     * @param replaceCount  the number of times to replace, -1 for replace all
-     * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException if any index is invalid
-     */
-    private StrBuilder replaceImpl(
-            final StrMatcher matcher, final String replaceStr,
-            final int from, int to, int replaceCount) {
-        if (matcher == null || size == 0) {
-            return this;
-        }
-        final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
-        for (int i = from; i < to && replaceCount != 0; i++) {
-            final char[] buf = buffer;
-            final int removeLen = matcher.isMatch(buf, i, from, to);
-            if (removeLen > 0) {
-                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
-                to = to - removeLen + replaceLen;
-                i = i + replaceLen - 1;
-                if (replaceCount > 0) {
-                    replaceCount--;
-                }
-            }
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Reverses the string builder placing each character in the opposite index.
-     *
-     * @return this, to enable chaining
-     */
-    public StrBuilder reverse() {
-        if (size == 0) {
-            return this;
-        }
-
-        final int half = size / 2;
-        final char[] buf = buffer;
-        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
-            final char swap = buf[leftIdx];
-            buf[leftIdx] = buf[rightIdx];
-            buf[rightIdx] = swap;
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Trims the builder by removing characters less than or equal to a space
-     * from the beginning and end.
-     *
-     * @return this, to enable chaining
-     */
-    public StrBuilder trim() {
-        if (size == 0) {
-            return this;
-        }
-        int len = size;
-        final char[] buf = buffer;
-        int pos = 0;
-        while (pos < len && buf[pos] <= ' ') {
-            pos++;
-        }
-        while (pos < len && buf[len - 1] <= ' ') {
-            len--;
-        }
-        if (len < size) {
-            delete(len, size);
-        }
-        if (pos > 0) {
-            delete(0, pos);
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Checks whether this builder starts with the specified string.
-     * <p>
-     * Note that this method handles null input quietly, unlike String.
-     *
-     * @param str  the string to search for, null returns false
-     * @return true if the builder starts with the string
-     */
-    public boolean startsWith(final String str) {
-        if (str == null) {
-            return false;
-        }
-        final int len = str.length();
-        if (len == 0) {
-            return true;
-        }
-        if (len > size) {
-            return false;
-        }
-        for (int i = 0; i < len; i++) {
-            if (buffer[i] != str.charAt(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Checks whether this builder ends with the specified string.
-     * <p>
-     * Note that this method handles null input quietly, unlike String.
-     *
-     * @param str  the string to search for, null returns false
-     * @return true if the builder ends with the string
-     */
-    public boolean endsWith(final String str) {
-        if (str == null) {
-            return false;
-        }
-        final int len = str.length();
-        if (len == 0) {
-            return true;
-        }
-        if (len > size) {
-            return false;
-        }
-        int pos = size - len;
-        for (int i = 0; i < len; i++, pos++) {
-            if (buffer[pos] != str.charAt(i)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public CharSequence subSequence(final int startIndex, final int endIndex) {
-      if (startIndex < 0) {
-          throw new StringIndexOutOfBoundsException(startIndex);
-      }
-      if (endIndex > size) {
-          throw new StringIndexOutOfBoundsException(endIndex);
-      }
-      if (startIndex > endIndex) {
-          throw new StringIndexOutOfBoundsException(endIndex - startIndex);
-      }
-      return substring(startIndex, endIndex);
-    }
-
-    /**
-     * Extracts a portion of this string builder as a string.
-     *
-     * @param start  the start index, inclusive, must be valid
-     * @return the new string
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public String substring(final int start) {
-        return substring(start, size);
-    }
-
-    /**
-     * Extracts a portion of this string builder as a string.
-     * <p>
-     * Note: This method treats an endIndex greater than the length of the
-     * builder as equal to the length of the builder, and continues
-     * without error, unlike StringBuffer or String.
-     *
-     * @param startIndex  the start index, inclusive, must be valid
-     * @param endIndex  the end index, exclusive, must be valid except
-     *  that if too large it is treated as end of string
-     * @return the new string
-     * @throws IndexOutOfBoundsException if the index is invalid
-     */
-    public String substring(final int startIndex, int endIndex) {
-        endIndex = validateRange(startIndex, endIndex);
-        return new String(buffer, startIndex, endIndex - startIndex);
-    }
-
-    /**
-     * Extracts the leftmost characters from the string builder without
-     * throwing an exception.
-     * <p>
-     * This method extracts the left <code>length</code> characters from
-     * the builder. If this many characters are not available, the whole
-     * builder is returned. Thus the returned string may be shorter than the
-     * length requested.
-     *
-     * @param length  the number of characters to extract, negative returns empty string
-     * @return the new string
-     */
-    public String leftString(final int length) {
-        if (length <= 0) {
-            return "";
-        } else if (length >= size) {
-            return new String(buffer, 0, size);
-        } else {
-            return new String(buffer, 0, length);
-        }
-    }
-
-    /**
-     * Extracts the rightmost characters from the string builder without
-     * throwing an exception.
-     * <p>
-     * This method extracts the right <code>length</code> characters from
-     * the builder. If this many characters are not available, the whole
-     * builder is returned. Thus the returned string may be shorter than the
-     * length requested.
-     *
-     * @param length  the number of characters to extract, negative returns empty string
-     * @return the new string
-     */
-    public String rightString(final int length) {
-        if (length <= 0) {
-            return "";
-        } else if (length >= size) {
-            return new String(buffer, 0, size);
-        } else {
-            return new String(buffer, size - length, length);
-        }
-    }
-
-    /**
-     * Extracts some characters from the middle of the string builder without
-     * throwing an exception.
-     * <p>
-     * This method extracts <code>length</code> characters from the builder
-     * at the specified index.
-     * If the index is negative it is treated as zero.
-     * If the index is greater than the builder size, it is treated as the builder size.
-     * If the length is negative, the empty string is returned.
-     * If insufficient characters are available in the builder, as much as possible is returned.
-     * Thus the returned string may be shorter than the length requested.
-     *
-     * @param index  the index to start at, negative means zero
-     * @param length  the number of characters to extract, negative returns empty string
-     * @return the new string
-     */
-    public String midString(int index, final int length) {
-        if (index < 0) {
-            index = 0;
-        }
-        if (length <= 0 || index >= size) {
-            return "";
-        }
-        if (size <= index + length) {
-            return new String(buffer, index, size - index);
-        }
-        return new String(buffer, index, length);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Checks if the string builder contains the specified char.
-     *
-     * @param ch  the character to find
-     * @return true if the builder contains the character
-     */
-    public boolean contains(final char ch) {
-        final char[] thisBuf = buffer;
-        for (int i = 0; i < this.size; i++) {
-            if (thisBuf[i] == ch) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Checks if the string builder contains the specified string.
-     *
-     * @param str  the string to find
-     * @return true if the builder contains the string
-     */
-    public boolean contains(final String str) {
-        return indexOf(str, 0) >= 0;
-    }
-
-    /**
-     * Checks if the string builder contains a string matched using the
-     * specified matcher.
-     * <p>
-     * Matchers can be used to perform advanced searching behaviour.
-     * For example you could write a matcher to search for the character
-     * 'a' followed by a number.
-     *
-     * @param matcher  the matcher to use, null returns -1
-     * @return true if the matcher finds a match in the builder
-     */
-    public boolean contains(final StrMatcher matcher) {
-        return indexOf(matcher, 0) >= 0;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Searches the string builder to find the first reference to the specified char.
-     *
-     * @param ch  the character to find
-     * @return the first index of the character, or -1 if not found
-     */
-    public int indexOf(final char ch) {
-        return indexOf(ch, 0);
-    }
-
-    /**
-     * Searches the string builder to find the first reference to the specified char.
-     *
-     * @param ch  the character to find
-     * @param startIndex  the index to start at, invalid index rounded to edge
-     * @return the first index of the character, or -1 if not found
-     */
-    public int indexOf(final char ch, int startIndex) {
-        startIndex = (startIndex < 0 ? 0 : startIndex);
-        if (startIndex >= size) {
-            return -1;
-        }
-        final char[] thisBuf = buffer;
-        for (int i = startIndex; i < size; i++) {
-            if (thisBuf[i] == ch) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Searches the string builder to find the first reference to the specified string.
-     * <p>
-     * Note that a null input string will return -1, whereas the JDK throws an exception.
-     *
-     * @param str  the string to find, null returns -1
-     * @return the first index of the string, or -1 if not found
-     */
-    public int indexOf(final String str) {
-        return indexOf(str, 0);
-    }
-
-    /**
-     * Searches the string builder to find the first reference to the specified
-     * string starting searching from the given index.
-     * <p>
-     * Note that a null input string will return -1, whereas the JDK throws an exception.
-     *
-     * @param str  the string to find, null returns -1
-     * @param startIndex  the index to start at, invalid index rounded to edge
-     * @return the first index of the string, or -1 if not found
-     */
-    public int indexOf(final String str, int startIndex) {
-        startIndex = (startIndex < 0 ? 0 : startIndex);
-        if (str == null || startIndex >= size) {
-            return -1;
-        }
-        final int strLen = str.length();
-        if (strLen == 1) {
-            return indexOf(str.charAt(0), startIndex);
-        }
-        if (strLen == 0) {
-            return startIndex;
-        }
-        if (strLen > size) {
-            return -1;
-        }
-        final char[] thisBuf = buffer;
-        final int len = size - strLen + 1;
-        outer:
-        for (int i = startIndex; i < len; i++) {
-            for (int j = 0; j < strLen; j++) {
-                if (str.charAt(j) != thisBuf[i + j]) {
-                    continue outer;
-                }
-            }
-            return i;
-        }
-        return -1;
-    }
-
-    /**
-     * Searches the string builder using the matcher to find the first match.
-     * <p>
-     * Matchers can be used to perform advanced searching behaviour.
-     * For example you could write a matcher to find the character 'a'
-     * followed by a number.
-     *
-     * @param matcher  the matcher to use, null returns -1
-     * @return the first index matched, or -1 if not found
-     */
-    public int indexOf(final StrMatcher matcher) {
-        return indexOf(matcher, 0);
-    }
-
-    /**
-     * Searches the string builder using the matcher to find the first
-     * match searching from the given index.
-     * <p>
-     * Matchers can be used to perform advanced searching behaviour.
-     * For example you could write a matcher to find the character 'a'
-     * followed by a number.
-     *
-     * @param matcher  the matcher to use, null returns -1
-     * @param startIndex  the index to start at, invalid index rounded to edge
-     * @return the first index matched, or -1 if not found
-     */
-    public int indexOf(final StrMatcher matcher, int startIndex) {
-        startIndex = (startIndex < 0 ? 0 : startIndex);
-        if (matcher == null || startIndex >= size) {
-            return -1;
-        }
-        final int len = size;
-        final char[] buf = buffer;
-        for (int i = startIndex; i < len; i++) {
-            if (matcher.is

<TRUNCATED>

[06/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaperTest.java b/src/test/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaperTest.java
deleted file mode 100644
index 9e30f73..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaperTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import java.io.UnsupportedEncodingException;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link JavaUnicodeEscaper}.
- */
-public class JavaUnicodeEscaperTest {
-
-    @Test
-    public void testBelow() {
-        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.below('F');
-
-        final String input = "ADFGZ";
-        final String result = jue.translate(input);
-        assertEquals("Failed to escape Unicode characters via the below method", "\\u0041\\u0044FGZ", result);
-    }
-
-    @Test
-    public void testBetween() {
-        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.between('F', 'L');
-
-        final String input = "ADFGZ";
-        final String result = jue.translate(input);
-        assertEquals("Failed to escape Unicode characters via the between method", "AD\\u0046\\u0047Z", result);
-    }
-
-    @Test
-    public void testAbove() {
-        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.above('F');
-
-        final String input = "ADFGZ";
-        final String result = jue.translate(input);
-        assertEquals("Failed to escape Unicode characters via the above method", "ADF\\u0047\\u005A", result);
-    }
-
-    @Test
-    public void testToUtf16Escape() throws UnsupportedEncodingException {
-        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.below('F');
-        // According to https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B10000..U.2B10FFFF,
-        // Character ?,	U+24B62,	Binary Code Point 0010 0100 1011 0110 0010,	Binary UTF-167 1101 1000 0101 0010 1101 1111 0110 0010, UTF-16 Hex Code Units D852 DF62
-        final String encoding = jue.toUtf16Escape(Integer.parseInt("024B62", 16));
-        assertEquals("\\uD852\\uDF62",encoding);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/LookupTranslatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/LookupTranslatorTest.java b/src/test/java/org/apache/commons/text/beta/translate/LookupTranslatorTest.java
deleted file mode 100644
index 384f58e..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/LookupTranslatorTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link LookupTranslator}.
- */
-public class LookupTranslatorTest  {
-
-    @Test
-    public void testBasicLookup() throws IOException {
-        final Map<CharSequence, CharSequence> translatorMap = new HashMap<>();
-        translatorMap.put("one", "two");
-        final LookupTranslator lt = new LookupTranslator(translatorMap);
-        final StringWriter out = new StringWriter();
-        final int result = lt.translate("one", 0, out);
-        assertEquals("Incorrect codepoint consumption", 3, result);
-        assertEquals("Incorrect value", "two", out.toString());
-    }
-
-    // Tests: https://issues.apache.org/jira/browse/LANG-882
-    @Test
-    public void testLang882() throws IOException {
-        final Map<CharSequence, CharSequence> translatorMap = new HashMap<>();
-        translatorMap.put(new StringBuffer("one"), new StringBuffer("two"));
-        final LookupTranslator lt = new LookupTranslator(translatorMap);
-        final StringWriter out = new StringWriter();
-        final int result = lt.translate(new StringBuffer("one"), 0, out);
-        assertEquals("Incorrect codepoint consumption", 3, result);
-        assertEquals("Incorrect value", "two", out.toString());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/NumericEntityEscaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/NumericEntityEscaperTest.java b/src/test/java/org/apache/commons/text/beta/translate/NumericEntityEscaperTest.java
deleted file mode 100644
index 9918885..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/NumericEntityEscaperTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link NumericEntityEscaper}.
- */
-public class NumericEntityEscaperTest  {
-
-    @Test
-    public void testBelow() {
-        final NumericEntityEscaper nee = NumericEntityEscaper.below('F');
-
-        final String input = "ADFGZ";
-        final String result = nee.translate(input);
-        assertEquals("Failed to escape numeric entities via the below method", "&#65;&#68;FGZ", result);
-    }
-
-    @Test
-    public void testBetween() {
-        final NumericEntityEscaper nee = NumericEntityEscaper.between('F', 'L');
-
-        final String input = "ADFGZ";
-        final String result = nee.translate(input);
-        assertEquals("Failed to escape numeric entities via the between method", "AD&#70;&#71;Z", result);
-    }
-
-    @Test
-    public void testAbove() {
-        final NumericEntityEscaper nee = NumericEntityEscaper.above('F');
-
-        final String input = "ADFGZ";
-        final String result = nee.translate(input);
-        assertEquals("Failed to escape numeric entities via the above method", "ADF&#71;&#90;", result);
-    }
-
-    // See LANG-617
-    @Test
-    public void testSupplementary() {
-        final NumericEntityEscaper nee = new NumericEntityEscaper();
-        final String input = "\uD803\uDC22";
-        final String expected = "&#68642;";
-
-        final String result = nee.translate(input);
-        assertEquals("Failed to escape numeric entities supplementary characters", expected, result);
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/NumericEntityUnescaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/NumericEntityUnescaperTest.java b/src/test/java/org/apache/commons/text/beta/translate/NumericEntityUnescaperTest.java
deleted file mode 100644
index ba5b0ce..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/NumericEntityUnescaperTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-/**
- * Unit tests for {@link NumericEntityUnescaper}.
- */
-public class NumericEntityUnescaperTest  {
-
-    @Test
-    public void testSupplementaryUnescaping() {
-        final NumericEntityUnescaper neu = new NumericEntityUnescaper();
-        final String input = "&#68642;";
-        final String expected = "\uD803\uDC22";
-
-        final String result = neu.translate(input);
-        assertEquals("Failed to unescape numeric entities supplementary characters", expected, result);
-    }
-
-    @Test
-    public void testOutOfBounds() {
-        final NumericEntityUnescaper neu = new NumericEntityUnescaper();
-
-        assertEquals("Failed to ignore when last character is &", "Test &", neu.translate("Test &"));
-        assertEquals("Failed to ignore when last character is &", "Test &#", neu.translate("Test &#"));
-        assertEquals("Failed to ignore when last character is &", "Test &#x", neu.translate("Test &#x"));
-        assertEquals("Failed to ignore when last character is &", "Test &#X", neu.translate("Test &#X"));
-    }
-
-    @Test
-    public void testUnfinishedEntity() {
-        // parse it
-        NumericEntityUnescaper neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional);
-        String input = "Test &#x30 not test";
-        String expected = "Test \u0030 not test";
-
-        String result = neu.translate(input);
-        assertEquals("Failed to support unfinished entities (i.e. missing semi-colon)", expected, result);
-
-        // ignore it
-        neu = new NumericEntityUnescaper();
-        input = "Test &#x30 not test";
-        expected = input;
-
-        result = neu.translate(input);
-        assertEquals("Failed to ignore unfinished entities (i.e. missing semi-colon)", expected, result);
-
-        // fail it
-        neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon);
-        input = "Test &#x30 not test";
-
-        try {
-            result = neu.translate(input);
-            fail("IllegalArgumentException expected");
-        } catch(final IllegalArgumentException iae) {
-            // expected
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/OctalUnescaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/OctalUnescaperTest.java b/src/test/java/org/apache/commons/text/beta/translate/OctalUnescaperTest.java
deleted file mode 100644
index 9f6442f..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/OctalUnescaperTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link OctalUnescaper}.
- */
-public class OctalUnescaperTest {
-
-    @Test
-    public void testBetween() {
-        final OctalUnescaper oue = new OctalUnescaper();   //.between("1", "377");
-
-        String input = "\\45";
-        String result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\45", result);
-
-        input = "\\377";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\377", result);
-
-        input = "\\377 and";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\377 and", result);
-
-        input = "\\378 and";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\37" + "8 and", result);
-
-        input = "\\378";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\37" + "8", result);
-
-        input = "\\1";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\1", result);
-
-        input = "\\036";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\036", result);
-
-        input = "\\0365";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\036" + "5", result);
-
-        input = "\\003";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\003", result);
-
-        input = "\\0003";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\000" + "3", result);
-
-        input = "\\279";
-        result = oue.translate(input);
-        assertEquals("Failed to unescape octal characters via the between method", "\279", result);
-
-        input = "\\999";
-        result = oue.translate(input);
-        assertEquals("Failed to ignore an out of range octal character via the between method", "\\999", result);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/SinglePassTranslatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/SinglePassTranslatorTest.java b/src/test/java/org/apache/commons/text/beta/translate/SinglePassTranslatorTest.java
deleted file mode 100644
index 6a77350..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/SinglePassTranslatorTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit test for {@link SinglePassTranslator}
- */
-public class SinglePassTranslatorTest {
-
-    private final SinglePassTranslator dummyTranslator = new SinglePassTranslator() {
-        @Override
-        void translateWhole(final CharSequence input, final Writer out) throws IOException {
-        }
-    };
-
-    private StringWriter out;
-
-    @Before
-    public void before() {
-         out = new StringWriter();
-    }
-
-    @Test
-    public void codePointsAreReturned() throws Exception {
-        assertEquals(0, dummyTranslator.translate("", 0, out));
-        assertEquals(3, dummyTranslator.translate("abc", 0, out));
-        assertEquals(7, dummyTranslator.translate("abcdefg", 0, out));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void indexIsValidated() throws Exception {
-        dummyTranslator.translate("abc", 1, out);
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/UnicodeEscaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/UnicodeEscaperTest.java b/src/test/java/org/apache/commons/text/beta/translate/UnicodeEscaperTest.java
deleted file mode 100644
index 7fe28ea..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/UnicodeEscaperTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link UnicodeEscaper}.
- */
-public class UnicodeEscaperTest  {
-
-    @Test
-    public void testBelow() {
-        final UnicodeEscaper ue = UnicodeEscaper.below('F');
-
-        final String input = "ADFGZ";
-        final String result = ue.translate(input);
-        assertEquals("Failed to escape Unicode characters via the below method", "\\u0041\\u0044FGZ", result);
-    }
-
-    @Test
-    public void testBetween() {
-        final UnicodeEscaper ue = UnicodeEscaper.between('F', 'L');
-
-        final String input = "ADFGZ";
-        final String result = ue.translate(input);
-        assertEquals("Failed to escape Unicode characters via the between method", "AD\\u0046\\u0047Z", result);
-    }
-
-    @Test
-    public void testAbove() {
-        final UnicodeEscaper ue = UnicodeEscaper.above('F');
-
-        final String input = "ADFGZ";
-        final String result = ue.translate(input);
-        assertEquals("Failed to escape Unicode characters via the above method", "ADF\\u0047\\u005A", result);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnescaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnescaperTest.java b/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnescaperTest.java
deleted file mode 100644
index 9a74b30..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnescaperTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-/**
- * Unit tests for {@link UnicodeEscaper}.
- */
-public class UnicodeUnescaperTest {
-
-    // Requested in LANG-507
-    @Test
-    public void testUPlus() {
-        final UnicodeUnescaper uu = new UnicodeUnescaper();
-
-        final String input = "\\u+0047";
-        assertEquals("Failed to unescape Unicode characters with 'u+' notation", "G", uu.translate(input));
-    }
-
-    @Test
-    public void testUuuuu() {
-        final UnicodeUnescaper uu = new UnicodeUnescaper();
-
-        final String input = "\\uuuuuuuu0047";
-        final String result = uu.translate(input);
-        assertEquals("Failed to unescape Unicode characters with many 'u' characters", "G", result);
-    }
-
-    @Test
-    public void testLessThanFour() {
-        final UnicodeUnescaper uu = new UnicodeUnescaper();
-
-        final String input = "\\0047\\u006";
-        try {
-            uu.translate(input);
-            fail("A lack of digits in a Unicode escape sequence failed to throw an exception");
-        } catch(final IllegalArgumentException iae) {
-            // expected
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemoverTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemoverTest.java b/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemoverTest.java
deleted file mode 100644
index 3d30cee..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemoverTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import java.io.CharArrayWriter;
-import java.io.IOException;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link UnicodeUnpairedSurrogateRemover}.
- */
-public class UnicodeUnpairedSurrogateRemoverTest {
-    final UnicodeUnpairedSurrogateRemover subject = new UnicodeUnpairedSurrogateRemover();
-    final CharArrayWriter writer = new CharArrayWriter(); // nothing is ever written to it
-    
-    @Test
-    public void testValidCharacters() throws IOException {
-        assertEquals(false, subject.translate(0xd7ff, writer));
-        assertEquals(false, subject.translate(0xe000, writer));
-        assertEquals(0, writer.size());
-    }
-    
-    @Test
-    public void testInvalidCharacters() throws IOException {
-        assertEquals(true, subject.translate(0xd800, writer));
-        assertEquals(true, subject.translate(0xdfff, writer));
-        assertEquals(0, writer.size());
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/diff/ReplacementsFinderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/diff/ReplacementsFinderTest.java b/src/test/java/org/apache/commons/text/diff/ReplacementsFinderTest.java
new file mode 100644
index 0000000..eea6f9f
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/diff/ReplacementsFinderTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+/**
+ * Tests for the ReplacementsFinder.
+ */
+@RunWith(Parameterized.class)
+public class ReplacementsFinderTest {
+    private SimpleHandler handler = null;
+    private final String left;
+    private final String right;
+    private final int skipped;
+    private final Character[] from;
+    private final Character[] to;
+    @Before
+    public void setUp() {
+        handler = new SimpleHandler();
+    }
+    @Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+            {
+                "branco",
+                "blanco",
+                1,
+                new Character[] {'r'},
+                new Character[] {'l'}},
+            {
+                "test the blocks before you use it",
+                "try the blocks before you put it",
+                25,
+                new Character[] {'e', 's', 't', 's', 'e'},
+                new Character[] {'r', 'y', 'p', 't'}
+            }
+        });
+    }
+    public ReplacementsFinderTest(final String left, final String right, final int skipped,
+            final Character[] from, final Character[] to) {
+        this.left = left;
+        this.right = right;
+        this.skipped = skipped;
+        this.from = from;
+        this.to = to;
+    }
+    @Test
+    public void testReplacementsHandler() {
+        final StringsComparator sc = new StringsComparator(left, right);
+        final ReplacementsFinder<Character> replacementFinder = new ReplacementsFinder<>(handler);
+        sc.getScript().visit(replacementFinder);
+        assertEquals("Skipped characters do not match", skipped, handler.getSkipped());
+        assertArrayEquals("From characters do not match", from,
+                handler.getFrom().toArray(new Character[0]));
+        assertArrayEquals("To characters do not match", to,
+                handler.getTo().toArray(new Character[0]));
+    }
+    // Helper RecplacementsHandler implementation for testing
+    private class SimpleHandler implements ReplacementsHandler<Character> {
+        private int skipped;
+        private final List<Character> from;
+        private final List<Character> to;
+        public SimpleHandler() {
+            skipped = 0;
+            from = new ArrayList<>();
+            to = new ArrayList<>();
+        }
+        public int getSkipped() {
+            return skipped;
+        }
+        public List<Character> getFrom() {
+            return from;
+        }
+        public List<Character> getTo() {
+            return to;
+        }
+        @Override
+        public void handleReplacement(final int skipped, final List<Character> from, final List<Character> to) {
+            this.skipped += skipped;
+            this.from.addAll(from);
+            this.to.addAll(to);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java b/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java
new file mode 100644
index 0000000..ddf0f2f
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+/**
+ * Tests for the StringsComparator.
+ */
+public class StringsComparatorTest {
+    private List<String> before;
+    private List<String> after;
+    private int[]        length;
+    private int[]        lcs;
+    @Test
+    public void testLength() {
+        for (int i = 0; i < before.size(); ++i) {
+            final StringsComparator comparator =  new StringsComparator(before.get(i), after.get(i));
+            Assert.assertEquals(length[i], comparator.getScript().getModifications());
+        }
+    }
+    @Test
+    public void testLongestCommonSubsequence() {
+        for (int i = 0; i < before.size(); ++i) {
+            final StringsComparator comparator =  new StringsComparator(before.get(i), after.get(i));
+            Assert.assertEquals(lcs[i], comparator.getScript().getLCSLength());
+        }
+    }
+    @Test
+    public void testExecution() {
+        for (int i = 0; i < before.size(); ++i) {
+            final ExecutionVisitor<Character> ev = new ExecutionVisitor<>();
+            new StringsComparator(before.get(i), after.get(i)).getScript().visit(ev);
+            Assert.assertEquals(after.get(i), ev.getString());
+        }
+    }
+    private class ExecutionVisitor<T> implements CommandVisitor<T> {
+        private final StringBuilder v;
+        public ExecutionVisitor() {
+            v = new StringBuilder();
+        }
+        @Override
+        public void visitInsertCommand(final T object) {
+            v.append(object);
+        }
+        @Override
+        public void visitKeepCommand(final T object) {
+            v.append(object);
+        }
+        @Override
+        public void visitDeleteCommand(final T object) {
+        }
+        public String getString() {
+            return v.toString();
+        }
+    }
+    @Before
+    public void setUp() {
+        before = Arrays.asList(
+            "bottle",
+            "nematode knowledge",
+            "",
+            "aa",
+            "prefixed string",
+            "ABCABBA",
+            "glop glop",
+            "coq",
+            "spider-man");
+        after = Arrays.asList(
+            "noodle",
+            "empty bottle",
+            "",
+            "C",
+            "prefix",
+            "CBABAC",
+            "pas glop pas glop",
+            "ane",
+            "klingon");
+        length = new int[] {
+            6,
+            16,
+            0,
+            3,
+            9,
+            5,
+            8,
+            6,
+            13
+        };
+        lcs = new int[] {
+            3,
+            7,
+            0,
+            0,
+            6,
+            4,
+            9,
+            0,
+            2
+        };
+    }
+    @After
+    public void tearDown() {
+        before = null;
+        after  = null;
+        length = null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/CosineDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/CosineDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/CosineDistanceTest.java
new file mode 100644
index 0000000..cd39e84
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/CosineDistanceTest.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link CosineSimilarity}.
+ */
+public class CosineDistanceTest {
+
+    /**
+     * Cosine distance under test.
+     */
+    private static CosineDistance cosineDistance;
+
+    /**
+     * Creates the cosine distance object used throughout the tests.
+     */
+    @BeforeClass
+    public static void setUp() {
+        cosineDistance = new CosineDistance();
+    }
+
+    /**
+     * Tests the cosine distance with several inputs.
+     */
+    @Test
+    public void testCosineDistance() {
+        assertEquals(Double.valueOf(0.5d), roundValue(cosineDistance.apply("the house", "da house")));
+        assertEquals(Double.valueOf(0.0d), roundValue(cosineDistance.apply("AB", "AB")));
+        assertEquals(Double.valueOf(1.0d), roundValue(cosineDistance.apply("AB", "BA")));
+        assertEquals(Double.valueOf(0.08d), roundValue(cosineDistance.apply(
+                "the boy was from tamana shi, kumamoto ken, and the girl was from rio de janeiro, rio",
+                "the boy was from tamana shi, kumamoto, and the boy was from rio de janeiro, rio de janeiro")));
+    }
+
+    // --- Utility methods
+
+    /**
+     * Rounds up a value.
+     *
+     * @param value a value
+     * @return rounded up value
+     */
+    private Double roundValue(final Double value) {
+        return (Double) new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/FuzzyScoreTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/FuzzyScoreTest.java b/src/test/java/org/apache/commons/text/similarity/FuzzyScoreTest.java
new file mode 100644
index 0000000..22621f2
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/FuzzyScoreTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Locale;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link FuzzyScore}.
+ */
+public class FuzzyScoreTest {
+
+    private static final FuzzyScore ENGLISH_SCORE = new FuzzyScore(Locale.ENGLISH);
+
+    @Test
+    public void testGetFuzzyScore() throws Exception {
+        assertEquals(0, (int) ENGLISH_SCORE.fuzzyScore("", ""));
+        assertEquals(0, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "b"));
+        assertEquals(1, (int) ENGLISH_SCORE.fuzzyScore("Room", "o"));
+        assertEquals(1, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "w"));
+        assertEquals(2, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "ws"));
+        assertEquals(4, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "wo"));
+        assertEquals(3, (int) ENGLISH_SCORE.fuzzyScore(
+            "Apache Software Foundation", "asf"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFuzzyScore_StringNullLocale() throws Exception {
+        ENGLISH_SCORE.fuzzyScore("not null", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFuzzyScore_NullStringLocale() throws Exception {
+        ENGLISH_SCORE.fuzzyScore(null, "not null");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFuzzyScore_NullNullLocale() throws Exception {
+        ENGLISH_SCORE.fuzzyScore(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingLocale() throws Exception {
+        new FuzzyScore((Locale) null);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/HammingDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/HammingDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/HammingDistanceTest.java
new file mode 100644
index 0000000..93c00a7
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/HammingDistanceTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link HammingDistance}.
+ */
+public class HammingDistanceTest {
+
+    private static HammingDistance distance;
+
+    @BeforeClass
+    public static void setUp() {
+        distance = new HammingDistance();
+    }
+
+    @Test
+    public void testHammingDistance() {
+        assertEquals(Integer.valueOf(0), distance.apply("", ""));
+        assertEquals(Integer.valueOf(0), distance.apply("pappa", "pappa"));
+        assertEquals(Integer.valueOf(1), distance.apply("papaa", "pappa"));
+        assertEquals(Integer.valueOf(3), distance.apply("karolin", "kathrin"));
+        assertEquals(Integer.valueOf(3), distance.apply("karolin", "kerstin"));
+        assertEquals(Integer.valueOf(2), distance.apply("1011101", "1001001"));
+        assertEquals(Integer.valueOf(3), distance.apply("2173896", "2233796"));
+        assertEquals(Integer.valueOf(2), distance.apply("ATCG", "ACCC"));
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testHammingDistance_nullLeftValue() {
+        distance.apply(null, "");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testHammingDistance_nullRightValue() {
+        distance.apply("", null);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/JaccardDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/JaccardDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/JaccardDistanceTest.java
new file mode 100644
index 0000000..47be780
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/JaccardDistanceTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link JaccardDistance}.
+ */
+public class JaccardDistanceTest {
+
+    private static JaccardDistance classBeingTested;
+    
+    @BeforeClass
+    public static void setUp() {
+        classBeingTested = new JaccardDistance();
+    }
+
+    @Test
+    public void testGettingJaccardDistance() {
+        assertEquals(1.00d, classBeingTested.apply("", ""), 0.0d);
+        assertEquals(1.00d, classBeingTested.apply("left", ""), 0.0d);
+        assertEquals(1.00d, classBeingTested.apply("", "right"), 0.0d);
+        assertEquals(0.25d, classBeingTested.apply("frog", "fog"), 0.0d);
+        assertEquals(1.00d, classBeingTested.apply("fly", "ant"), 0.0d);
+        assertEquals(0.78d, classBeingTested.apply("elephant", "hippo"), 0.0d);
+        assertEquals(0.36d, classBeingTested.apply("ABC Corporation", "ABC Corp"), 0.0d);
+        assertEquals(0.24d, classBeingTested.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.0d);
+        assertEquals(0.11d, classBeingTested.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.0d);
+        assertEquals(0.10d, classBeingTested.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.0d);
+        assertEquals(0.87d, classBeingTested.apply("left", "right"), 0.0d);
+        assertEquals(0.87d, classBeingTested.apply("leettteft", "ritttght"), 0.0d);
+        assertEquals(0.0d, classBeingTested.apply("the same string", "the same string"), 0.0d);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingJaccardDistanceNullNull() throws Exception {
+        classBeingTested.apply(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingJaccardDistanceStringNull() throws Exception {
+        classBeingTested.apply(" ", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingJaccardDistanceNullString() throws Exception {
+        classBeingTested.apply(null, "right");
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityTest.java b/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityTest.java
new file mode 100644
index 0000000..dddfe13
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityTest.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link JaccardSimilarity}.
+ */
+public class JaccardSimilarityTest {
+
+    private static JaccardSimilarity classBeingTested;
+    
+    @BeforeClass
+    public static void setUp() {
+        classBeingTested = new JaccardSimilarity();
+    }
+
+    @Test
+    public void testGettingJaccardSimilarity() {
+        assertEquals(0.00d, classBeingTested.apply("", ""), 0.0d);
+        assertEquals(0.00d, classBeingTested.apply("left", ""), 0.0d);
+        assertEquals(0.00d, classBeingTested.apply("", "right"), 0.0d);
+        assertEquals(0.75d, classBeingTested.apply("frog", "fog"), 0.0d);
+        assertEquals(0.00d, classBeingTested.apply("fly", "ant"), 0.0d);
+        assertEquals(0.22d, classBeingTested.apply("elephant", "hippo"), 0.0d);
+        assertEquals(0.64d, classBeingTested.apply("ABC Corporation", "ABC Corp"), 0.0d);
+        assertEquals(0.76d, classBeingTested.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.0d);
+        assertEquals(0.89d, classBeingTested.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.0d);
+        assertEquals(0.9d, classBeingTested.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.0d);
+        assertEquals(0.13d, classBeingTested.apply("left", "right"), 0.0d);
+        assertEquals(0.13d, classBeingTested.apply("leettteft", "ritttght"), 0.0d);
+        assertEquals(1.0d, classBeingTested.apply("the same string", "the same string"), 0.0d);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingJaccardSimilarityNullNull() throws Exception {
+        classBeingTested.apply(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingJaccardSimilarityStringNull() throws Exception {
+        classBeingTested.apply(" ", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingJaccardSimilarityNullString() throws Exception {
+        classBeingTested.apply(null, "right");
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/JaroWinklerDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/JaroWinklerDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/JaroWinklerDistanceTest.java
new file mode 100644
index 0000000..84276f1
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/JaroWinklerDistanceTest.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link JaroWinklerDistance}.
+ */
+public class JaroWinklerDistanceTest {
+
+    private static JaroWinklerDistance distance;
+    
+    @BeforeClass
+    public static void setUp() {
+        distance = new JaroWinklerDistance();
+    }
+    
+    @Test
+    public void testGetJaroWinklerDistance_StringString() {
+        assertEquals(0.93d, (double) distance.apply("frog", "fog"), 0.0d);
+        assertEquals(0.0d, (double) distance.apply("fly", "ant"), 0.0d);
+        assertEquals(0.44d, (double) distance.apply("elephant", "hippo"), 0.0d);
+        assertEquals(0.93d, (double) distance.apply("ABC Corporation", "ABC Corp"), 0.0d);
+        assertEquals(0.95d, (double) distance.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.0d);
+        assertEquals(0.92d, (double) distance.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.0d);
+        assertEquals(0.88d, (double) distance.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.0d);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetJaroWinklerDistance_NullNull() throws Exception {
+        distance.apply(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetJaroWinklerDistance_StringNull() throws Exception {
+        distance.apply(" ", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetJaroWinklerDistance_NullString() throws Exception {
+        distance.apply(null, "clear");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/LevenshteinDetailedDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/LevenshteinDetailedDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/LevenshteinDetailedDistanceTest.java
new file mode 100644
index 0000000..93eea39
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/LevenshteinDetailedDistanceTest.java
@@ -0,0 +1,402 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class LevenshteinDetailedDistanceTest {
+
+    private static final LevenshteinDetailedDistance UNLIMITED_DISTANCE = new LevenshteinDetailedDistance();
+
+    @Test
+    public void testGetLevenshteinDetailedDistance_StringString() {
+        LevenshteinResults result = UNLIMITED_DISTANCE.apply("", "");
+        assertEquals(0, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("", "a");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(1, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("aaapppp", "");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(7, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("frog", "fog");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(1, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("fly", "ant");
+        assertEquals(3, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(3, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("elephant", "hippo");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(3, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("hippo", "elephant");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("hippo", "zzzzzzzz");
+        assertEquals(8, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(5, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("zzzzzzzz", "hippo");
+        assertEquals(8, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(3, (int) result.getDeleteCount());
+        assertEquals(5, (int) result.getSubstituteCount());
+
+        result = UNLIMITED_DISTANCE.apply("hello", "hallo");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+    }
+    
+    @Test
+    public void testEquals() {
+     final LevenshteinDetailedDistance classBeingTested = new LevenshteinDetailedDistance();
+     LevenshteinResults actualResult = classBeingTested.apply("hello", "hallo");
+     LevenshteinResults expectedResult = new LevenshteinResults(1, 0, 0, 1);
+     assertEquals(actualResult, expectedResult);
+     
+     actualResult = classBeingTested.apply("zzzzzzzz", "hippo");
+     expectedResult = new LevenshteinResults(8, 0, 3, 5);
+     assertEquals(actualResult, expectedResult);
+     assertEquals(actualResult, actualResult); //intentionally added
+
+     actualResult = classBeingTested.apply("", "");
+     expectedResult = new LevenshteinResults(0, 0, 0, 0);
+     assertEquals(actualResult, expectedResult);
+    }
+
+    @Test
+    public void testHashCode() {
+     final LevenshteinDetailedDistance classBeingTested = new LevenshteinDetailedDistance();
+     LevenshteinResults actualResult = classBeingTested.apply("aaapppp", "");
+     LevenshteinResults expectedResult = new LevenshteinResults(7, 0, 7, 0);
+     assertEquals(actualResult.hashCode(), expectedResult.hashCode());
+     
+     actualResult = classBeingTested.apply("frog", "fog");
+     expectedResult = new LevenshteinResults(1, 0, 1, 0);
+     assertEquals(actualResult.hashCode(), expectedResult.hashCode());
+
+     actualResult = classBeingTested.apply("elephant", "hippo");
+     expectedResult = new LevenshteinResults(7, 0, 3, 4);
+     assertEquals(actualResult.hashCode(), expectedResult.hashCode());
+    }
+
+    @Test
+    public void testToString() {
+     final LevenshteinDetailedDistance classBeingTested = new LevenshteinDetailedDistance();
+     LevenshteinResults actualResult = classBeingTested.apply("fly", "ant");
+     LevenshteinResults expectedResult = new LevenshteinResults(3, 0, 0, 3);
+     assertEquals(actualResult.toString(), expectedResult.toString());
+     
+     actualResult = classBeingTested.apply("hippo", "elephant");
+     expectedResult = new LevenshteinResults(7, 3, 0, 4);
+     assertEquals(actualResult.toString(), expectedResult.toString());
+
+     actualResult = classBeingTested.apply("", "a");
+     expectedResult = new LevenshteinResults(1, 1, 0, 0);
+     assertEquals(actualResult.toString(), expectedResult.toString());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDetailedDistance_NullString() throws Exception {
+        UNLIMITED_DISTANCE.apply("a", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDetailedDistance_StringNull() throws Exception {
+        UNLIMITED_DISTANCE.apply(null, "a");
+    }
+
+    @Test
+    public void testGetLevenshteinDetailedDistance_StringStringInt() {
+
+        LevenshteinResults result = new LevenshteinDetailedDistance(0).apply("", "");
+
+        assertEquals(0, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(8).apply("aaapppp", "");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(7, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(7).apply("aaapppp", "");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(7, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(6).apply("aaapppp", "");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(0).apply("b", "a");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(0).apply("a", "b");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(0).apply("aa", "aa");
+        assertEquals(0, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(2).apply("aa", "aa");
+        assertEquals(0, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(2).apply("aaa", "bbb");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(3).apply("aaa", "bbb");
+        assertEquals(3, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(3, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(10).apply("aaaaaa", "b");
+        assertEquals(6, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(5, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(8).apply("aaapppp", "b");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(6, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(4).apply("a", "bbb");
+        assertEquals(3, (int) result.getDistance());
+        assertEquals(2, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(7).apply("aaapppp", "b");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(6, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(3).apply("a", "bbb");
+        assertEquals(3, (int) result.getDistance());
+        assertEquals(2, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(2).apply("a", "bbb");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(2).apply("bbb", "a");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(6).apply("aaapppp", "b");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(1).apply("a", "bbb");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(1).apply("bbb", "a");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(1).apply("12345", "1234567");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(1).apply("1234567", "12345");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(1).apply("frog", "fog");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(1, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(3).apply("fly", "ant");
+        assertEquals(3, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(3, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(7).apply("elephant", "hippo");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(3, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(6).apply("elephant", "hippo");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(7).apply("hippo", "elephant");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(7).apply("hippo", "elephant");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(6).apply("hippo", "elephant");
+        assertEquals(-1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(8).apply("hippo", "zzzzzzzz");
+        assertEquals(8, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(5, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(8).apply("zzzzzzzz", "hippo");
+        assertEquals(8, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(3, (int) result.getDeleteCount());
+        assertEquals(5, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(1).apply("hello", "hallo");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("frog", "fog");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(1, (int) result.getDeleteCount());
+        assertEquals(0, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("fly", "ant");
+        assertEquals(3, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(3, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("elephant", "hippo");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(3, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hippo", "elephant");
+        assertEquals(7, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(4, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hippo", "zzzzzzzz");
+        assertEquals(8, (int) result.getDistance());
+        assertEquals(3, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(5, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("zzzzzzzz", "hippo");
+        assertEquals(8, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(3, (int) result.getDeleteCount());
+        assertEquals(5, (int) result.getSubstituteCount());
+
+        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hello", "hallo");
+        assertEquals(1, (int) result.getDistance());
+        assertEquals(0, (int) result.getInsertCount());
+        assertEquals(0, (int) result.getDeleteCount());
+        assertEquals(1, (int) result.getSubstituteCount());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDetailedDistance_NullStringInt() throws Exception {
+        UNLIMITED_DISTANCE.apply(null, "a");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDetailedDistance_StringNullInt() throws Exception {
+        UNLIMITED_DISTANCE.apply("a", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConstructorWithNegativeThreshold() throws Exception {
+        new LevenshteinDetailedDistance(-1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java
new file mode 100644
index 0000000..d40b8cf
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link LevenshteinDistance}.
+ */
+public class LevenshteinDistanceTest {
+
+    private static final LevenshteinDistance UNLIMITED_DISTANCE = new LevenshteinDistance();
+
+    @Test
+    public void testGetLevenshteinDistance_StringString() {
+        assertEquals(0, (int) UNLIMITED_DISTANCE.apply("", ""));
+        assertEquals(1, (int) UNLIMITED_DISTANCE.apply("", "a"));
+        assertEquals(7, (int) UNLIMITED_DISTANCE.apply("aaapppp", ""));
+        assertEquals(1, (int) UNLIMITED_DISTANCE.apply("frog", "fog"));
+        assertEquals(3, (int) UNLIMITED_DISTANCE.apply("fly", "ant"));
+        assertEquals(7, (int) UNLIMITED_DISTANCE.apply("elephant", "hippo"));
+        assertEquals(7, (int) UNLIMITED_DISTANCE.apply("hippo", "elephant"));
+        assertEquals(8, (int) UNLIMITED_DISTANCE.apply("hippo", "zzzzzzzz"));
+        assertEquals(8, (int) UNLIMITED_DISTANCE.apply("zzzzzzzz", "hippo"));
+        assertEquals(1, (int) UNLIMITED_DISTANCE.apply("hello", "hallo"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDistance_NullString() throws Exception {
+        UNLIMITED_DISTANCE.apply("a", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDistance_StringNull() throws Exception {
+        UNLIMITED_DISTANCE.apply(null, "a");
+    }
+
+    @Test
+    public void testGetLevenshteinDistance_StringStringInt() {
+        // empty strings
+        assertEquals(0, (int) new LevenshteinDistance(0).apply("", ""));
+        assertEquals(7, (int) new LevenshteinDistance(8).apply("aaapppp", ""));
+        assertEquals(7, (int) new LevenshteinDistance(7).apply("aaapppp", ""));
+        assertEquals(-1, (int) new LevenshteinDistance(6).apply("aaapppp", ""));
+
+        // unequal strings, zero threshold
+        assertEquals(-1, (int) new LevenshteinDistance(0).apply("b", "a"));
+        assertEquals(-1, (int) new LevenshteinDistance(0).apply("a", "b"));
+
+        // equal strings
+        assertEquals(0, (int) new LevenshteinDistance(0).apply("aa", "aa"));
+        assertEquals(0, (int) new LevenshteinDistance(2).apply("aa", "aa"));
+
+        // same length
+        assertEquals(-1, (int) new LevenshteinDistance(2).apply("aaa", "bbb"));
+        assertEquals(3, (int) new LevenshteinDistance(3).apply("aaa", "bbb"));
+
+        // big stripe
+        assertEquals(6, (int) new LevenshteinDistance(10).apply("aaaaaa", "b"));
+
+        // distance less than threshold
+        assertEquals(7, (int) new LevenshteinDistance(8).apply("aaapppp", "b"));
+        assertEquals(3, (int) new LevenshteinDistance(4).apply("a", "bbb"));
+
+        // distance equal to threshold
+        assertEquals(7, (int) new LevenshteinDistance(7).apply("aaapppp", "b"));
+        assertEquals(3, (int) new LevenshteinDistance(3).apply("a", "bbb"));
+
+        // distance greater than threshold
+        assertEquals(-1, (int) new LevenshteinDistance(2).apply("a", "bbb"));
+        assertEquals(-1, (int) new LevenshteinDistance(2).apply("bbb", "a"));
+        assertEquals(-1, (int) new LevenshteinDistance(6).apply("aaapppp", "b"));
+
+        // stripe runs off array, strings not similar
+        assertEquals(-1, (int) new LevenshteinDistance(1).apply("a", "bbb"));
+        assertEquals(-1, (int) new LevenshteinDistance(1).apply("bbb", "a"));
+
+        // stripe runs off array, strings are similar
+        assertEquals(-1, (int) new LevenshteinDistance(1).apply("12345", "1234567"));
+        assertEquals(-1, (int) new LevenshteinDistance(1).apply("1234567", "12345"));
+
+        // old getLevenshteinDistance test cases
+        assertEquals(1, (int) new LevenshteinDistance(1).apply("frog", "fog"));
+        assertEquals(3, (int) new LevenshteinDistance(3).apply("fly", "ant"));
+        assertEquals(7, (int) new LevenshteinDistance(7).apply("elephant", "hippo"));
+        assertEquals(-1, (int) new LevenshteinDistance(6).apply("elephant", "hippo"));
+        assertEquals(7, (int) new LevenshteinDistance(7).apply("hippo", "elephant"));
+        assertEquals(-1, (int) new LevenshteinDistance(6).apply("hippo", "elephant"));
+        assertEquals(8, (int) new LevenshteinDistance(8).apply("hippo", "zzzzzzzz"));
+        assertEquals(8, (int) new LevenshteinDistance(8).apply("zzzzzzzz", "hippo"));
+        assertEquals(1, (int) new LevenshteinDistance(1).apply("hello", "hallo"));
+
+        assertEquals(1,
+                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("frog", "fog"));
+        assertEquals(3, (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("fly", "ant"));
+        assertEquals(7,
+                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("elephant", "hippo"));
+        assertEquals(7,
+                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("hippo", "elephant"));
+        assertEquals(8,
+                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("hippo", "zzzzzzzz"));
+        assertEquals(8,
+                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("zzzzzzzz", "hippo"));
+        assertEquals(1,
+                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("hello", "hallo"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDistance_NullStringInt() throws Exception {
+        UNLIMITED_DISTANCE.apply(null, "a");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetLevenshteinDistance_StringNullInt() throws Exception {
+        UNLIMITED_DISTANCE.apply("a", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConstructorWithNegativeThreshold() throws Exception {
+        new LevenshteinDistance(-1);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java
new file mode 100644
index 0000000..4c9ff6f
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link LongestCommonSubsequenceDistance}.
+ */
+public class LongestCommonSubsequenceDistanceTest {
+
+    private static LongestCommonSubsequenceDistance subject;
+    
+    @BeforeClass
+    public static void setup() {
+        subject = new LongestCommonSubsequenceDistance();
+    }
+
+    @Test
+    public void testGettingLogestCommonSubsequenceDistacne() {
+        assertEquals(Integer.valueOf(0), subject.apply("", ""));
+        assertEquals(Integer.valueOf(4), subject.apply("left", ""));
+        assertEquals(Integer.valueOf(5), subject.apply("", "right"));
+        assertEquals(Integer.valueOf(1), subject.apply("frog", "fog"));
+        assertEquals(Integer.valueOf(6), subject.apply("fly", "ant"));
+        assertEquals(Integer.valueOf(11), subject.apply("elephant", "hippo"));
+        assertEquals(Integer.valueOf(7), subject.apply("ABC Corporation", "ABC Corp"));
+        assertEquals(Integer.valueOf(4), subject.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."));
+        assertEquals(Integer.valueOf(9), subject.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"));
+        assertEquals(Integer.valueOf(3), subject.apply("PENNSYLVANIA", "PENNCISYLVNIA"));
+        assertEquals(Integer.valueOf(7), subject.apply("left", "right"));
+        assertEquals(Integer.valueOf(9), subject.apply("leettteft", "ritttght"));
+        assertEquals(Integer.valueOf(0), subject.apply("the same string", "the same string"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceDistanceNullNull() throws Exception {
+        subject.apply(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceDistanceStringNull() throws Exception {
+        subject.apply(" ", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceDistanceNullString() throws Exception {
+        subject.apply(null, "right");
+    }
+
+}


[19/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/EntityArrays.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/EntityArrays.java b/src/main/java/org/apache/commons/text/beta/translate/EntityArrays.java
deleted file mode 100644
index 2db22f0..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/EntityArrays.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Class holding various entity data for HTML and XML - generally for use with
- * the LookupTranslator.
- * All Maps are generated using <code>java.util.Collections.unmodifiableMap()</code>.
- *
- * @since 1.0
- */
-public class EntityArrays {
-
-   /**
-     * A Map&lt;CharSequence, CharSequence&gt; to to escape
-     * <a href="https://secure.wikimedia.org/wikipedia/en/wiki/ISO/IEC_8859-1">ISO-8859-1</a>
-     * characters to their named HTML 3.x equivalents.
-     */
-    public static final Map<CharSequence, CharSequence> ISO8859_1_ESCAPE;
-    static {
-        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
-        initialMap.put("\u00A0", "&nbsp;"); // non-breaking space
-        initialMap.put("\u00A1", "&iexcl;"); // inverted exclamation mark
-        initialMap.put("\u00A2", "&cent;"); // cent sign
-        initialMap.put("\u00A3", "&pound;"); // pound sign
-        initialMap.put("\u00A4", "&curren;"); // currency sign
-        initialMap.put("\u00A5", "&yen;"); // yen sign = yuan sign
-        initialMap.put("\u00A6", "&brvbar;"); // broken bar = broken vertical bar
-        initialMap.put("\u00A7", "&sect;"); // section sign
-        initialMap.put("\u00A8", "&uml;"); // diaeresis = spacing diaeresis
-        initialMap.put("\u00A9", "&copy;"); // � - copyright sign
-        initialMap.put("\u00AA", "&ordf;"); // feminine ordinal indicator
-        initialMap.put("\u00AB", "&laquo;"); // left-pointing double angle quotation mark = left pointing guillemet
-        initialMap.put("\u00AC", "&not;"); // not sign
-        initialMap.put("\u00AD", "&shy;"); // soft hyphen = discretionary hyphen
-        initialMap.put("\u00AE", "&reg;"); // � - registered trademark sign
-        initialMap.put("\u00AF", "&macr;"); // macron = spacing macron = overline = APL overbar
-        initialMap.put("\u00B0", "&deg;"); // degree sign
-        initialMap.put("\u00B1", "&plusmn;"); // plus-minus sign = plus-or-minus sign
-        initialMap.put("\u00B2", "&sup2;"); // superscript two = superscript digit two = squared
-        initialMap.put("\u00B3", "&sup3;"); // superscript three = superscript digit three = cubed
-        initialMap.put("\u00B4", "&acute;"); // acute accent = spacing acute
-        initialMap.put("\u00B5", "&micro;"); // micro sign
-        initialMap.put("\u00B6", "&para;"); // pilcrow sign = paragraph sign
-        initialMap.put("\u00B7", "&middot;"); // middle dot = Georgian comma = Greek middle dot
-        initialMap.put("\u00B8", "&cedil;"); // cedilla = spacing cedilla
-        initialMap.put("\u00B9", "&sup1;"); // superscript one = superscript digit one
-        initialMap.put("\u00BA", "&ordm;"); // masculine ordinal indicator
-        initialMap.put("\u00BB", "&raquo;"); // right-pointing double angle quotation mark = right pointing guillemet
-        initialMap.put("\u00BC", "&frac14;"); // vulgar fraction one quarter = fraction one quarter
-        initialMap.put("\u00BD", "&frac12;"); // vulgar fraction one half = fraction one half
-        initialMap.put("\u00BE", "&frac34;"); // vulgar fraction three quarters = fraction three quarters
-        initialMap.put("\u00BF", "&iquest;"); // inverted question mark = turned question mark
-        initialMap.put("\u00C0", "&Agrave;"); // � - uppercase A, grave accent
-        initialMap.put("\u00C1", "&Aacute;"); // � - uppercase A, acute accent
-        initialMap.put("\u00C2", "&Acirc;"); // � - uppercase A, circumflex accent
-        initialMap.put("\u00C3", "&Atilde;"); // � - uppercase A, tilde
-        initialMap.put("\u00C4", "&Auml;"); // � - uppercase A, umlaut
-        initialMap.put("\u00C5", "&Aring;"); // � - uppercase A, ring
-        initialMap.put("\u00C6", "&AElig;"); // � - uppercase AE
-        initialMap.put("\u00C7", "&Ccedil;"); // � - uppercase C, cedilla
-        initialMap.put("\u00C8", "&Egrave;"); // � - uppercase E, grave accent
-        initialMap.put("\u00C9", "&Eacute;"); // � - uppercase E, acute accent
-        initialMap.put("\u00CA", "&Ecirc;"); // � - uppercase E, circumflex accent
-        initialMap.put("\u00CB", "&Euml;"); // � - uppercase E, umlaut
-        initialMap.put("\u00CC", "&Igrave;"); // � - uppercase I, grave accent
-        initialMap.put("\u00CD", "&Iacute;"); // � - uppercase I, acute accent
-        initialMap.put("\u00CE", "&Icirc;"); // � - uppercase I, circumflex accent
-        initialMap.put("\u00CF", "&Iuml;"); // � - uppercase I, umlaut
-        initialMap.put("\u00D0", "&ETH;"); // � - uppercase Eth, Icelandic
-        initialMap.put("\u00D1", "&Ntilde;"); // � - uppercase N, tilde
-        initialMap.put("\u00D2", "&Ograve;"); // � - uppercase O, grave accent
-        initialMap.put("\u00D3", "&Oacute;"); // � - uppercase O, acute accent
-        initialMap.put("\u00D4", "&Ocirc;"); // � - uppercase O, circumflex accent
-        initialMap.put("\u00D5", "&Otilde;"); // � - uppercase O, tilde
-        initialMap.put("\u00D6", "&Ouml;"); // � - uppercase O, umlaut
-        initialMap.put("\u00D7", "&times;"); // multiplication sign
-        initialMap.put("\u00D8", "&Oslash;"); // � - uppercase O, slash
-        initialMap.put("\u00D9", "&Ugrave;"); // � - uppercase U, grave accent
-        initialMap.put("\u00DA", "&Uacute;"); // � - uppercase U, acute accent
-        initialMap.put("\u00DB", "&Ucirc;"); // � - uppercase U, circumflex accent
-        initialMap.put("\u00DC", "&Uuml;"); // � - uppercase U, umlaut
-        initialMap.put("\u00DD", "&Yacute;"); // � - uppercase Y, acute accent
-        initialMap.put("\u00DE", "&THORN;"); // � - uppercase THORN, Icelandic
-        initialMap.put("\u00DF", "&szlig;"); // � - lowercase sharps, German
-        initialMap.put("\u00E0", "&agrave;"); // � - lowercase a, grave accent
-        initialMap.put("\u00E1", "&aacute;"); // � - lowercase a, acute accent
-        initialMap.put("\u00E2", "&acirc;"); // � - lowercase a, circumflex accent
-        initialMap.put("\u00E3", "&atilde;"); // � - lowercase a, tilde
-        initialMap.put("\u00E4", "&auml;"); // � - lowercase a, umlaut
-        initialMap.put("\u00E5", "&aring;"); // � - lowercase a, ring
-        initialMap.put("\u00E6", "&aelig;"); // � - lowercase ae
-        initialMap.put("\u00E7", "&ccedil;"); // � - lowercase c, cedilla
-        initialMap.put("\u00E8", "&egrave;"); // � - lowercase e, grave accent
-        initialMap.put("\u00E9", "&eacute;"); // � - lowercase e, acute accent
-        initialMap.put("\u00EA", "&ecirc;"); // � - lowercase e, circumflex accent
-        initialMap.put("\u00EB", "&euml;"); // � - lowercase e, umlaut
-        initialMap.put("\u00EC", "&igrave;"); // � - lowercase i, grave accent
-        initialMap.put("\u00ED", "&iacute;"); // � - lowercase i, acute accent
-        initialMap.put("\u00EE", "&icirc;"); // � - lowercase i, circumflex accent
-        initialMap.put("\u00EF", "&iuml;"); // � - lowercase i, umlaut
-        initialMap.put("\u00F0", "&eth;"); // � - lowercase eth, Icelandic
-        initialMap.put("\u00F1", "&ntilde;"); // � - lowercase n, tilde
-        initialMap.put("\u00F2", "&ograve;"); // � - lowercase o, grave accent
-        initialMap.put("\u00F3", "&oacute;"); // � - lowercase o, acute accent
-        initialMap.put("\u00F4", "&ocirc;"); // � - lowercase o, circumflex accent
-        initialMap.put("\u00F5", "&otilde;"); // � - lowercase o, tilde
-        initialMap.put("\u00F6", "&ouml;"); // � - lowercase o, umlaut
-        initialMap.put("\u00F7", "&divide;"); // division sign
-        initialMap.put("\u00F8", "&oslash;"); // � - lowercase o, slash
-        initialMap.put("\u00F9", "&ugrave;"); // � - lowercase u, grave accent
-        initialMap.put("\u00FA", "&uacute;"); // � - lowercase u, acute accent
-        initialMap.put("\u00FB", "&ucirc;"); // � - lowercase u, circumflex accent
-        initialMap.put("\u00FC", "&uuml;"); // � - lowercase u, umlaut
-        initialMap.put("\u00FD", "&yacute;"); // � - lowercase y, acute accent
-        initialMap.put("\u00FE", "&thorn;"); // � - lowercase thorn, Icelandic
-        initialMap.put("\u00FF", "&yuml;"); // � - lowercase y, umlaut
-        ISO8859_1_ESCAPE = Collections.unmodifiableMap(initialMap);
-    }
-
-    /**
-     * Reverse of {@link #ISO8859_1_ESCAPE} for unescaping purposes.
-     */
-    public static final Map<CharSequence, CharSequence> ISO8859_1_UNESCAPE;
-    static {
-        ISO8859_1_UNESCAPE = Collections.unmodifiableMap(invert(ISO8859_1_ESCAPE));
-    }
-
-    /**
-     * A Map&lt;CharSequence, CharSequence&gt; to escape additional
-     * <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">character entity
-     * references</a>. Note that this must be used with {@link #ISO8859_1_ESCAPE} to get the full list of
-     * HTML 4.0 character entities.
-     */
-    public static final Map<CharSequence, CharSequence> HTML40_EXTENDED_ESCAPE;
-    static {
-        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
-        // <!-- Latin Extended-B -->
-        initialMap.put("\u0192", "&fnof;"); // latin small f with hook = function= florin, U+0192 ISOtech -->
-        // <!-- Greek -->
-        initialMap.put("\u0391", "&Alpha;"); // greek capital letter alpha, U+0391 -->
-        initialMap.put("\u0392", "&Beta;"); // greek capital letter beta, U+0392 -->
-        initialMap.put("\u0393", "&Gamma;"); // greek capital letter gamma,U+0393 ISOgrk3 -->
-        initialMap.put("\u0394", "&Delta;"); // greek capital letter delta,U+0394 ISOgrk3 -->
-        initialMap.put("\u0395", "&Epsilon;"); // greek capital letter epsilon, U+0395 -->
-        initialMap.put("\u0396", "&Zeta;"); // greek capital letter zeta, U+0396 -->
-        initialMap.put("\u0397", "&Eta;"); // greek capital letter eta, U+0397 -->
-        initialMap.put("\u0398", "&Theta;"); // greek capital letter theta,U+0398 ISOgrk3 -->
-        initialMap.put("\u0399", "&Iota;"); // greek capital letter iota, U+0399 -->
-        initialMap.put("\u039A", "&Kappa;"); // greek capital letter kappa, U+039A -->
-        initialMap.put("\u039B", "&Lambda;"); // greek capital letter lambda,U+039B ISOgrk3 -->
-        initialMap.put("\u039C", "&Mu;"); // greek capital letter mu, U+039C -->
-        initialMap.put("\u039D", "&Nu;"); // greek capital letter nu, U+039D -->
-        initialMap.put("\u039E", "&Xi;"); // greek capital letter xi, U+039E ISOgrk3 -->
-        initialMap.put("\u039F", "&Omicron;"); // greek capital letter omicron, U+039F -->
-        initialMap.put("\u03A0", "&Pi;"); // greek capital letter pi, U+03A0 ISOgrk3 -->
-        initialMap.put("\u03A1", "&Rho;"); // greek capital letter rho, U+03A1 -->
-        // <!-- there is no Sigmaf, and no U+03A2 character either -->
-        initialMap.put("\u03A3", "&Sigma;"); // greek capital letter sigma,U+03A3 ISOgrk3 -->
-        initialMap.put("\u03A4", "&Tau;"); // greek capital letter tau, U+03A4 -->
-        initialMap.put("\u03A5", "&Upsilon;"); // greek capital letter upsilon,U+03A5 ISOgrk3 -->
-        initialMap.put("\u03A6", "&Phi;"); // greek capital letter phi,U+03A6 ISOgrk3 -->
-        initialMap.put("\u03A7", "&Chi;"); // greek capital letter chi, U+03A7 -->
-        initialMap.put("\u03A8", "&Psi;"); // greek capital letter psi,U+03A8 ISOgrk3 -->
-        initialMap.put("\u03A9", "&Omega;"); // greek capital letter omega,U+03A9 ISOgrk3 -->
-        initialMap.put("\u03B1", "&alpha;"); // greek small letter alpha,U+03B1 ISOgrk3 -->
-        initialMap.put("\u03B2", "&beta;"); // greek small letter beta, U+03B2 ISOgrk3 -->
-        initialMap.put("\u03B3", "&gamma;"); // greek small letter gamma,U+03B3 ISOgrk3 -->
-        initialMap.put("\u03B4", "&delta;"); // greek small letter delta,U+03B4 ISOgrk3 -->
-        initialMap.put("\u03B5", "&epsilon;"); // greek small letter epsilon,U+03B5 ISOgrk3 -->
-        initialMap.put("\u03B6", "&zeta;"); // greek small letter zeta, U+03B6 ISOgrk3 -->
-        initialMap.put("\u03B7", "&eta;"); // greek small letter eta, U+03B7 ISOgrk3 -->
-        initialMap.put("\u03B8", "&theta;"); // greek small letter theta,U+03B8 ISOgrk3 -->
-        initialMap.put("\u03B9", "&iota;"); // greek small letter iota, U+03B9 ISOgrk3 -->
-        initialMap.put("\u03BA", "&kappa;"); // greek small letter kappa,U+03BA ISOgrk3 -->
-        initialMap.put("\u03BB", "&lambda;"); // greek small letter lambda,U+03BB ISOgrk3 -->
-        initialMap.put("\u03BC", "&mu;"); // greek small letter mu, U+03BC ISOgrk3 -->
-        initialMap.put("\u03BD", "&nu;"); // greek small letter nu, U+03BD ISOgrk3 -->
-        initialMap.put("\u03BE", "&xi;"); // greek small letter xi, U+03BE ISOgrk3 -->
-        initialMap.put("\u03BF", "&omicron;"); // greek small letter omicron, U+03BF NEW -->
-        initialMap.put("\u03C0", "&pi;"); // greek small letter pi, U+03C0 ISOgrk3 -->
-        initialMap.put("\u03C1", "&rho;"); // greek small letter rho, U+03C1 ISOgrk3 -->
-        initialMap.put("\u03C2", "&sigmaf;"); // greek small letter final sigma,U+03C2 ISOgrk3 -->
-        initialMap.put("\u03C3", "&sigma;"); // greek small letter sigma,U+03C3 ISOgrk3 -->
-        initialMap.put("\u03C4", "&tau;"); // greek small letter tau, U+03C4 ISOgrk3 -->
-        initialMap.put("\u03C5", "&upsilon;"); // greek small letter upsilon,U+03C5 ISOgrk3 -->
-        initialMap.put("\u03C6", "&phi;"); // greek small letter phi, U+03C6 ISOgrk3 -->
-        initialMap.put("\u03C7", "&chi;"); // greek small letter chi, U+03C7 ISOgrk3 -->
-        initialMap.put("\u03C8", "&psi;"); // greek small letter psi, U+03C8 ISOgrk3 -->
-        initialMap.put("\u03C9", "&omega;"); // greek small letter omega,U+03C9 ISOgrk3 -->
-        initialMap.put("\u03D1", "&thetasym;"); // greek small letter theta symbol,U+03D1 NEW -->
-        initialMap.put("\u03D2", "&upsih;"); // greek upsilon with hook symbol,U+03D2 NEW -->
-        initialMap.put("\u03D6", "&piv;"); // greek pi symbol, U+03D6 ISOgrk3 -->
-        // <!-- General Punctuation -->
-        initialMap.put("\u2022", "&bull;"); // bullet = black small circle,U+2022 ISOpub -->
-        // <!-- bullet is NOT the same as bullet operator, U+2219 -->
-        initialMap.put("\u2026", "&hellip;"); // horizontal ellipsis = three dot leader,U+2026 ISOpub -->
-        initialMap.put("\u2032", "&prime;"); // prime = minutes = feet, U+2032 ISOtech -->
-        initialMap.put("\u2033", "&Prime;"); // double prime = seconds = inches,U+2033 ISOtech -->
-        initialMap.put("\u203E", "&oline;"); // overline = spacing overscore,U+203E NEW -->
-        initialMap.put("\u2044", "&frasl;"); // fraction slash, U+2044 NEW -->
-        // <!-- Letterlike Symbols -->
-        initialMap.put("\u2118", "&weierp;"); // script capital P = power set= Weierstrass p, U+2118 ISOamso -->
-        initialMap.put("\u2111", "&image;"); // blackletter capital I = imaginary part,U+2111 ISOamso -->
-        initialMap.put("\u211C", "&real;"); // blackletter capital R = real part symbol,U+211C ISOamso -->
-        initialMap.put("\u2122", "&trade;"); // trade mark sign, U+2122 ISOnum -->
-        initialMap.put("\u2135", "&alefsym;"); // alef symbol = first transfinite cardinal,U+2135 NEW -->
-        // <!-- alef symbol is NOT the same as hebrew letter alef,U+05D0 although the
-        // same glyph could be used to depict both characters -->
-        // <!-- Arrows -->
-        initialMap.put("\u2190", "&larr;"); // leftwards arrow, U+2190 ISOnum -->
-        initialMap.put("\u2191", "&uarr;"); // upwards arrow, U+2191 ISOnum-->
-        initialMap.put("\u2192", "&rarr;"); // rightwards arrow, U+2192 ISOnum -->
-        initialMap.put("\u2193", "&darr;"); // downwards arrow, U+2193 ISOnum -->
-        initialMap.put("\u2194", "&harr;"); // left right arrow, U+2194 ISOamsa -->
-        initialMap.put("\u21B5", "&crarr;"); // downwards arrow with corner leftwards= carriage return, U+21B5 NEW -->
-        initialMap.put("\u21D0", "&lArr;"); // leftwards double arrow, U+21D0 ISOtech -->
-        // <!-- ISO 10646 does not say that lArr is the same as the 'is implied by'
-        // arrow but also does not have any other character for that function.
-        // So ? lArr canbe used for 'is implied by' as ISOtech suggests -->
-        initialMap.put("\u21D1", "&uArr;"); // upwards double arrow, U+21D1 ISOamsa -->
-        initialMap.put("\u21D2", "&rArr;"); // rightwards double arrow,U+21D2 ISOtech -->
-        // <!-- ISO 10646 does not say this is the 'implies' character but does not
-        // have another character with this function so ?rArr can be used for
-        // 'implies' as ISOtech suggests -->
-        initialMap.put("\u21D3", "&dArr;"); // downwards double arrow, U+21D3 ISOamsa -->
-        initialMap.put("\u21D4", "&hArr;"); // left right double arrow,U+21D4 ISOamsa -->
-        // <!-- Mathematical Operators -->
-        initialMap.put("\u2200", "&forall;"); // for all, U+2200 ISOtech -->
-        initialMap.put("\u2202", "&part;"); // partial differential, U+2202 ISOtech -->
-        initialMap.put("\u2203", "&exist;"); // there exists, U+2203 ISOtech -->
-        initialMap.put("\u2205", "&empty;"); // empty set = null set = diameter,U+2205 ISOamso -->
-        initialMap.put("\u2207", "&nabla;"); // nabla = backward difference,U+2207 ISOtech -->
-        initialMap.put("\u2208", "&isin;"); // element of, U+2208 ISOtech -->
-        initialMap.put("\u2209", "&notin;"); // not an element of, U+2209 ISOtech -->
-        initialMap.put("\u220B", "&ni;"); // contains as member, U+220B ISOtech -->
-        // <!-- should there be a more memorable name than 'ni'? -->
-        initialMap.put("\u220F", "&prod;"); // n-ary product = product sign,U+220F ISOamsb -->
-        // <!-- prod is NOT the same character as U+03A0 'greek capital letter pi'
-        // though the same glyph might be used for both -->
-        initialMap.put("\u2211", "&sum;"); // n-ary summation, U+2211 ISOamsb -->
-        // <!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
-        // though the same glyph might be used for both -->
-        initialMap.put("\u2212", "&minus;"); // minus sign, U+2212 ISOtech -->
-        initialMap.put("\u2217", "&lowast;"); // asterisk operator, U+2217 ISOtech -->
-        initialMap.put("\u221A", "&radic;"); // square root = radical sign,U+221A ISOtech -->
-        initialMap.put("\u221D", "&prop;"); // proportional to, U+221D ISOtech -->
-        initialMap.put("\u221E", "&infin;"); // infinity, U+221E ISOtech -->
-        initialMap.put("\u2220", "&ang;"); // angle, U+2220 ISOamso -->
-        initialMap.put("\u2227", "&and;"); // logical and = wedge, U+2227 ISOtech -->
-        initialMap.put("\u2228", "&or;"); // logical or = vee, U+2228 ISOtech -->
-        initialMap.put("\u2229", "&cap;"); // intersection = cap, U+2229 ISOtech -->
-        initialMap.put("\u222A", "&cup;"); // union = cup, U+222A ISOtech -->
-        initialMap.put("\u222B", "&int;"); // integral, U+222B ISOtech -->
-        initialMap.put("\u2234", "&there4;"); // therefore, U+2234 ISOtech -->
-        initialMap.put("\u223C", "&sim;"); // tilde operator = varies with = similar to,U+223C ISOtech -->
-        // <!-- tilde operator is NOT the same character as the tilde, U+007E,although
-        // the same glyph might be used to represent both -->
-        initialMap.put("\u2245", "&cong;"); // approximately equal to, U+2245 ISOtech -->
-        initialMap.put("\u2248", "&asymp;"); // almost equal to = asymptotic to,U+2248 ISOamsr -->
-        initialMap.put("\u2260", "&ne;"); // not equal to, U+2260 ISOtech -->
-        initialMap.put("\u2261", "&equiv;"); // identical to, U+2261 ISOtech -->
-        initialMap.put("\u2264", "&le;"); // less-than or equal to, U+2264 ISOtech -->
-        initialMap.put("\u2265", "&ge;"); // greater-than or equal to,U+2265 ISOtech -->
-        initialMap.put("\u2282", "&sub;"); // subset of, U+2282 ISOtech -->
-        initialMap.put("\u2283", "&sup;"); // superset of, U+2283 ISOtech -->
-        // <!-- note that nsup, 'not a superset of, U+2283' is not covered by the
-        // Symbol font encoding and is not included. Should it be, for symmetry?
-        // It is in ISOamsn -->,
-        initialMap.put("\u2284", "&nsub;"); // not a subset of, U+2284 ISOamsn -->
-        initialMap.put("\u2286", "&sube;"); // subset of or equal to, U+2286 ISOtech -->
-        initialMap.put("\u2287", "&supe;"); // superset of or equal to,U+2287 ISOtech -->
-        initialMap.put("\u2295", "&oplus;"); // circled plus = direct sum,U+2295 ISOamsb -->
-        initialMap.put("\u2297", "&otimes;"); // circled times = vector product,U+2297 ISOamsb -->
-        initialMap.put("\u22A5", "&perp;"); // up tack = orthogonal to = perpendicular,U+22A5 ISOtech -->
-        initialMap.put("\u22C5", "&sdot;"); // dot operator, U+22C5 ISOamsb -->
-        // <!-- dot operator is NOT the same character as U+00B7 middle dot -->
-        // <!-- Miscellaneous Technical -->
-        initialMap.put("\u2308", "&lceil;"); // left ceiling = apl upstile,U+2308 ISOamsc -->
-        initialMap.put("\u2309", "&rceil;"); // right ceiling, U+2309 ISOamsc -->
-        initialMap.put("\u230A", "&lfloor;"); // left floor = apl downstile,U+230A ISOamsc -->
-        initialMap.put("\u230B", "&rfloor;"); // right floor, U+230B ISOamsc -->
-        initialMap.put("\u2329", "&lang;"); // left-pointing angle bracket = bra,U+2329 ISOtech -->
-        // <!-- lang is NOT the same character as U+003C 'less than' or U+2039 'single left-pointing angle quotation
-        // mark' -->
-        initialMap.put("\u232A", "&rang;"); // right-pointing angle bracket = ket,U+232A ISOtech -->
-        // <!-- rang is NOT the same character as U+003E 'greater than' or U+203A
-        // 'single right-pointing angle quotation mark' -->
-        // <!-- Geometric Shapes -->
-        initialMap.put("\u25CA", "&loz;"); // lozenge, U+25CA ISOpub -->
-        // <!-- Miscellaneous Symbols -->
-        initialMap.put("\u2660", "&spades;"); // black spade suit, U+2660 ISOpub -->
-        // <!-- black here seems to mean filled as opposed to hollow -->
-        initialMap.put("\u2663", "&clubs;"); // black club suit = shamrock,U+2663 ISOpub -->
-        initialMap.put("\u2665", "&hearts;"); // black heart suit = valentine,U+2665 ISOpub -->
-        initialMap.put("\u2666", "&diams;"); // black diamond suit, U+2666 ISOpub -->
-
-        // <!-- Latin Extended-A -->
-        initialMap.put("\u0152", "&OElig;"); // -- latin capital ligature OE,U+0152 ISOlat2 -->
-        initialMap.put("\u0153", "&oelig;"); // -- latin small ligature oe, U+0153 ISOlat2 -->
-        // <!-- ligature is a misnomer, this is a separate character in some languages -->
-        initialMap.put("\u0160", "&Scaron;"); // -- latin capital letter S with caron,U+0160 ISOlat2 -->
-        initialMap.put("\u0161", "&scaron;"); // -- latin small letter s with caron,U+0161 ISOlat2 -->
-        initialMap.put("\u0178", "&Yuml;"); // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 -->
-        // <!-- Spacing Modifier Letters -->
-        initialMap.put("\u02C6", "&circ;"); // -- modifier letter circumflex accent,U+02C6 ISOpub -->
-        initialMap.put("\u02DC", "&tilde;"); // small tilde, U+02DC ISOdia -->
-        // <!-- General Punctuation -->
-        initialMap.put("\u2002", "&ensp;"); // en space, U+2002 ISOpub -->
-        initialMap.put("\u2003", "&emsp;"); // em space, U+2003 ISOpub -->
-        initialMap.put("\u2009", "&thinsp;"); // thin space, U+2009 ISOpub -->
-        initialMap.put("\u200C", "&zwnj;"); // zero width non-joiner,U+200C NEW RFC 2070 -->
-        initialMap.put("\u200D", "&zwj;"); // zero width joiner, U+200D NEW RFC 2070 -->
-        initialMap.put("\u200E", "&lrm;"); // left-to-right mark, U+200E NEW RFC 2070 -->
-        initialMap.put("\u200F", "&rlm;"); // right-to-left mark, U+200F NEW RFC 2070 -->
-        initialMap.put("\u2013", "&ndash;"); // en dash, U+2013 ISOpub -->
-        initialMap.put("\u2014", "&mdash;"); // em dash, U+2014 ISOpub -->
-        initialMap.put("\u2018", "&lsquo;"); // left single quotation mark,U+2018 ISOnum -->
-        initialMap.put("\u2019", "&rsquo;"); // right single quotation mark,U+2019 ISOnum -->
-        initialMap.put("\u201A", "&sbquo;"); // single low-9 quotation mark, U+201A NEW -->
-        initialMap.put("\u201C", "&ldquo;"); // left double quotation mark,U+201C ISOnum -->
-        initialMap.put("\u201D", "&rdquo;"); // right double quotation mark,U+201D ISOnum -->
-        initialMap.put("\u201E", "&bdquo;"); // double low-9 quotation mark, U+201E NEW -->
-        initialMap.put("\u2020", "&dagger;"); // dagger, U+2020 ISOpub -->
-        initialMap.put("\u2021", "&Dagger;"); // double dagger, U+2021 ISOpub -->
-        initialMap.put("\u2030", "&permil;"); // per mille sign, U+2030 ISOtech -->
-        initialMap.put("\u2039", "&lsaquo;"); // single left-pointing angle quotation mark,U+2039 ISO proposed -->
-        // <!-- lsaquo is proposed but not yet ISO standardized -->
-        initialMap.put("\u203A", "&rsaquo;"); // single right-pointing angle quotation mark,U+203A ISO proposed -->
-        // <!-- rsaquo is proposed but not yet ISO standardized -->
-        initialMap.put("\u20AC", "&euro;"); // -- euro sign, U+20AC NEW -->
-        HTML40_EXTENDED_ESCAPE = Collections.unmodifiableMap(initialMap);
-    }
-
-    /**
-     * Reverse of {@link #HTML40_EXTENDED_ESCAPE} for unescaping purposes.
-     */
-    public static final Map<CharSequence, CharSequence> HTML40_EXTENDED_UNESCAPE;
-    static {
-        HTML40_EXTENDED_UNESCAPE = Collections.unmodifiableMap(invert(HTML40_EXTENDED_ESCAPE));
-    }
-
-    /**
-     * A Map&lt;CharSequence, CharSequence&gt; to escape the basic XML and HTML
-     * character entities.
-     *
-     * Namely: {@code " & < >}
-     */
-    public static final Map<CharSequence, CharSequence> BASIC_ESCAPE;
-    static {
-        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
-        initialMap.put("\"", "&quot;"); // " - double-quote
-        initialMap.put("&", "&amp;");   // & - ampersand
-        initialMap.put("<", "&lt;");    // < - less-than
-        initialMap.put(">", "&gt;");    // > - greater-than
-        BASIC_ESCAPE = Collections.unmodifiableMap(initialMap);
-    }
-
-    /**
-     * Reverse of {@link #BASIC_ESCAPE} for unescaping purposes.
-     */
-    public static final Map<CharSequence, CharSequence> BASIC_UNESCAPE;
-    static {
-        BASIC_UNESCAPE = Collections.unmodifiableMap(invert(BASIC_ESCAPE));
-    }
-
-    /**
-     * A Map&lt;CharSequence, CharSequence&gt; to escape the apostrophe character to
-     * its XML character entity.
-     */
-    public static final Map<CharSequence, CharSequence> APOS_ESCAPE;
-    static {
-        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
-        initialMap.put("'","&apos;"); // XML apostrophe
-        APOS_ESCAPE = Collections.unmodifiableMap(initialMap);
-    }
-
-    /**
-     * Reverse of {@link #APOS_ESCAPE} for unescaping purposes.
-     */
-    public static final Map<CharSequence, CharSequence> APOS_UNESCAPE;
-    static {
-        APOS_UNESCAPE = Collections.unmodifiableMap(invert(APOS_ESCAPE));
-    }
-
-    /**
-     * A Map&lt;CharSequence, CharSequence&gt; to escape the Java
-     * control characters.
-     *
-     * Namely: {@code \b \n \t \f \r}
-     */
-    public static final Map<CharSequence, CharSequence> JAVA_CTRL_CHARS_ESCAPE;
-    static {
-        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
-        initialMap.put("\b", "\\b");
-        initialMap.put("\n", "\\n");
-        initialMap.put("\t", "\\t");
-        initialMap.put("\f", "\\f");
-        initialMap.put("\r", "\\r");
-        JAVA_CTRL_CHARS_ESCAPE = Collections.unmodifiableMap(initialMap);
-    }
-
-    /**
-     * Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE} for unescaping purposes.
-     */
-    public static final Map<CharSequence, CharSequence> JAVA_CTRL_CHARS_UNESCAPE;
-    static {
-        JAVA_CTRL_CHARS_UNESCAPE = Collections.unmodifiableMap(invert(JAVA_CTRL_CHARS_ESCAPE));
-    }
-
-    /**
-     * Used to invert an escape Map into an unescape Map
-     * @param map Map&lt;String, String&gt; to be inverted
-     * @return Map&lt;String, String&gt; inverted array
-     */
-    public static Map<CharSequence, CharSequence> invert(final Map<CharSequence, CharSequence> map) {
-        Map<CharSequence, CharSequence> newMap = new HashMap<>();
-        Iterator<Map.Entry<CharSequence, CharSequence>> it = map.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry<CharSequence, CharSequence> pair = it.next();
-            newMap.put((CharSequence) pair.getValue(), (CharSequence) pair.getKey());
-        }
-        return newMap;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaper.java b/src/main/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaper.java
deleted file mode 100644
index c3a519c..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/JavaUnicodeEscaper.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-/**
- * Translates codepoints to their Unicode escaped value suitable for Java source.
- *
- * @since 1.0
- */
-public class JavaUnicodeEscaper extends UnicodeEscaper {
-
-    /**
-     * <p>
-     * Constructs a <code>JavaUnicodeEscaper</code> above the specified value (exclusive).
-     * </p>
-     * 
-     * @param codepoint
-     *            above which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static JavaUnicodeEscaper above(final int codepoint) {
-        return outsideOf(0, codepoint);
-    }
-
-    /**
-     * <p>
-     * Constructs a <code>JavaUnicodeEscaper</code> below the specified value (exclusive).
-     * </p>
-     * 
-     * @param codepoint
-     *            below which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static JavaUnicodeEscaper below(final int codepoint) {
-        return outsideOf(codepoint, Integer.MAX_VALUE);
-    }
-
-    /**
-     * <p>
-     * Constructs a <code>JavaUnicodeEscaper</code> between the specified values (inclusive).
-     * </p>
-     * 
-     * @param codepointLow
-     *            above which to escape
-     * @param codepointHigh
-     *            below which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static JavaUnicodeEscaper between(final int codepointLow, final int codepointHigh) {
-        return new JavaUnicodeEscaper(codepointLow, codepointHigh, true);
-    }
-
-    /**
-     * <p>
-     * Constructs a <code>JavaUnicodeEscaper</code> outside of the specified values (exclusive).
-     * </p>
-     * 
-     * @param codepointLow
-     *            below which to escape
-     * @param codepointHigh
-     *            above which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static JavaUnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) {
-        return new JavaUnicodeEscaper(codepointLow, codepointHigh, false);
-    }
-
-    /**
-     * <p>
-     * Constructs a <code>JavaUnicodeEscaper</code> for the specified range. This is the underlying method for the
-     * other constructors/builders. The <code>below</code> and <code>above</code> boundaries are inclusive when
-     * <code>between</code> is <code>true</code> and exclusive when it is <code>false</code>.
-     * </p>
-     * 
-     * @param below
-     *            int value representing the lowest codepoint boundary
-     * @param above
-     *            int value representing the highest codepoint boundary
-     * @param between
-     *            whether to escape between the boundaries or outside them
-     */
-    public JavaUnicodeEscaper(final int below, final int above, final boolean between) {
-        super(below, above, between);
-    }
-
-    /**
-     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX\\uXXXX"}
-     * 
-     * @param codepoint
-     *            a Unicode code point
-     * @return the hex string for the given codepoint
-     */
-    @Override
-    protected String toUtf16Escape(final int codepoint) {
-        final char[] surrogatePair = Character.toChars(codepoint);
-        return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/LookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/LookupTranslator.java b/src/main/java/org/apache/commons/text/beta/translate/LookupTranslator.java
deleted file mode 100644
index 064ab27..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/LookupTranslator.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.security.InvalidParameterException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Translates a value using a lookup table.
- *
- * @since 1.0
- */
-public class LookupTranslator extends CharSequenceTranslator {
-
-    private final Map<String, String> lookupMap;
-    private final HashSet<Character> prefixSet;
-    private final int shortest;
-    private final int longest;
-
-    /**
-     * Define the lookup table to be used in translation
-     *
-     * Note that, as of Lang 3.1 (the orgin of this code), the key to the lookup
-     * table is converted to a java.lang.String. This is because we need the key
-     * to support hashCode and equals(Object), allowing it to be the key for a
-     * HashMap. See LANG-882.
-     *
-     * @param lookupMap Map&lt;CharSequence, CharSequence&gt; table of translator
-     *                  mappings
-     */
-    public LookupTranslator(final Map<CharSequence, CharSequence> lookupMap) {
-        if (lookupMap == null) {
-            throw new InvalidParameterException("lookupMap cannot be null");
-        }
-        this.lookupMap = new HashMap<>();
-        prefixSet = new HashSet<>();
-        int _shortest = Integer.MAX_VALUE;
-        int _longest = 0;
-        Iterator<Map.Entry<CharSequence, CharSequence>> it = lookupMap.entrySet().iterator();
-
-        while (it.hasNext()) {
-            Map.Entry<CharSequence, CharSequence> pair = it.next();
-            this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
-            this.prefixSet.add((pair.getKey()).charAt(0));
-            final int sz = pair.getKey().length();
-            if (sz < _shortest) {
-                _shortest = sz;
-            }
-            if (sz > _longest) {
-                _longest = sz;
-            }
-        }
-        shortest = _shortest;
-        longest = _longest;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        // check if translation exists for the input at position index
-        if (prefixSet.contains(input.charAt(index))) {
-            int max = longest;
-            if (index + longest > input.length()) {
-                max = input.length() - index;
-            }
-            // implement greedy algorithm by trying maximum match first
-            for (int i = max; i >= shortest; i--) {
-                final CharSequence subSeq = input.subSequence(index, index + i);
-                final String result = lookupMap.get(subSeq.toString());
-
-                if (result != null) {
-                    out.write(result);
-                    return i;
-                }
-            }
-        }
-        return 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/NumericEntityEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/NumericEntityEscaper.java b/src/main/java/org/apache/commons/text/beta/translate/NumericEntityEscaper.java
deleted file mode 100644
index ab6f4e0..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/NumericEntityEscaper.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Translates codepoints to their XML numeric entity escaped value.
- *
- * @since 1.0
- */
-public class NumericEntityEscaper extends CodePointTranslator {
-
-    private final int below;
-    private final int above;
-    private final boolean between;
-
-    /**
-     * <p>Constructs a <code>NumericEntityEscaper</code> for the specified range. This is
-     * the underlying method for the other constructors/builders. The <code>below</code>
-     * and <code>above</code> boundaries are inclusive when <code>between</code> is
-     * <code>true</code> and exclusive when it is <code>false</code>. </p>
-     *
-     * @param below int value representing the lowest codepoint boundary
-     * @param above int value representing the highest codepoint boundary
-     * @param between whether to escape between the boundaries or outside them
-     */
-    private NumericEntityEscaper(final int below, final int above, final boolean between) {
-        this.below = below;
-        this.above = above;
-        this.between = between;
-    }
-
-    /**
-     * <p>Constructs a <code>NumericEntityEscaper</code> for all characters. </p>
-     */
-    public NumericEntityEscaper() {
-        this(0, Integer.MAX_VALUE, true);
-    }
-
-    /**
-     * <p>Constructs a <code>NumericEntityEscaper</code> below the specified value (exclusive). </p>
-     *
-     * @param codepoint below which to escape
-     * @return the newly created {@code NumericEntityEscaper} instance
-     */
-    public static NumericEntityEscaper below(final int codepoint) {
-        return outsideOf(codepoint, Integer.MAX_VALUE);
-    }
-
-    /**
-     * <p>Constructs a <code>NumericEntityEscaper</code> above the specified value (exclusive). </p>
-     *
-     * @param codepoint above which to escape
-     * @return the newly created {@code NumericEntityEscaper} instance
-     */
-    public static NumericEntityEscaper above(final int codepoint) {
-        return outsideOf(0, codepoint);
-    }
-
-    /**
-     * <p>Constructs a <code>NumericEntityEscaper</code> between the specified values (inclusive). </p>
-     *
-     * @param codepointLow above which to escape
-     * @param codepointHigh below which to escape
-     * @return the newly created {@code NumericEntityEscaper} instance
-     */
-    public static NumericEntityEscaper between(final int codepointLow, final int codepointHigh) {
-        return new NumericEntityEscaper(codepointLow, codepointHigh, true);
-    }
-
-    /**
-     * <p>Constructs a <code>NumericEntityEscaper</code> outside of the specified values (exclusive). </p>
-     *
-     * @param codepointLow below which to escape
-     * @param codepointHigh above which to escape
-     * @return the newly created {@code NumericEntityEscaper} instance
-     */
-    public static NumericEntityEscaper outsideOf(final int codepointLow, final int codepointHigh) {
-        return new NumericEntityEscaper(codepointLow, codepointHigh, false);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean translate(final int codepoint, final Writer out) throws IOException {
-        if(between) {
-            if (codepoint < below || codepoint > above) {
-                return false;
-            }
-        } else {
-            if (codepoint >= below && codepoint <= above) {
-                return false;
-            }
-        }
-
-        out.write("&#");
-        out.write(Integer.toString(codepoint, 10));
-        out.write(';');
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/NumericEntityUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/NumericEntityUnescaper.java b/src/main/java/org/apache/commons/text/beta/translate/NumericEntityUnescaper.java
deleted file mode 100644
index 6d7b8c9..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/NumericEntityUnescaper.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Arrays;
-import java.util.EnumSet;
-
-/**
- * Translate XML numeric entities of the form &amp;#[xX]?\d+;? to 
- * the specific codepoint.
- *
- * Note that the semi-colon is optional.
- *
- * @since 1.0
- */
-public class NumericEntityUnescaper extends CharSequenceTranslator {
-
-    public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
-
-    // TODO?: Create an OptionsSet class to hide some of the conditional logic below
-    private final EnumSet<OPTION> options;
-
-    /**
-     * Create a UnicodeUnescaper.
-     *
-     * The constructor takes a list of options, only one type of which is currently 
-     * available (whether to allow, error or ignore the semi-colon on the end of a 
-     * numeric entity to being missing).
-     *
-     * For example, to support numeric entities without a ';':
-     *    new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional)
-     * and to throw an IllegalArgumentException when they're missing:
-     *    new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon)
-     *
-     * Note that the default behaviour is to ignore them. 
-     *
-     * @param options to apply to this unescaper
-     */
-    public NumericEntityUnescaper(final OPTION... options) {
-        if(options.length > 0) {
-            this.options = EnumSet.copyOf(Arrays.asList(options));
-        } else {
-            this.options = EnumSet.copyOf(Arrays.asList(new OPTION[] { OPTION.semiColonRequired }));
-        }
-    }
-
-    /**
-     * Whether the passed in option is currently set.
-     *
-     * @param option to check state of
-     * @return whether the option is set
-     */
-    public boolean isSet(final OPTION option) { 
-        return options == null ? false : options.contains(option);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        final int seqEnd = input.length();
-        // Uses -2 to ensure there is something after the &#
-        if(input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
-            int start = index + 2;
-            boolean isHex = false;
-
-            final char firstChar = input.charAt(start);
-            if(firstChar == 'x' || firstChar == 'X') {
-                start++;
-                isHex = true;
-
-                // Check there's more than just an x after the &#
-                if(start == seqEnd) {
-                    return 0;
-                }
-            }
-
-            int end = start;
-            // Note that this supports character codes without a ; on the end
-            while(end < seqEnd && ( input.charAt(end) >= '0' && input.charAt(end) <= '9' ||
-                                    input.charAt(end) >= 'a' && input.charAt(end) <= 'f' ||
-                                    input.charAt(end) >= 'A' && input.charAt(end) <= 'F' ) )
-            {
-                end++;
-            }
-
-            final boolean semiNext = end != seqEnd && input.charAt(end) == ';';
-
-            if(!semiNext) {
-                if(isSet(OPTION.semiColonRequired)) {
-                    return 0;
-                } else
-                if(isSet(OPTION.errorIfNoSemiColon)) {
-                    throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
-                }
-            }
-
-            int entityValue;
-            try {
-                if(isHex) {
-                    entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 16);
-                } else {
-                    entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 10);
-                }
-            } catch(final NumberFormatException nfe) {
-                return 0;
-            }
-
-            if(entityValue > 0xFFFF) {
-                final char[] chrs = Character.toChars(entityValue);
-                out.write(chrs[0]);
-                out.write(chrs[1]);
-            } else {
-                out.write(entityValue);
-            }
-
-            return 2 + end - start + (isHex ? 1 : 0) + (semiNext ? 1 : 0);
-        }
-        return 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/OctalUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/OctalUnescaper.java b/src/main/java/org/apache/commons/text/beta/translate/OctalUnescaper.java
deleted file mode 100644
index e30ff09..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/OctalUnescaper.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Translate escaped octal Strings back to their octal values.
- *
- * For example, "\45" should go back to being the specific value (a %).
- *
- * Note that this currently only supports the viable range of octal for Java; namely 
- * 1 to 377. This is because parsing Java is the main use case.
- *
- * @since 1.0
- */
-public class OctalUnescaper extends CharSequenceTranslator {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        final int remaining = input.length() - index - 1; // how many characters left, ignoring the first \
-        final StringBuilder builder = new StringBuilder();
-        if(input.charAt(index) == '\\' && remaining > 0 && isOctalDigit(input.charAt(index + 1)) ) {
-            final int next = index + 1;
-            final int next2 = index + 2;
-            final int next3 = index + 3;
-
-            // we know this is good as we checked it in the if block above
-            builder.append(input.charAt(next));
-
-            if(remaining > 1 && isOctalDigit(input.charAt(next2))) {
-                builder.append(input.charAt(next2));
-                if(remaining > 2 && isZeroToThree(input.charAt(next)) && isOctalDigit(input.charAt(next3))) {
-                    builder.append(input.charAt(next3));
-                }
-            }
-
-            out.write( Integer.parseInt(builder.toString(), 8) );
-            return 1 + builder.length();
-        }
-        return 0;
-    }
-
-    /**
-     * Checks if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
-     * @param ch the char to check
-     * @return true if the given char is the character representation of one of the digits from 0 to 7
-     */
-    private boolean isOctalDigit(final char ch) {
-        return ch >= '0' && ch <= '7';
-    }
-
-    /**
-     * Checks if the given char is the character representation of one of the digit from 0 to 3.
-     * @param ch the char to check
-     * @return true if the given char is the character representation of one of the digits from 0 to 3
-     */
-    private boolean isZeroToThree(final char ch) {
-        return ch >= '0' && ch <= '3';
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/SingleLookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/SingleLookupTranslator.java b/src/main/java/org/apache/commons/text/beta/translate/SingleLookupTranslator.java
deleted file mode 100644
index ffb5489..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/SingleLookupTranslator.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * Translates a value using a lookup table.
- * But doesn't translate if that value is already translated.
- *
- * @since 1.0
- */
-public class SingleLookupTranslator extends CharSequenceTranslator {
-
-    private final Map<String, String> lookupMap;
-    private final HashSet<Character> prefixSet;
-    private final int shortest;
-    private final int longest;
-    private final int shortestValue;
-    private final int longestValue;
-
-    /**
-     * Define the look tables to be used in translation.
-     * <p>
-     * Note that, as of Lang 3.1, the key to the lookup table is converted to a
-     * java.lang.String. This is because we need the key to support hashCode and
-     * equals(Object), allowing it to be the key for a HashMap. See LANG-882.
-     * <p>
-     * Also note that, multiple lookup tables should be passed to this translator
-     * instead of passing multiple instances of this translator to the
-     * AggregateTranslator. Because, this translator only checks the values of the
-     * lookup table passed to this instance while deciding whether a value is
-     * already translated or not.
-     *
-     * @param inputMaps, an array of Map&lt;CharSequence, CharSequence&gt;.
-     */
-    public SingleLookupTranslator(Map<CharSequence, CharSequence>... inputMaps) {
-        Map<CharSequence, CharSequence> lookup = new HashMap<>();
-        for (Map<CharSequence, CharSequence> input : inputMaps) {
-            Iterator<Map.Entry<CharSequence, CharSequence>> it = input.entrySet().iterator();
-            while (it.hasNext()) {
-                Map.Entry<CharSequence, CharSequence> pair = it.next();
-                lookup.put(pair.getKey(), pair.getValue());
-            }
-        }
-        lookupMap = new HashMap<String, String>();
-        prefixSet = new HashSet<Character>();
-        int _shortest = Integer.MAX_VALUE;
-        int _longest = 0;
-        int _shortestValue = Integer.MAX_VALUE;
-        int _longestValue = 0;
-        if (lookup != null) {
-            Iterator<Map.Entry<CharSequence, CharSequence>> it = lookup.entrySet().iterator();
-            while (it.hasNext()) {
-                Map.Entry<CharSequence, CharSequence> pair = it.next();
-                this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
-                this.prefixSet.add(pair.getKey().charAt(0));
-                final int sz = pair.getKey().length();
-                if (sz < _shortest) {
-                    _shortest = sz;
-                }
-                if (sz > _longest) {
-                    _longest = sz;
-                }
-                final int sizeOfValue = lookup.get(pair.getKey()).length();
-                if (sizeOfValue < _shortestValue) {
-                    _shortestValue = sizeOfValue;
-                }
-                if (sizeOfValue > _longestValue) {
-                    _longestValue = sizeOfValue;
-                }
-            }
-        }
-        shortest = _shortest;
-        longest = _longest;
-        shortestValue = _shortestValue;
-        longestValue = _longestValue;
-    }
-
-    /**
-     * Translate a set of codepoints, represented by an int index into a CharSequence,
-     * into another set of codepoints. The number of codepoints consumed must be returned,
-     * and the only IOExceptions thrown must be from interacting with the Writer so that
-     * the top level API may reliably ignore StringWriter IOExceptions.
-     *
-     * @param input CharSequence that is being translated
-     * @param index int representing the current point of translation
-     * @param out   Writer to translate the text to
-     * @return int count of codepoints consumed
-     * @throws IOException if and only if the Writer produces an IOException
-     */
-    @Override
-    public int translate(CharSequence input, int index, Writer out) throws IOException {
-        // check if already translated
-        int maxValue = longestValue;
-        if (index + maxValue > input.length()) {
-            maxValue = input.length() - index;
-        }
-        // implement greedy algorithm to check all the possible 'value' matches
-        // for which we need to skip translation.
-        for (int i = maxValue; i >= shortestValue; i--) {
-            final CharSequence subSeq = input.subSequence(index, index + i);
-            // If the sub-string is already translated, return without translating.
-            if (lookupMap.containsValue(subSeq.toString())) {
-                return 0;
-            }
-        }
-
-        // check if translation exists for the input at position index
-        if (prefixSet.contains(input.charAt(index))) {
-            int max = longest;
-            if (index + longest > input.length()) {
-                max = input.length() - index;
-            }
-            // implement greedy algorithm by trying maximum match first
-            for (int i = max; i >= shortest; i--) {
-                final CharSequence subSeq = input.subSequence(index, index + i);
-                final String result = lookupMap.get(subSeq.toString());
-
-                if (result != null) {
-                    out.write(result);
-                    return i;
-                }
-            }
-        }
-        return 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/SinglePassTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/SinglePassTranslator.java b/src/main/java/org/apache/commons/text/beta/translate/SinglePassTranslator.java
deleted file mode 100644
index 1d06ec6..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/SinglePassTranslator.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Abstract translator for processing whole input in single pass.
- * Handles initial index checking and counting of returned code points.
- */
-abstract class SinglePassTranslator extends CharSequenceTranslator {
-
-    @Override
-    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        if (index != 0) {
-            throw new IllegalArgumentException(getClassName() + ".translate(final CharSequence input, final int " +
-                    "index, final Writer out) can not handle a non-zero index.");
-        }
-
-        translateWhole(input, out);
-
-        return Character.codePointCount(input, index, input.length());
-    }
-
-    private String getClassName() {
-        final Class<? extends SinglePassTranslator> clazz = this.getClass();
-        return clazz.isAnonymousClass() ?  clazz.getName() : clazz.getSimpleName();
-    }
-
-    /**
-     * Translate whole set of code points passed in input.
-     *
-     * @param input CharSequence that is being translated
-     * @param out Writer to translate the text to
-     * @return total count of codepoints in input
-     * @throws IOException if and only if the Writer produces an IOException
-     */
-    abstract void translateWhole(final CharSequence input, final Writer out) throws IOException;
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/UnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/UnicodeEscaper.java b/src/main/java/org/apache/commons/text/beta/translate/UnicodeEscaper.java
deleted file mode 100644
index 3b8c983..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/UnicodeEscaper.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Translates codepoints to their Unicode escaped value.
- *
- * @since 1.0
- */
-public class UnicodeEscaper extends CodePointTranslator {
-
-    private final int below;
-    private final int above;
-    private final boolean between;
-
-    /**
-     * <p>Constructs a <code>UnicodeEscaper</code> for all characters. </p>
-     */
-    public UnicodeEscaper(){
-        this(0, Integer.MAX_VALUE, true);
-    }
-
-    /**
-     * <p>Constructs a <code>UnicodeEscaper</code> for the specified range. This is
-     * the underlying method for the other constructors/builders. The <code>below</code>
-     * and <code>above</code> boundaries are inclusive when <code>between</code> is
-     * <code>true</code> and exclusive when it is <code>false</code>. </p>
-     *
-     * @param below int value representing the lowest codepoint boundary
-     * @param above int value representing the highest codepoint boundary
-     * @param between whether to escape between the boundaries or outside them
-     */
-    protected UnicodeEscaper(final int below, final int above, final boolean between) {
-        this.below = below;
-        this.above = above;
-        this.between = between;
-    }
-
-    /**
-     * <p>Constructs a <code>UnicodeEscaper</code> below the specified value (exclusive). </p>
-     *
-     * @param codepoint below which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static UnicodeEscaper below(final int codepoint) {
-        return outsideOf(codepoint, Integer.MAX_VALUE);
-    }
-
-    /**
-     * <p>Constructs a <code>UnicodeEscaper</code> above the specified value (exclusive). </p>
-     *
-     * @param codepoint above which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static UnicodeEscaper above(final int codepoint) {
-        return outsideOf(0, codepoint);
-    }
-
-    /**
-     * <p>Constructs a <code>UnicodeEscaper</code> outside of the specified values (exclusive). </p>
-     *
-     * @param codepointLow below which to escape
-     * @param codepointHigh above which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static UnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) {
-        return new UnicodeEscaper(codepointLow, codepointHigh, false);
-    }
-
-    /**
-     * <p>Constructs a <code>UnicodeEscaper</code> between the specified values (inclusive). </p>
-     *
-     * @param codepointLow above which to escape
-     * @param codepointHigh below which to escape
-     * @return the newly created {@code UnicodeEscaper} instance
-     */
-    public static UnicodeEscaper between(final int codepointLow, final int codepointHigh) {
-        return new UnicodeEscaper(codepointLow, codepointHigh, true);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean translate(final int codepoint, final Writer out) throws IOException {
-        if (between) {
-            if (codepoint < below || codepoint > above) {
-                return false;
-            }
-        } else {
-            if (codepoint >= below && codepoint <= above) {
-                return false;
-            }
-        }
-
-        // TODO: Handle potential + sign per various Unicode escape implementations
-        if (codepoint > 0xffff) {
-            out.write(toUtf16Escape(codepoint));
-        } else {
-          out.write("\\u");
-          out.write(HEX_DIGITS[(codepoint >> 12) & 15]);
-          out.write(HEX_DIGITS[(codepoint >> 8) & 15]);
-          out.write(HEX_DIGITS[(codepoint >> 4) & 15]);
-          out.write(HEX_DIGITS[(codepoint) & 15]);
-        }
-        return true;
-    }
-
-    /**
-     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX"}
-     * 
-     * @param codepoint
-     *            a Unicode code point
-     * @return the hex string for the given codepoint
-     *
-     */
-    protected String toUtf16Escape(final int codepoint) {
-        return "\\u" + hex(codepoint);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnescaper.java b/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnescaper.java
deleted file mode 100644
index fcd1e3f..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnescaper.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Translates escaped Unicode values of the form \\u+\d\d\d\d back to 
- * Unicode. It supports multiple 'u' characters and will work with or 
- * without the +.
- *
- * @since 1.0
- */
-public class UnicodeUnescaper extends CharSequenceTranslator {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-        if (input.charAt(index) == '\\' && index + 1 < input.length() && input.charAt(index + 1) == 'u') {
-            // consume optional additional 'u' chars
-            int i = 2;
-            while (index + i < input.length() && input.charAt(index + i) == 'u') {
-                i++;
-            }
-
-            if (index + i < input.length() && input.charAt(index + i) == '+') {
-                i++;
-            }
-
-            if (index + i + 4 <= input.length()) {
-                // Get 4 hex digits
-                final CharSequence unicode = input.subSequence(index + i, index + i + 4);
-
-                try {
-                    final int value = Integer.parseInt(unicode.toString(), 16);
-                    out.write((char) value);
-                } catch (final NumberFormatException nfe) {
-                    throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
-                }
-                return i + 4;
-            }
-            throw new IllegalArgumentException("Less than 4 hex digits in unicode value: '" + input.subSequence(index, input.length())
-                    + "' due to end of CharSequence");
-        }
-        return 0;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemover.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemover.java b/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemover.java
deleted file mode 100644
index d316863..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/UnicodeUnpairedSurrogateRemover.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import java.io.IOException;
-import java.io.Writer;
-
-/**
- * Helper subclass to CharSequenceTranslator to remove unpaired surrogates.
- *
- * @since 1.0
- */
-public class UnicodeUnpairedSurrogateRemover extends CodePointTranslator {
-    /**
-     * Implementation of translate that throws out unpaired surrogates. 
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean translate(final int codepoint, final Writer out) throws IOException {
-        if (codepoint >= Character.MIN_SURROGATE && codepoint <= Character.MAX_SURROGATE) {
-            // It's a surrogate. Write nothing and say we've translated.
-            return true;
-        }
-        // It's not a surrogate. Don't translate it.
-        return false;
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/translate/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/translate/package-info.java b/src/main/java/org/apache/commons/text/beta/translate/package-info.java
deleted file mode 100644
index 6376a56..0000000
--- a/src/main/java/org/apache/commons/text/beta/translate/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * <p> An API for creating text translation routines from a set of smaller building blocks. Initially created to make it
- * possible for the user to customize the rules in the StringEscapeUtils class.</p>
- * <p>These classes are immutable, and therefore thread-safe.</p>
- *
- * @since 1.0
- */
-package org.apache.commons.text.beta.translate;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/CommandVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/CommandVisitor.java b/src/main/java/org/apache/commons/text/diff/CommandVisitor.java
new file mode 100644
index 0000000..7e5f40f
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/CommandVisitor.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+/**
+ * This interface should be implemented by user object to walk
+ * through {@link EditScript EditScript} objects.
+ * <p>
+ * Users should implement this interface in order to walk through
+ * the {@link EditScript EditScript} object created by the comparison
+ * of two sequences. This is a direct application of the visitor
+ * design pattern. The {@link EditScript#visit EditScript.visit}
+ * method takes an object implementing this interface as an argument,
+ * it will perform the loop over all commands in the script and the
+ * proper methods of the user class will be called as the commands are
+ * encountered.
+ * </p>
+ * <p>
+ * The implementation of the user visitor class will depend on the
+ * need. Here are two examples.
+ * </p>
+ * <p>
+ * The first example is a visitor that build the longest common
+ * subsequence:
+ * </p>
+ * <pre>
+ * import org.apache.commons.text.diff.CommandVisitor;
+ *
+ * import java.util.ArrayList;
+ *
+ * public class LongestCommonSubSequence implements CommandVisitor {
+ *
+ *   public LongestCommonSubSequence() {
+ *     a = new ArrayList();
+ *   }
+ *
+ *   public void visitInsertCommand(Object object) {
+ *   }
+ *
+ *   public void visitKeepCommand(Object object) {
+ *     a.add(object);
+ *   }
+ *
+ *   public void visitDeleteCommand(Object object) {
+ *   }
+ *
+ *   public Object[] getSubSequence() {
+ *     return a.toArray();
+ *   }
+ *
+ *   private ArrayList a;
+ *
+ * }
+ * </pre>
+ * <p>
+ * The second example is a visitor that shows the commands and the way
+ * they transform the first sequence into the second one:
+ * <pre>
+ * import org.apache.commons.text.diff.CommandVisitor;
+ *
+ * import java.util.Arrays;
+ * import java.util.ArrayList;
+ * import java.util.Iterator;
+ *
+ * public class ShowVisitor implements CommandVisitor {
+ *
+ *   public ShowVisitor(Object[] sequence1) {
+ *     v = new ArrayList();
+ *     v.addAll(Arrays.asList(sequence1));
+ *     index = 0;
+ *   }
+ *
+ *   public void visitInsertCommand(Object object) {
+ *     v.insertElementAt(object, index++);
+ *     display("insert", object);
+ *   }
+ *
+ *   public void visitKeepCommand(Object object) {
+ *     ++index;
+ *     display("keep  ", object);
+ *   }
+ *
+ *   public void visitDeleteCommand(Object object) {
+ *     v.remove(index);
+ *     display("delete", object);
+ *   }
+ *
+ *   private void display(String commandName, Object object) {
+ *     System.out.println(commandName + " " + object + ": " + this);
+ *   }
+ *
+ *   public String toString() {
+ *     StringBuffer buffer = new StringBuffer();
+ *     for (Iterator iter = v.iterator(); iter.hasNext();) {
+ *       buffer.append(' ').append(iter.next());
+ *     }
+ *     return buffer.toString();
+ *   }
+ *
+ *   private ArrayList v;
+ *   private int index;
+ *
+ * }
+ * </pre>
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public interface CommandVisitor<T> {
+
+    /**
+     * Method called when an insert command is encountered.
+     *
+     * @param object object to insert (this object comes from the second sequence)
+     */
+    void visitInsertCommand(T object);
+
+    /**
+     * Method called when a keep command is encountered.
+     *
+     * @param object object to keep (this object comes from the first sequence)
+     */
+    void visitKeepCommand(T object);
+
+    /**
+     * Method called when a delete command is encountered.
+     *
+     * @param object object to delete (this object comes from the first sequence)
+     */
+    void visitDeleteCommand(T object);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/DeleteCommand.java b/src/main/java/org/apache/commons/text/diff/DeleteCommand.java
new file mode 100644
index 0000000..8173718
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/DeleteCommand.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+/**
+ * Command representing the deletion of one object of the first sequence.
+ * <p>
+ * When one object of the first sequence has no corresponding object in the
+ * second sequence at the right place, the {@link EditScript edit script}
+ * transforming the first sequence into the second sequence uses an instance of
+ * this class to represent the deletion of this object. The objects embedded in
+ * these type of commands always come from the first sequence.
+ * </p>
+ *
+ * @see StringsComparator
+ * @see EditScript
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public class DeleteCommand<T> extends EditCommand<T> {
+
+    /**
+     * Simple constructor. Creates a new instance of {@link DeleteCommand}.
+     *
+     * @param object  the object of the first sequence that should be deleted
+     */
+    public DeleteCommand(final T object) {
+        super(object);
+    }
+
+    /**
+     * Accept a visitor. When a <code>DeleteCommand</code> accepts a visitor, it calls
+     * its {@link CommandVisitor#visitDeleteCommand visitDeleteCommand} method.
+     *
+     * @param visitor  the visitor to be accepted
+     */
+    @Override
+    public void accept(final CommandVisitor<T> visitor) {
+        visitor.visitDeleteCommand(getObject());
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/diff/EditCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/diff/EditCommand.java b/src/main/java/org/apache/commons/text/diff/EditCommand.java
new file mode 100644
index 0000000..7920206
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/diff/EditCommand.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.diff;
+
+/**
+ * Abstract base class for all commands used to transform an objects sequence
+ * into another one.
+ * <p>
+ * When two objects sequences are compared through the
+ * {@link StringsComparator#getScript StringsComparator.getScript} method,
+ * the result is provided has a {@link EditScript script} containing the commands
+ * that progressively transform the first sequence into the second one.
+ * </p>
+ * <p>
+ * There are only three types of commands, all of which are subclasses of this
+ * abstract class. Each command is associated with one object belonging to at
+ * least one of the sequences. These commands are {@link InsertCommand
+ * InsertCommand} which correspond to an object of the second sequence being
+ * inserted into the first sequence, {@link DeleteCommand DeleteCommand} which
+ * correspond to an object of the first sequence being removed and
+ * {@link KeepCommand KeepCommand} which correspond to an object of the first
+ * sequence which <code>equals</code> an object in the second sequence. It is
+ * guaranteed that comparison is always performed this way (i.e. the
+ * <code>equals</code> method of the object from the first sequence is used and
+ * the object passed as an argument comes from the second sequence) ; this can
+ * be important if subclassing is used for some elements in the first sequence
+ * and the <code>equals</code> method is specialized.
+ * </p>
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Collections 4.0.
+ * </p>
+ *
+ * @see StringsComparator
+ * @see EditScript
+ *
+ * @param <T> object type
+ * @since 1.0
+ */
+public abstract class EditCommand<T> {
+
+    /** Object on which the command should be applied. */
+    private final T object;
+
+    /**
+     * Simple constructor. Creates a new instance of EditCommand
+     *
+     * @param object  reference to the object associated with this command, this
+     *   refers to an element of one of the sequences being compared
+     */
+    protected EditCommand(final T object) {
+        this.object = object;
+    }
+
+    /**
+     * Returns the object associated with this command.
+     *
+     * @return the object on which the command is applied
+     */
+    protected T getObject() {
+        return object;
+    }
+
+    /**
+     * Accept a visitor.
+     * <p>
+     * This method is invoked for each commands belonging to
+     * an {@link EditScript EditScript}, in order to implement the visitor design pattern
+     *
+     * @param visitor  the visitor to be accepted
+     */
+    public abstract void accept(CommandVisitor<T> visitor);
+
+}


[28/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/StrBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrBuilder.java b/src/main/java/org/apache/commons/text/StrBuilder.java
new file mode 100644
index 0000000..a3bc429
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/StrBuilder.java
@@ -0,0 +1,3092 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.Writer;
+import java.nio.CharBuffer;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Builds a string from constituent parts providing a more flexible and powerful API
+ * than StringBuffer.
+ * <p>
+ * The main differences from StringBuffer/StringBuilder are:
+ * </p>
+ * <ul>
+ * <li>Not synchronized</li>
+ * <li>Not final</li>
+ * <li>Subclasses have direct access to character array</li>
+ * <li>Additional methods
+ *  <ul>
+ *   <li>appendWithSeparators - adds an array of values, with a separator</li>
+ *   <li>appendPadding - adds a length padding characters</li>
+ *   <li>appendFixedLength - adds a fixed width field to the builder</li>
+ *   <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
+ *   <li>delete - delete char or string</li>
+ *   <li>replace - search and replace for a char or string</li>
+ *   <li>leftString/rightString/midString - substring without exceptions</li>
+ *   <li>contains - whether the builder contains a char or string</li>
+ *   <li>size/clear/isEmpty - collections style API methods</li>
+ *  </ul>
+ * </li>
+ * <li>Views
+ *  <ul>
+ *   <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
+ *   <li>asReader - uses the internal buffer as the source of a Reader</li>
+ *   <li>asWriter - allows a Writer to write directly to the internal buffer</li>
+ *  </ul>
+ * </li>
+ * </ul>
+ * <p>
+ * The aim has been to provide an API that mimics very closely what StringBuffer
+ * provides, but with additional methods. It should be noted that some edge cases,
+ * with invalid indices or null input, have been altered - see individual methods.
+ * The biggest of these changes is that by default, null will not output the text
+ * 'null'. This can be controlled by a property, {@link #setNullText(String)}.
+ * </p>
+ *
+ * @since 1.0
+ *
+ */
+public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
+
+    /**
+     * The extra capacity for new builders.
+     */
+    static final int CAPACITY = 32;
+
+    /**
+     * Required for serialization support.
+     *
+     * @see java.io.Serializable
+     */
+    private static final long serialVersionUID = 7628716375283629643L;
+
+    /** Internal data storage. */
+    char[] buffer; // package-protected for test code use only
+    /** Current size of the buffer. */
+    private int size;
+    /** The new line. */
+    private String newLine;
+    /** The null text. */
+    private String nullText;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor that creates an empty builder initial capacity 32 characters.
+     */
+    public StrBuilder() {
+        this(CAPACITY);
+    }
+
+    /**
+     * Constructor that creates an empty builder the specified initial capacity.
+     *
+     * @param initialCapacity  the initial capacity, zero or less will be converted to 32
+     */
+    public StrBuilder(int initialCapacity) {
+        super();
+        if (initialCapacity <= 0) {
+            initialCapacity = CAPACITY;
+        }
+        buffer = new char[initialCapacity];
+    }
+
+    /**
+     * Constructor that creates a builder from the string, allocating
+     * 32 extra characters for growth.
+     *
+     * @param str  the string to copy, null treated as blank string
+     */
+    public StrBuilder(final String str) {
+        super();
+        if (str == null) {
+            buffer = new char[CAPACITY];
+        } else {
+            buffer = new char[str.length() + CAPACITY];
+            append(str);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the text to be appended when a new line is added.
+     *
+     * @return the new line text, null means use system default
+     */
+    public String getNewLineText() {
+        return newLine;
+    }
+
+    /**
+     * Sets the text to be appended when a new line is added.
+     *
+     * @param newLine  the new line text, null means use system default
+     * @return this, to enable chaining
+     */
+    public StrBuilder setNewLineText(final String newLine) {
+        this.newLine = newLine;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the text to be appended when null is added.
+     *
+     * @return the null text, null means no append
+     */
+    public String getNullText() {
+        return nullText;
+    }
+
+    /**
+     * Sets the text to be appended when null is added.
+     *
+     * @param nullText  the null text, null means no append
+     * @return this, to enable chaining
+     */
+    public StrBuilder setNullText(String nullText) {
+        if (nullText != null && nullText.isEmpty()) {
+            nullText = null;
+        }
+        this.nullText = nullText;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the length of the string builder.
+     *
+     * @return the length
+     */
+    @Override
+    public int length() {
+        return size;
+    }
+
+    /**
+     * Updates the length of the builder by either dropping the last characters
+     * or adding filler of Unicode zero.
+     *
+     * @param length  the length to set to, must be zero or positive
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the length is negative
+     */
+    public StrBuilder setLength(final int length) {
+        if (length < 0) {
+            throw new StringIndexOutOfBoundsException(length);
+        }
+        if (length < size) {
+            size = length;
+        } else if (length > size) {
+            ensureCapacity(length);
+            final int oldEnd = size;
+            final int newEnd = length;
+            size = length;
+            for (int i = oldEnd; i < newEnd; i++) {
+                buffer[i] = '\0';
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the current size of the internal character array buffer.
+     *
+     * @return the capacity
+     */
+    public int capacity() {
+        return buffer.length;
+    }
+
+    /**
+     * Checks the capacity and ensures that it is at least the size specified.
+     *
+     * @param capacity  the capacity to ensure
+     * @return this, to enable chaining
+     */
+    public StrBuilder ensureCapacity(final int capacity) {
+        if (capacity > buffer.length) {
+            final char[] old = buffer;
+            buffer = new char[capacity * 2];
+            System.arraycopy(old, 0, buffer, 0, size);
+        }
+        return this;
+    }
+
+    /**
+     * Minimizes the capacity to the actual length of the string.
+     *
+     * @return this, to enable chaining
+     */
+    public StrBuilder minimizeCapacity() {
+        if (buffer.length > length()) {
+            final char[] old = buffer;
+            buffer = new char[length()];
+            System.arraycopy(old, 0, buffer, 0, size);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the length of the string builder.
+     * <p>
+     * This method is the same as {@link #length()} and is provided to match the
+     * API of Collections.
+     *
+     * @return the length
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Checks is the string builder is empty (convenience Collections API style method).
+     * <p>
+     * This method is the same as checking {@link #length()} and is provided to match the
+     * API of Collections.
+     *
+     * @return <code>true</code> if the size is <code>0</code>.
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Clears the string builder (convenience Collections API style method).
+     * <p>
+     * This method does not reduce the size of the internal character buffer.
+     * To do that, call <code>clear()</code> followed by {@link #minimizeCapacity()}.
+     * <p>
+     * This method is the same as {@link #setLength(int)} called with zero
+     * and is provided to match the API of Collections.
+     *
+     * @return this, to enable chaining
+     */
+    public StrBuilder clear() {
+        size = 0;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character at the specified index.
+     *
+     * @see #setCharAt(int, char)
+     * @see #deleteCharAt(int)
+     * @param index  the index to retrieve, must be valid
+     * @return the character at the index
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    @Override
+    public char charAt(final int index) {
+        if (index < 0 || index >= length()) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        return buffer[index];
+    }
+
+    /**
+     * Sets the character at the specified index.
+     *
+     * @see #charAt(int)
+     * @see #deleteCharAt(int)
+     * @param index  the index to set
+     * @param ch  the new character
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder setCharAt(final int index, final char ch) {
+        if (index < 0 || index >= length()) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        buffer[index] = ch;
+        return this;
+    }
+
+    /**
+     * Deletes the character at the specified index.
+     *
+     * @see #charAt(int)
+     * @see #setCharAt(int, char)
+     * @param index  the index to delete
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder deleteCharAt(final int index) {
+        if (index < 0 || index >= size) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        deleteImpl(index, index + 1, 1);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Copies the builder's character array into a new character array.
+     *
+     * @return a new array that represents the contents of the builder
+     */
+    public char[] toCharArray() {
+        if (size == 0) {
+            return new char[0];
+        }
+        final char[] chars = new char[size];
+        System.arraycopy(buffer, 0, chars, 0, size);
+        return chars;
+    }
+
+    /**
+     * Copies part of the builder's character array into a new character array.
+     *
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param endIndex  the end index, exclusive, must be valid except that
+     *  if too large it is treated as end of string
+     * @return a new array that holds part of the contents of the builder
+     * @throws IndexOutOfBoundsException if startIndex is invalid,
+     *  or if endIndex is invalid (but endIndex greater than size is valid)
+     */
+    public char[] toCharArray(final int startIndex, int endIndex) {
+        endIndex = validateRange(startIndex, endIndex);
+        final int len = endIndex - startIndex;
+        if (len == 0) {
+            return new char[0];
+        }
+        final char[] chars = new char[len];
+        System.arraycopy(buffer, startIndex, chars, 0, len);
+        return chars;
+    }
+
+    /**
+     * Copies the character array into the specified array.
+     *
+     * @param destination  the destination array, null will cause an array to be created
+     * @return the input array, unless that was null or too small
+     */
+    public char[] getChars(char[] destination) {
+        final int len = length();
+        if (destination == null || destination.length < len) {
+            destination = new char[len];
+        }
+        System.arraycopy(buffer, 0, destination, 0, len);
+        return destination;
+    }
+
+    /**
+     * Copies the character array into the specified array.
+     *
+     * @param startIndex  first index to copy, inclusive, must be valid
+     * @param endIndex  last index, exclusive, must be valid
+     * @param destination  the destination array, must not be null or too small
+     * @param destinationIndex  the index to start copying in destination
+     * @throws NullPointerException if the array is null
+     * @throws IndexOutOfBoundsException if any index is invalid
+     */
+    public void getChars(final int startIndex,
+                         final int endIndex,
+                         final char[] destination,
+                         final int destinationIndex) {
+        if (startIndex < 0) {
+            throw new StringIndexOutOfBoundsException(startIndex);
+        }
+        if (endIndex < 0 || endIndex > length()) {
+            throw new StringIndexOutOfBoundsException(endIndex);
+        }
+        if (startIndex > endIndex) {
+            throw new StringIndexOutOfBoundsException("end < start");
+        }
+        System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * If possible, reads chars from the provided {@link Readable} directly into underlying
+     * character buffer without making extra copies.
+     *
+     * @param readable  object to read from
+     * @return the number of characters read
+     * @throws IOException if an I/O error occurs
+     *
+     * @see #appendTo(Appendable)
+     */
+    public int readFrom(final Readable readable) throws IOException {
+        final int oldSize = size;
+        if (readable instanceof Reader) {
+            final Reader r = (Reader) readable;
+            ensureCapacity(size + 1);
+            int read;
+            while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
+                size += read;
+                ensureCapacity(size + 1);
+            }
+        } else if (readable instanceof CharBuffer) {
+            final CharBuffer cb = (CharBuffer) readable;
+            final int remaining = cb.remaining();
+            ensureCapacity(size + remaining);
+            cb.get(buffer, size, remaining);
+            size += remaining;
+        } else {
+            while (true) {
+                ensureCapacity(size + 1);
+                final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
+                final int read = readable.read(buf);
+                if (read == -1) {
+                    break;
+                }
+                size += read;
+            }
+        }
+        return size - oldSize;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the new line string to this string builder.
+     * <p>
+     * The new line string can be altered using {@link #setNewLineText(String)}.
+     * This might be used to force the output to always use Unix line endings
+     * even when on Windows.
+     *
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendNewLine() {
+        if (newLine == null)  {
+            append(System.getProperty("line.separator"));
+            return this;
+        }
+        return append(newLine);
+    }
+
+    /**
+     * Appends the text representing <code>null</code> to this string builder.
+     *
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendNull() {
+        if (nullText == null)  {
+            return this;
+        }
+        return append(nullText);
+    }
+
+    /**
+     * Appends an object to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param obj  the object to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final Object obj) {
+        if (obj == null) {
+            return appendNull();
+        }
+        if (obj instanceof CharSequence) {
+            return append((CharSequence) obj);
+        }
+        return append(obj.toString());
+    }
+
+    /**
+     * Appends a CharSequence to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param seq  the CharSequence to append
+     * @return this, to enable chaining
+     */
+    @Override
+    public StrBuilder append(final CharSequence seq) {
+        if (seq == null) {
+            return appendNull();
+        }
+        if (seq instanceof StrBuilder) {
+            return append((StrBuilder) seq);
+        }
+        if (seq instanceof StringBuilder) {
+            return append((StringBuilder) seq);
+        }
+        if (seq instanceof StringBuffer) {
+            return append((StringBuffer) seq);
+        }
+        if (seq instanceof CharBuffer) {
+            return append((CharBuffer) seq);
+        }
+        return append(seq.toString());
+    }
+
+    /**
+     * Appends part of a CharSequence to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param seq  the CharSequence to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    @Override
+    public StrBuilder append(final CharSequence seq, final int startIndex, final int length) {
+        if (seq == null) {
+            return appendNull();
+        }
+        return append(seq.toString(), startIndex, length);
+    }
+
+    /**
+     * Appends a string to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final String str) {
+        if (str == null) {
+            return appendNull();
+        }
+        final int strLen = str.length();
+        if (strLen > 0) {
+            final int len = length();
+            ensureCapacity(len + strLen);
+            str.getChars(0, strLen, buffer, len);
+            size += strLen;
+        }
+        return this;
+    }
+
+
+    /**
+     * Appends part of a string to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final String str, final int startIndex, final int length) {
+        if (str == null) {
+            return appendNull();
+        }
+        if (startIndex < 0 || startIndex > str.length()) {
+            throw new StringIndexOutOfBoundsException("startIndex must be valid");
+        }
+        if (length < 0 || (startIndex + length) > str.length()) {
+            throw new StringIndexOutOfBoundsException("length must be valid");
+        }
+        if (length > 0) {
+            final int len = length();
+            ensureCapacity(len + length);
+            str.getChars(startIndex, startIndex + length, buffer, len);
+            size += length;
+        }
+        return this;
+    }
+
+    /**
+     * Calls {@link String#format(String, Object...)} and appends the result.
+     *
+     * @param format the format string
+     * @param objs the objects to use in the format string
+     * @return {@code this} to enable chaining
+     * @see String#format(String, Object...)
+     */
+    public StrBuilder append(final String format, final Object... objs) {
+        return append(String.format(format, objs));
+    }
+
+    /**
+     * Appends the contents of a char buffer to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param buf  the char buffer to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final CharBuffer buf) {
+        if (buf == null) {
+            return appendNull();
+        }
+        if (buf.hasArray()) {
+            final int length = buf.remaining();
+            final int len = length();
+            ensureCapacity(len + length);
+            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length);
+            size += length;
+        } else {
+            append(buf.toString());
+        }
+        return this;
+    }
+
+    /**
+     * Appends the contents of a char buffer to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param buf  the char buffer to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) {
+        if (buf == null) {
+            return appendNull();
+        }
+        if (buf.hasArray()) {
+            final int totalLength = buf.remaining();
+            if (startIndex < 0 || startIndex > totalLength) {
+                throw new StringIndexOutOfBoundsException("startIndex must be valid");
+            }
+            if (length < 0 || (startIndex + length) > totalLength) {
+                throw new StringIndexOutOfBoundsException("length must be valid");
+            }
+            final int len = length();
+            ensureCapacity(len + length);
+            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length);
+            size += length;
+        } else {
+            append(buf.toString(), startIndex, length);
+        }
+        return this;
+    }
+
+    /**
+     * Appends a string buffer to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string buffer to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final StringBuffer str) {
+        if (str == null) {
+            return appendNull();
+        }
+        final int strLen = str.length();
+        if (strLen > 0) {
+            final int len = length();
+            ensureCapacity(len + strLen);
+            str.getChars(0, strLen, buffer, len);
+            size += strLen;
+        }
+        return this;
+    }
+
+    /**
+     * Appends part of a string buffer to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
+        if (str == null) {
+            return appendNull();
+        }
+        if (startIndex < 0 || startIndex > str.length()) {
+            throw new StringIndexOutOfBoundsException("startIndex must be valid");
+        }
+        if (length < 0 || (startIndex + length) > str.length()) {
+            throw new StringIndexOutOfBoundsException("length must be valid");
+        }
+        if (length > 0) {
+            final int len = length();
+            ensureCapacity(len + length);
+            str.getChars(startIndex, startIndex + length, buffer, len);
+            size += length;
+        }
+        return this;
+    }
+
+    /**
+     * Appends a StringBuilder to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str the StringBuilder to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final StringBuilder str) {
+        if (str == null) {
+            return appendNull();
+        }
+        final int strLen = str.length();
+        if (strLen > 0) {
+            final int len = length();
+            ensureCapacity(len + strLen);
+            str.getChars(0, strLen, buffer, len);
+            size += strLen;
+        }
+        return this;
+    }
+
+    /**
+     * Appends part of a StringBuilder to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str the StringBuilder to append
+     * @param startIndex the start index, inclusive, must be valid
+     * @param length the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
+        if (str == null) {
+            return appendNull();
+        }
+        if (startIndex < 0 || startIndex > str.length()) {
+            throw new StringIndexOutOfBoundsException("startIndex must be valid");
+        }
+        if (length < 0 || (startIndex + length) > str.length()) {
+            throw new StringIndexOutOfBoundsException("length must be valid");
+        }
+        if (length > 0) {
+            final int len = length();
+            ensureCapacity(len + length);
+            str.getChars(startIndex, startIndex + length, buffer, len);
+            size += length;
+        }
+        return this;
+    }
+
+    /**
+     * Appends another string builder to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string builder to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final StrBuilder str) {
+        if (str == null) {
+            return appendNull();
+        }
+        final int strLen = str.length();
+        if (strLen > 0) {
+            final int len = length();
+            ensureCapacity(len + strLen);
+            System.arraycopy(str.buffer, 0, buffer, len, strLen);
+            size += strLen;
+        }
+        return this;
+    }
+
+    /**
+     * Appends part of a string builder to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
+        if (str == null) {
+            return appendNull();
+        }
+        if (startIndex < 0 || startIndex > str.length()) {
+            throw new StringIndexOutOfBoundsException("startIndex must be valid");
+        }
+        if (length < 0 || (startIndex + length) > str.length()) {
+            throw new StringIndexOutOfBoundsException("length must be valid");
+        }
+        if (length > 0) {
+            final int len = length();
+            ensureCapacity(len + length);
+            str.getChars(startIndex, startIndex + length, buffer, len);
+            size += length;
+        }
+        return this;
+    }
+
+    /**
+     * Appends a char array to the string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param chars  the char array to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final char[] chars) {
+        if (chars == null) {
+            return appendNull();
+        }
+        final int strLen = chars.length;
+        if (strLen > 0) {
+            final int len = length();
+            ensureCapacity(len + strLen);
+            System.arraycopy(chars, 0, buffer, len, strLen);
+            size += strLen;
+        }
+        return this;
+    }
+
+    /**
+     * Appends a char array to the string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param chars  the char array to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final char[] chars, final int startIndex, final int length) {
+        if (chars == null) {
+            return appendNull();
+        }
+        if (startIndex < 0 || startIndex > chars.length) {
+            throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
+        }
+        if (length < 0 || (startIndex + length) > chars.length) {
+            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
+        }
+        if (length > 0) {
+            final int len = length();
+            ensureCapacity(len + length);
+            System.arraycopy(chars, startIndex, buffer, len, length);
+            size += length;
+        }
+        return this;
+    }
+
+    /**
+     * Appends a boolean value to the string builder.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final boolean value) {
+        if (value) {
+            ensureCapacity(size + 4);
+            buffer[size++] = 't';
+            buffer[size++] = 'r';
+            buffer[size++] = 'u';
+            buffer[size++] = 'e';
+        } else {
+            ensureCapacity(size + 5);
+            buffer[size++] = 'f';
+            buffer[size++] = 'a';
+            buffer[size++] = 'l';
+            buffer[size++] = 's';
+            buffer[size++] = 'e';
+        }
+        return this;
+    }
+
+    /**
+     * Appends a char value to the string builder.
+     *
+     * @param ch  the value to append
+     * @return this, to enable chaining
+     */
+    @Override
+    public StrBuilder append(final char ch) {
+        final int len = length();
+        ensureCapacity(len + 1);
+        buffer[size++] = ch;
+        return this;
+    }
+
+    /**
+     * Appends an int value to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final int value) {
+        return append(String.valueOf(value));
+    }
+
+    /**
+     * Appends a long value to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final long value) {
+        return append(String.valueOf(value));
+    }
+
+    /**
+     * Appends a float value to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final float value) {
+        return append(String.valueOf(value));
+    }
+
+    /**
+     * Appends a double value to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder append(final double value) {
+        return append(String.valueOf(value));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends an object followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param obj  the object to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final Object obj) {
+        return append(obj).appendNewLine();
+    }
+
+    /**
+     * Appends a string followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final String str) {
+        return append(str).appendNewLine();
+    }
+
+    /**
+     * Appends part of a string followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final String str, final int startIndex, final int length) {
+        return append(str, startIndex, length).appendNewLine();
+    }
+
+    /**
+     * Calls {@link String#format(String, Object...)} and appends the result.
+     *
+     * @param format the format string
+     * @param objs the objects to use in the format string
+     * @return {@code this} to enable chaining
+     * @see String#format(String, Object...)
+     */
+    public StrBuilder appendln(final String format, final Object... objs) {
+        return append(format, objs).appendNewLine();
+    }
+
+    /**
+     * Appends a string buffer followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string buffer to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final StringBuffer str) {
+        return append(str).appendNewLine();
+    }
+
+    /**
+     * Appends a string builder followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string builder to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final StringBuilder str) {
+        return append(str).appendNewLine();
+    }
+
+    /**
+     * Appends part of a string builder followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string builder to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
+        return append(str, startIndex, length).appendNewLine();
+    }
+
+    /**
+     * Appends part of a string buffer followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
+        return append(str, startIndex, length).appendNewLine();
+    }
+
+    /**
+     * Appends another string builder followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string builder to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final StrBuilder str) {
+        return append(str).appendNewLine();
+    }
+
+    /**
+     * Appends part of a string builder followed by a new line to this string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param str  the string to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) {
+        return append(str, startIndex, length).appendNewLine();
+    }
+
+    /**
+     * Appends a char array followed by a new line to the string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param chars  the char array to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final char[] chars) {
+        return append(chars).appendNewLine();
+    }
+
+    /**
+     * Appends a char array followed by a new line to the string builder.
+     * Appending null will call {@link #appendNull()}.
+     *
+     * @param chars  the char array to append
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param length  the length to append, must be valid
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final char[] chars, final int startIndex, final int length) {
+        return append(chars, startIndex, length).appendNewLine();
+    }
+
+    /**
+     * Appends a boolean value followed by a new line to the string builder.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final boolean value) {
+        return append(value).appendNewLine();
+    }
+
+    /**
+     * Appends a char value followed by a new line to the string builder.
+     *
+     * @param ch  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final char ch) {
+        return append(ch).appendNewLine();
+    }
+
+    /**
+     * Appends an int value followed by a new line to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final int value) {
+        return append(value).appendNewLine();
+    }
+
+    /**
+     * Appends a long value followed by a new line to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final long value) {
+        return append(value).appendNewLine();
+    }
+
+    /**
+     * Appends a float value followed by a new line to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final float value) {
+        return append(value).appendNewLine();
+    }
+
+    /**
+     * Appends a double value followed by a new line to the string builder using <code>String.valueOf</code>.
+     *
+     * @param value  the value to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendln(final double value) {
+        return append(value).appendNewLine();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends each item in an array to the builder without any separators.
+     * Appending a null array will have no effect.
+     * Each object is appended using {@link #append(Object)}.
+     *
+     * @param <T>  the element type
+     * @param array  the array to append
+     * @return this, to enable chaining
+     */
+    public <T> StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
+        /*
+         * @SuppressWarnings used to hide warning about vararg usage. We cannot
+         * use @SafeVarargs, since this method is not final. Using @SupressWarnings
+         * is fine, because it isn't inherited by subclasses, so each subclass must
+         * vouch for itself whether its use of 'array' is safe.
+         */
+        if (array != null && array.length > 0) {
+            for (final Object element : array) {
+                append(element);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Appends each item in an iterable to the builder without any separators.
+     * Appending a null iterable will have no effect.
+     * Each object is appended using {@link #append(Object)}.
+     *
+     * @param iterable  the iterable to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendAll(final Iterable<?> iterable) {
+        if (iterable != null) {
+            for (final Object o : iterable) {
+                append(o);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Appends each item in an iterator to the builder without any separators.
+     * Appending a null iterator will have no effect.
+     * Each object is appended using {@link #append(Object)}.
+     *
+     * @param it  the iterator to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendAll(final Iterator<?> it) {
+        if (it != null) {
+            while (it.hasNext()) {
+                append(it.next());
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends an array placing separators between each value, but
+     * not before the first or after the last.
+     * Appending a null array will have no effect.
+     * Each object is appended using {@link #append(Object)}.
+     *
+     * @param array  the array to append
+     * @param separator  the separator to use, null means no separator
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
+        if (array != null && array.length > 0) {
+            final String sep = Objects.toString(separator, "");
+            append(array[0]);
+            for (int i = 1; i < array.length; i++) {
+                append(sep);
+                append(array[i]);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Appends an iterable placing separators between each value, but
+     * not before the first or after the last.
+     * Appending a null iterable will have no effect.
+     * Each object is appended using {@link #append(Object)}.
+     *
+     * @param iterable  the iterable to append
+     * @param separator  the separator to use, null means no separator
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
+        if (iterable != null) {
+            final String sep = Objects.toString(separator, "");
+            final Iterator<?> it = iterable.iterator();
+            while (it.hasNext()) {
+                append(it.next());
+                if (it.hasNext()) {
+                    append(sep);
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Appends an iterator placing separators between each value, but
+     * not before the first or after the last.
+     * Appending a null iterator will have no effect.
+     * Each object is appended using {@link #append(Object)}.
+     *
+     * @param it  the iterator to append
+     * @param separator  the separator to use, null means no separator
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendWithSeparators(final Iterator<?> it, final String separator) {
+        if (it != null) {
+            final String sep = Objects.toString(separator, "");
+            while (it.hasNext()) {
+                append(it.next());
+                if (it.hasNext()) {
+                    append(sep);
+                }
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a separator if the builder is currently non-empty.
+     * Appending a null separator will have no effect.
+     * The separator is appended using {@link #append(String)}.
+     * <p>
+     * This method is useful for adding a separator each time around the
+     * loop except the first.
+     * <pre>
+     * for (Iterator it = list.iterator(); it.hasNext(); ) {
+     *   appendSeparator(",");
+     *   append(it.next());
+     * }
+     * </pre>
+     * Note that for this simple example, you should use
+     * {@link #appendWithSeparators(Iterable, String)}.
+     *
+     * @param separator  the separator to use, null means no separator
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendSeparator(final String separator) {
+        return appendSeparator(separator, null);
+    }
+
+    /**
+     * Appends one of both separators to the StrBuilder.
+     * If the builder is currently empty it will append the defaultIfEmpty-separator
+     * Otherwise it will append the standard-separator
+     *
+     * Appending a null separator will have no effect.
+     * The separator is appended using {@link #append(String)}.
+     * <p>
+     * This method is for example useful for constructing queries
+     * <pre>
+     * StrBuilder whereClause = new StrBuilder();
+     * if(searchCommand.getPriority() != null) {
+     *  whereClause.appendSeparator(" and", " where");
+     *  whereClause.append(" priority = ?")
+     * }
+     * if(searchCommand.getComponent() != null) {
+     *  whereClause.appendSeparator(" and", " where");
+     *  whereClause.append(" component = ?")
+     * }
+     * selectClause.append(whereClause)
+     * </pre>
+     *
+     * @param standard the separator if builder is not empty, null means no separator
+     * @param defaultIfEmpty the separator if builder is empty, null means no separator
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
+        final String str = isEmpty() ? defaultIfEmpty : standard;
+        if (str != null) {
+            append(str);
+        }
+        return this;
+    }
+
+    /**
+     * Appends a separator if the builder is currently non-empty.
+     * The separator is appended using {@link #append(char)}.
+     * <p>
+     * This method is useful for adding a separator each time around the
+     * loop except the first.
+     * <pre>
+     * for (Iterator it = list.iterator(); it.hasNext(); ) {
+     *   appendSeparator(',');
+     *   append(it.next());
+     * }
+     * </pre>
+     * Note that for this simple example, you should use
+     * {@link #appendWithSeparators(Iterable, String)}.
+     *
+     * @param separator  the separator to use
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendSeparator(final char separator) {
+        if (size() > 0) {
+            append(separator);
+        }
+        return this;
+    }
+
+    /**
+     * Append one of both separators to the builder
+     * If the builder is currently empty it will append the defaultIfEmpty-separator
+     * Otherwise it will append the standard-separator
+     *
+     * The separator is appended using {@link #append(char)}.
+     * @param standard the separator if builder is not empty
+     * @param defaultIfEmpty the separator if builder is empty
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
+        if (size() > 0) {
+            append(standard);
+        } else {
+            append(defaultIfEmpty);
+        }
+        return this;
+    }
+    /**
+     * Appends a separator to the builder if the loop index is greater than zero.
+     * Appending a null separator will have no effect.
+     * The separator is appended using {@link #append(String)}.
+     * <p>
+     * This method is useful for adding a separator each time around the
+     * loop except the first.
+     * </p>
+     * <pre>
+     * for (int i = 0; i &lt; list.size(); i++) {
+     *   appendSeparator(",", i);
+     *   append(list.get(i));
+     * }
+     * </pre>
+     * Note that for this simple example, you should use
+     * {@link #appendWithSeparators(Iterable, String)}.
+     *
+     * @param separator  the separator to use, null means no separator
+     * @param loopIndex  the loop index
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendSeparator(final String separator, final int loopIndex) {
+        if (separator != null && loopIndex > 0) {
+            append(separator);
+        }
+        return this;
+    }
+
+    /**
+     * Appends a separator to the builder if the loop index is greater than zero.
+     * The separator is appended using {@link #append(char)}.
+     * <p>
+     * This method is useful for adding a separator each time around the
+     * loop except the first.
+     * </p>
+     * <pre>
+     * for (int i = 0; i &lt; list.size(); i++) {
+     *   appendSeparator(",", i);
+     *   append(list.get(i));
+     * }
+     * </pre>
+     * Note that for this simple example, you should use
+     * {@link #appendWithSeparators(Iterable, String)}.
+     *
+     * @param separator  the separator to use
+     * @param loopIndex  the loop index
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendSeparator(final char separator, final int loopIndex) {
+        if (loopIndex > 0) {
+            append(separator);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the pad character to the builder the specified number of times.
+     *
+     * @param length  the length to append, negative means no append
+     * @param padChar  the character to append
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendPadding(final int length, final char padChar) {
+        if (length >= 0) {
+            ensureCapacity(size + length);
+            for (int i = 0; i < length; i++) {
+                buffer[size++] = padChar;
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends an object to the builder padding on the left to a fixed width.
+     * The <code>toString</code> of the object is used.
+     * If the object is larger than the length, the left hand side is lost.
+     * If the object is null, the null text value is used.
+     *
+     * @param obj  the object to append, null uses null text
+     * @param width  the fixed field width, zero or negative has no effect
+     * @param padChar  the pad character to use
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
+        if (width > 0) {
+            ensureCapacity(size + width);
+            String str = (obj == null ? getNullText() : obj.toString());
+            if (str == null) {
+                str = "";
+            }
+            final int strLen = str.length();
+            if (strLen >= width) {
+                str.getChars(strLen - width, strLen, buffer, size);
+            } else {
+                final int padLen = width - strLen;
+                for (int i = 0; i < padLen; i++) {
+                    buffer[size + i] = padChar;
+                }
+                str.getChars(0, strLen, buffer, size + padLen);
+            }
+            size += width;
+        }
+        return this;
+    }
+
+    /**
+     * Appends an object to the builder padding on the left to a fixed width.
+     * The <code>String.valueOf</code> of the <code>int</code> value is used.
+     * If the formatted value is larger than the length, the left hand side is lost.
+     *
+     * @param value  the value to append
+     * @param width  the fixed field width, zero or negative has no effect
+     * @param padChar  the pad character to use
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
+        return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
+    }
+
+    /**
+     * Appends an object to the builder padding on the right to a fixed length.
+     * The <code>toString</code> of the object is used.
+     * If the object is larger than the length, the right hand side is lost.
+     * If the object is null, null text value is used.
+     *
+     * @param obj  the object to append, null uses null text
+     * @param width  the fixed field width, zero or negative has no effect
+     * @param padChar  the pad character to use
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
+        if (width > 0) {
+            ensureCapacity(size + width);
+            String str = (obj == null ? getNullText() : obj.toString());
+            if (str == null) {
+                str = "";
+            }
+            final int strLen = str.length();
+            if (strLen >= width) {
+                str.getChars(0, width, buffer, size);
+            } else {
+                final int padLen = width - strLen;
+                str.getChars(0, strLen, buffer, size);
+                for (int i = 0; i < padLen; i++) {
+                    buffer[size + strLen + i] = padChar;
+                }
+            }
+            size += width;
+        }
+        return this;
+    }
+
+    /**
+     * Appends an object to the builder padding on the right to a fixed length.
+     * The <code>String.valueOf</code> of the <code>int</code> value is used.
+     * If the object is larger than the length, the right hand side is lost.
+     *
+     * @param value  the value to append
+     * @param width  the fixed field width, zero or negative has no effect
+     * @param padChar  the pad character to use
+     * @return this, to enable chaining
+     */
+    public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
+        return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Inserts the string representation of an object into this builder.
+     * Inserting null will use the stored null text value.
+     *
+     * @param index  the index to add at, must be valid
+     * @param obj  the object to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final Object obj) {
+        if (obj == null) {
+            return insert(index, nullText);
+        }
+        return insert(index, obj.toString());
+    }
+
+    /**
+     * Inserts the string into this builder.
+     * Inserting null will use the stored null text value.
+     *
+     * @param index  the index to add at, must be valid
+     * @param str  the string to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, String str) {
+        validateIndex(index);
+        if (str == null) {
+            str = nullText;
+        }
+        if (str != null) {
+            final int strLen = str.length();
+            if (strLen > 0) {
+                final int newSize = size + strLen;
+                ensureCapacity(newSize);
+                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
+                size = newSize;
+                str.getChars(0, strLen, buffer, index);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Inserts the character array into this builder.
+     * Inserting null will use the stored null text value.
+     *
+     * @param index  the index to add at, must be valid
+     * @param chars  the char array to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final char[] chars) {
+        validateIndex(index);
+        if (chars == null) {
+            return insert(index, nullText);
+        }
+        final int len = chars.length;
+        if (len > 0) {
+            ensureCapacity(size + len);
+            System.arraycopy(buffer, index, buffer, index + len, size - index);
+            System.arraycopy(chars, 0, buffer, index, len);
+            size += len;
+        }
+        return this;
+    }
+
+    /**
+     * Inserts part of the character array into this builder.
+     * Inserting null will use the stored null text value.
+     *
+     * @param index  the index to add at, must be valid
+     * @param chars  the char array to insert
+     * @param offset  the offset into the character array to start at, must be valid
+     * @param length  the length of the character array part to copy, must be positive
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if any index is invalid
+     */
+    public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
+        validateIndex(index);
+        if (chars == null) {
+            return insert(index, nullText);
+        }
+        if (offset < 0 || offset > chars.length) {
+            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
+        }
+        if (length < 0 || offset + length > chars.length) {
+            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
+        }
+        if (length > 0) {
+            ensureCapacity(size + length);
+            System.arraycopy(buffer, index, buffer, index + length, size - index);
+            System.arraycopy(chars, offset, buffer, index, length);
+            size += length;
+        }
+        return this;
+    }
+
+    /**
+     * Inserts the value into this builder.
+     *
+     * @param index  the index to add at, must be valid
+     * @param value  the value to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(int index, final boolean value) {
+        validateIndex(index);
+        if (value) {
+            ensureCapacity(size + 4);
+            System.arraycopy(buffer, index, buffer, index + 4, size - index);
+            buffer[index++] = 't';
+            buffer[index++] = 'r';
+            buffer[index++] = 'u';
+            buffer[index] = 'e';
+            size += 4;
+        } else {
+            ensureCapacity(size + 5);
+            System.arraycopy(buffer, index, buffer, index + 5, size - index);
+            buffer[index++] = 'f';
+            buffer[index++] = 'a';
+            buffer[index++] = 'l';
+            buffer[index++] = 's';
+            buffer[index] = 'e';
+            size += 5;
+        }
+        return this;
+    }
+
+    /**
+     * Inserts the value into this builder.
+     *
+     * @param index  the index to add at, must be valid
+     * @param value  the value to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final char value) {
+        validateIndex(index);
+        ensureCapacity(size + 1);
+        System.arraycopy(buffer, index, buffer, index + 1, size - index);
+        buffer[index] = value;
+        size++;
+        return this;
+    }
+
+    /**
+     * Inserts the value into this builder.
+     *
+     * @param index  the index to add at, must be valid
+     * @param value  the value to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final int value) {
+        return insert(index, String.valueOf(value));
+    }
+
+    /**
+     * Inserts the value into this builder.
+     *
+     * @param index  the index to add at, must be valid
+     * @param value  the value to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final long value) {
+        return insert(index, String.valueOf(value));
+    }
+
+    /**
+     * Inserts the value into this builder.
+     *
+     * @param index  the index to add at, must be valid
+     * @param value  the value to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final float value) {
+        return insert(index, String.valueOf(value));
+    }
+
+    /**
+     * Inserts the value into this builder.
+     *
+     * @param index  the index to add at, must be valid
+     * @param value  the value to insert
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder insert(final int index, final double value) {
+        return insert(index, String.valueOf(value));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Internal method to delete a range without validation.
+     *
+     * @param startIndex  the start index, must be valid
+     * @param endIndex  the end index (exclusive), must be valid
+     * @param len  the length, must be valid
+     * @throws IndexOutOfBoundsException if any index is invalid
+     */
+    private void deleteImpl(final int startIndex, final int endIndex, final int len) {
+        System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
+        size -= len;
+    }
+
+    /**
+     * Deletes the characters between the two specified indices.
+     *
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param endIndex  the end index, exclusive, must be valid except
+     *  that if too large it is treated as end of string
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder delete(final int startIndex, int endIndex) {
+        endIndex = validateRange(startIndex, endIndex);
+        final int len = endIndex - startIndex;
+        if (len > 0) {
+            deleteImpl(startIndex, endIndex, len);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Deletes the character wherever it occurs in the builder.
+     *
+     * @param ch  the character to delete
+     * @return this, to enable chaining
+     */
+    public StrBuilder deleteAll(final char ch) {
+        for (int i = 0; i < size; i++) {
+            if (buffer[i] == ch) {
+                final int start = i;
+                while (++i < size) {
+                    if (buffer[i] != ch) {
+                        break;
+                    }
+                }
+                final int len = i - start;
+                deleteImpl(start, i, len);
+                i -= len;
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Deletes the character wherever it occurs in the builder.
+     *
+     * @param ch  the character to delete
+     * @return this, to enable chaining
+     */
+    public StrBuilder deleteFirst(final char ch) {
+        for (int i = 0; i < size; i++) {
+            if (buffer[i] == ch) {
+                deleteImpl(i, i + 1, 1);
+                break;
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Deletes the string wherever it occurs in the builder.
+     *
+     * @param str  the string to delete, null causes no action
+     * @return this, to enable chaining
+     */
+    public StrBuilder deleteAll(final String str) {
+        final int len = (str == null ? 0 : str.length());
+        if (len > 0) {
+            int index = indexOf(str, 0);
+            while (index >= 0) {
+                deleteImpl(index, index + len, len);
+                index = indexOf(str, index);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Deletes the string wherever it occurs in the builder.
+     *
+     * @param str  the string to delete, null causes no action
+     * @return this, to enable chaining
+     */
+    public StrBuilder deleteFirst(final String str) {
+        final int len = (str == null ? 0 : str.length());
+        if (len > 0) {
+            final int index = indexOf(str, 0);
+            if (index >= 0) {
+                deleteImpl(index, index + len, len);
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Deletes all parts of the builder that the matcher matches.
+     * <p>
+     * Matchers can be used to perform advanced deletion behaviour.
+     * For example you could write a matcher to delete all occurrences
+     * where the character 'a' is followed by a number.
+     *
+     * @param matcher  the matcher to use to find the deletion, null causes no action
+     * @return this, to enable chaining
+     */
+    public StrBuilder deleteAll(final StrMatcher matcher) {
+        return replace(matcher, null, 0, size, -1);
+    }
+
+    /**
+     * Deletes the first match within the builder using the specified matcher.
+     * <p>
+     * Matchers can be used to perform advanced deletion behaviour.
+     * For example you could write a matcher to delete
+     * where the character 'a' is followed by a number.
+     *
+     * @param matcher  the matcher to use to find the deletion, null causes no action
+     * @return this, to enable chaining
+     */
+    public StrBuilder deleteFirst(final StrMatcher matcher) {
+        return replace(matcher, null, 0, size, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Internal method to delete a range without validation.
+     *
+     * @param startIndex  the start index, must be valid
+     * @param endIndex  the end index (exclusive), must be valid
+     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
+     * @param insertStr  the string to replace with, null means delete range
+     * @param insertLen  the length of the insert string, must be valid
+     * @throws IndexOutOfBoundsException if any index is invalid
+     */
+    private void replaceImpl(final int startIndex,
+                             final int endIndex,
+                             final int removeLen,
+                             final String insertStr,
+                             final int insertLen) {
+        final int newSize = size - removeLen + insertLen;
+        if (insertLen != removeLen) {
+            ensureCapacity(newSize);
+            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
+            size = newSize;
+        }
+        if (insertLen > 0) {
+            insertStr.getChars(0, insertLen, buffer, startIndex);
+        }
+    }
+
+    /**
+     * Replaces a portion of the string builder with another string.
+     * The length of the inserted string does not have to match the removed length.
+     *
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param endIndex  the end index, exclusive, must be valid except
+     *  that if too large it is treated as end of string
+     * @param replaceStr  the string to replace with, null means delete range
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
+        endIndex = validateRange(startIndex, endIndex);
+        final int insertLen = (replaceStr == null ? 0 : replaceStr.length());
+        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces the search character with the replace character
+     * throughout the builder.
+     *
+     * @param search  the search character
+     * @param replace  the replace character
+     * @return this, to enable chaining
+     */
+    public StrBuilder replaceAll(final char search, final char replace) {
+        if (search != replace) {
+            for (int i = 0; i < size; i++) {
+                if (buffer[i] == search) {
+                    buffer[i] = replace;
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Replaces the first instance of the search character with the
+     * replace character in the builder.
+     *
+     * @param search  the search character
+     * @param replace  the replace character
+     * @return this, to enable chaining
+     */
+    public StrBuilder replaceFirst(final char search, final char replace) {
+        if (search != replace) {
+            for (int i = 0; i < size; i++) {
+                if (buffer[i] == search) {
+                    buffer[i] = replace;
+                    break;
+                }
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces the search string with the replace string throughout the builder.
+     *
+     * @param searchStr  the search string, null causes no action to occur
+     * @param replaceStr  the replace string, null is equivalent to an empty string
+     * @return this, to enable chaining
+     */
+    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
+        final int searchLen = (searchStr == null ? 0 : searchStr.length());
+        if (searchLen > 0) {
+            final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
+            int index = indexOf(searchStr, 0);
+            while (index >= 0) {
+                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
+                index = indexOf(searchStr, index + replaceLen);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Replaces the first instance of the search string with the replace string.
+     *
+     * @param searchStr  the search string, null causes no action to occur
+     * @param replaceStr  the replace string, null is equivalent to an empty string
+     * @return this, to enable chaining
+     */
+    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
+        final int searchLen = (searchStr == null ? 0 : searchStr.length());
+        if (searchLen > 0) {
+            final int index = indexOf(searchStr, 0);
+            if (index >= 0) {
+                final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
+                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all matches within the builder with the replace string.
+     * <p>
+     * Matchers can be used to perform advanced replace behaviour.
+     * For example you could write a matcher to replace all occurrences
+     * where the character 'a' is followed by a number.
+     *
+     * @param matcher  the matcher to use to find the deletion, null causes no action
+     * @param replaceStr  the replace string, null is equivalent to an empty string
+     * @return this, to enable chaining
+     */
+    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
+        return replace(matcher, replaceStr, 0, size, -1);
+    }
+
+    /**
+     * Replaces the first match within the builder with the replace string.
+     * <p>
+     * Matchers can be used to perform advanced replace behaviour.
+     * For example you could write a matcher to replace
+     * where the character 'a' is followed by a number.
+     *
+     * @param matcher  the matcher to use to find the deletion, null causes no action
+     * @param replaceStr  the replace string, null is equivalent to an empty string
+     * @return this, to enable chaining
+     */
+    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
+        return replace(matcher, replaceStr, 0, size, 1);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Advanced search and replaces within the builder using a matcher.
+     * <p>
+     * Matchers can be used to perform advanced behaviour.
+     * For example you could write a matcher to delete all occurrences
+     * where the character 'a' is followed by a number.
+     *
+     * @param matcher  the matcher to use to find the deletion, null causes no action
+     * @param replaceStr  the string to replace the match with, null is a delete
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param endIndex  the end index, exclusive, must be valid except
+     *  that if too large it is treated as end of string
+     * @param replaceCount  the number of times to replace, -1 for replace all
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if start index is invalid
+     */
+    public StrBuilder replace(
+            final StrMatcher matcher, final String replaceStr,
+            final int startIndex, int endIndex, final int replaceCount) {
+        endIndex = validateRange(startIndex, endIndex);
+        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
+    }
+
+    /**
+     * Replaces within the builder using a matcher.
+     * <p>
+     * Matchers can be used to perform advanced behaviour.
+     * For example you could write a matcher to delete all occurrences
+     * where the character 'a' is followed by a number.
+     *
+     * @param matcher  the matcher to use to find the deletion, null causes no action
+     * @param replaceStr  the string to replace the match with, null is a delete
+     * @param from  the start index, must be valid
+     * @param to  the end index (exclusive), must be valid
+     * @param replaceCount  the number of times to replace, -1 for replace all
+     * @return this, to enable chaining
+     * @throws IndexOutOfBoundsException if any index is invalid
+     */
+    private StrBuilder replaceImpl(
+            final StrMatcher matcher, final String replaceStr,
+            final int from, int to, int replaceCount) {
+        if (matcher == null || size == 0) {
+            return this;
+        }
+        final int replaceLen = (replaceStr == null ? 0 : replaceStr.length());
+        for (int i = from; i < to && replaceCount != 0; i++) {
+            final char[] buf = buffer;
+            final int removeLen = matcher.isMatch(buf, i, from, to);
+            if (removeLen > 0) {
+                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
+                to = to - removeLen + replaceLen;
+                i = i + replaceLen - 1;
+                if (replaceCount > 0) {
+                    replaceCount--;
+                }
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Reverses the string builder placing each character in the opposite index.
+     *
+     * @return this, to enable chaining
+     */
+    public StrBuilder reverse() {
+        if (size == 0) {
+            return this;
+        }
+
+        final int half = size / 2;
+        final char[] buf = buffer;
+        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
+            final char swap = buf[leftIdx];
+            buf[leftIdx] = buf[rightIdx];
+            buf[rightIdx] = swap;
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Trims the builder by removing characters less than or equal to a space
+     * from the beginning and end.
+     *
+     * @return this, to enable chaining
+     */
+    public StrBuilder trim() {
+        if (size == 0) {
+            return this;
+        }
+        int len = size;
+        final char[] buf = buffer;
+        int pos = 0;
+        while (pos < len && buf[pos] <= ' ') {
+            pos++;
+        }
+        while (pos < len && buf[len - 1] <= ' ') {
+            len--;
+        }
+        if (len < size) {
+            delete(len, size);
+        }
+        if (pos > 0) {
+            delete(0, pos);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks whether this builder starts with the specified string.
+     * <p>
+     * Note that this method handles null input quietly, unlike String.
+     *
+     * @param str  the string to search for, null returns false
+     * @return true if the builder starts with the string
+     */
+    public boolean startsWith(final String str) {
+        if (str == null) {
+            return false;
+        }
+        final int len = str.length();
+        if (len == 0) {
+            return true;
+        }
+        if (len > size) {
+            return false;
+        }
+        for (int i = 0; i < len; i++) {
+            if (buffer[i] != str.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks whether this builder ends with the specified string.
+     * <p>
+     * Note that this method handles null input quietly, unlike String.
+     *
+     * @param str  the string to search for, null returns false
+     * @return true if the builder ends with the string
+     */
+    public boolean endsWith(final String str) {
+        if (str == null) {
+            return false;
+        }
+        final int len = str.length();
+        if (len == 0) {
+            return true;
+        }
+        if (len > size) {
+            return false;
+        }
+        int pos = size - len;
+        for (int i = 0; i < len; i++, pos++) {
+            if (buffer[pos] != str.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public CharSequence subSequence(final int startIndex, final int endIndex) {
+      if (startIndex < 0) {
+          throw new StringIndexOutOfBoundsException(startIndex);
+      }
+      if (endIndex > size) {
+          throw new StringIndexOutOfBoundsException(endIndex);
+      }
+      if (startIndex > endIndex) {
+          throw new StringIndexOutOfBoundsException(endIndex - startIndex);
+      }
+      return substring(startIndex, endIndex);
+    }
+
+    /**
+     * Extracts a portion of this string builder as a string.
+     *
+     * @param start  the start index, inclusive, must be valid
+     * @return the new string
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public String substring(final int start) {
+        return substring(start, size);
+    }
+
+    /**
+     * Extracts a portion of this string builder as a string.
+     * <p>
+     * Note: This method treats an endIndex greater than the length of the
+     * builder as equal to the length of the builder, and continues
+     * without error, unlike StringBuffer or String.
+     *
+     * @param startIndex  the start index, inclusive, must be valid
+     * @param endIndex  the end index, exclusive, must be valid except
+     *  that if too large it is treated as end of string
+     * @return the new string
+     * @throws IndexOutOfBoundsException if the index is invalid
+     */
+    public String substring(final int startIndex, int endIndex) {
+        endIndex = validateRange(startIndex, endIndex);
+        return new String(buffer, startIndex, endIndex - startIndex);
+    }
+
+    /**
+     * Extracts the leftmost characters from the string builder without
+     * throwing an exception.
+     * <p>
+     * This method extracts the left <code>length</code> characters from
+     * the builder. If this many characters are not available, the whole
+     * builder is returned. Thus the returned string may be shorter than the
+     * length requested.
+     *
+     * @param length  the number of characters to extract, negative returns empty string
+     * @return the new string
+     */
+    public String leftString(final int length) {
+        if (length <= 0) {
+            return "";
+        } else if (length >= size) {
+            return new String(buffer, 0, size);
+        } else {
+            return new String(buffer, 0, length);
+        }
+    }
+
+    /**
+     * Extracts the rightmost characters from the string builder without
+     * throwing an exception.
+     * <p>
+     * This method extracts the right <code>length</code> characters from
+     * the builder. If this many characters are not available, the whole
+     * builder is returned. Thus the returned string may be shorter than the
+     * length requested.
+     *
+     * @param length  the number of characters to extract, negative returns empty string
+     * @return the new string
+     */
+    public String rightString(final int length) {
+        if (length <= 0) {
+            return "";
+        } else if (length >= size) {
+            return new String(buffer, 0, size);
+        } else {
+            return new String(buffer, size - length, length);
+        }
+    }
+
+    /**
+     * Extracts some characters from the middle of the string builder without
+     * throwing an exception.
+     * <p>
+     * This method extracts <code>length</code> characters from the builder
+     * at the specified index.
+     * If the index is negative it is treated as zero.
+     * If the index is greater than the builder size, it is treated as the builder size.
+     * If the length is negative, the empty string is returned.
+     * If insufficient characters are available in the builder, as much as possible is returned.
+     * Thus the returned string may be shorter than the length requested.
+     *
+     * @param index  the index to start at, negative means zero
+     * @param length  the number of characters to extract, negative returns empty string
+     * @return the new string
+     */
+    public String midString(int index, final int length) {
+        if (index < 0) {
+            index = 0;
+        }
+        if (length <= 0 || index >= size) {
+            return "";
+        }
+        if (size <= index + length) {
+            return new String(buffer, index, size - index);
+        }
+        return new String(buffer, index, length);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the string builder contains the specified char.
+     *
+     * @param ch  the character to find
+     * @return true if the builder contains the character
+     */
+    public boolean contains(final char ch) {
+        final char[] thisBuf = buffer;
+        for (int i = 0; i < this.size; i++) {
+            if (thisBuf[i] == ch) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Checks if the string builder contains the specified string.
+     *
+     * @param str  the string to find
+     * @return true if the builder contains the string
+     */
+    public boolean contains(final String str) {
+        return indexOf(str, 0) >= 0;
+    }
+
+    /**
+     * Checks if the string builder contains a string matched using the
+     * specified matcher.
+     * <p>
+     * Matchers can be used to perform advanced searching behaviour.
+     * For example you could write a matcher to search for the character
+     * 'a' followed by a number.
+     *
+     * @param matcher  the matcher to use, null returns -1
+     * @return true if the matcher finds a match in the builder
+     */
+    public boolean contains(final StrMatcher matcher) {
+        return indexOf(matcher, 0) >= 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Searches the string builder to find the first reference to the specified char.
+     *
+     * @param ch  the character to find
+     * @return the first index of the character, or -1 if not found
+     */
+    public int indexOf(final char ch) {
+        return indexOf(ch, 0);
+    }
+
+    /**
+     * Searches the string builder to find the first reference to the specified char.
+     *
+     * @param ch  the character to find
+     * @param startIndex  the index to start at, invalid index rounded to edge
+     * @return the first index of the character, or -1 if not found
+     */
+    public int indexOf(final char ch, int startIndex) {
+        startIndex = (startIndex < 0 ? 0 : startIndex);
+        if (startIndex >= size) {
+            return -1;
+        }
+        final char[] thisBuf = buffer;
+        for (int i = startIndex; i < size; i++) {
+            if (thisBuf[i] == ch) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Searches the string builder to find the first reference to the specified string.
+     * <p>
+     * Note that a null input string will return -1, whereas the JDK throws an exception.
+     *
+     * @param str  the string to find, null returns -1
+     * @return the first index of the string, or -1 if not found
+     */
+    public int indexOf(final String str) {
+        return indexOf(str, 0);
+    }
+
+    /**
+     * Searches the string builder to find the first reference to the specified
+     * string starting searching from the given index.
+     * <p>
+     * Note that a null input string will return -1, whereas the JDK throws an exception.
+     *
+     * @param str  the string to find, null returns -1
+     * @param startIndex  the index to start at, invalid index rounded to edge
+     * @return the first index of the string, or -1 if not found
+     */
+    public int indexOf(final String str, int startIndex) {
+        startIndex = (startIndex < 0 ? 0 : startIndex);
+        if (str == null || startIndex >= size) {
+            return -1;
+        }
+        final int strLen = str.length();
+        if (strLen == 1) {
+            return indexOf(str.charAt(0), startIndex);
+        }
+        if (strLen == 0) {
+            return startIndex;
+        }
+        if (strLen > size) {
+            return -1;
+        }
+        final char[] thisBuf = buffer;
+        final int len = size - strLen + 1;
+        outer:
+        for (int i = startIndex; i < len; i++) {
+            for (int j = 0; j < strLen; j++) {
+                if (str.charAt(j) != thisBuf[i + j]) {
+                    continue outer;
+                }
+            }
+            return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Searches the string builder using the matcher to find the first match.
+     * <p>
+     * Matchers can be used to perform advanced searching behaviour.
+     * For example you could write a matcher to find the character 'a'
+     * followed by a number.
+     *
+     * @param matcher  the matcher to use, null returns -1
+     * @return the first index matched, or -1 if not found
+     */
+    public int indexOf(final StrMatcher matcher) {
+        return indexOf(matcher, 0);
+    }
+
+    /**
+     * Searches the string builder using the matcher to find the first
+     * match searching from the given index.
+     * <p>
+     * Matchers can be used to perform advanced searching behaviour.
+     * For example you could write a matcher to find the character 'a'
+     * followed by a number.
+     *
+     * @param matcher  the matcher to use, null returns -1
+     * @param startIndex  the index to start at, invalid index rounded to edge
+     * @return the first index matched, or -1 if not found
+     */
+    public int indexOf(final StrMatcher matcher, int startIndex) {
+        startIndex = (startIndex < 0 ? 0 : startIndex);
+        if (matcher == null || startIndex >= size) {
+            return -1;
+        }
+        final int len = size;
+        final char[] buf = buffer;
+        for (int i = startIndex; i < len; i++) {
+            if (matcher.isMatch(buf, i, startIndex, len

<TRUNCATED>

[14/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
new file mode 100644
index 0000000..95a4adf
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
@@ -0,0 +1,1605 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import java.text.DecimalFormatSymbols;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+
+/**
+ * Unit tests for {@link StrBuilder}.
+ */
+public class StrBuilderAppendInsertTest {
+
+    /** The system line separator. */
+    private static final String SEP = System.lineSeparator();
+
+    /** Test subclass of Object, with a toString method. */
+    private static final Object FOO = new Object() {
+        @Override
+        public String toString() {
+            return "foo";
+        }
+    };
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendNewLine() {
+        StrBuilder sb = new StrBuilder("---");
+        sb.appendNewLine().append("+++");
+        assertEquals("---" + SEP + "+++", sb.toString());
+        
+        sb = new StrBuilder("---");
+        sb.setNewLineText("#").appendNewLine().setNewLineText(null).appendNewLine();
+        assertEquals("---#" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL");
+        assertEquals("", sb.toString());
+
+        sb.appendNull();
+        assertEquals("NULL", sb.toString());
+
+        sb.append((Object) null);
+        assertEquals("NULLNULL", sb.toString());
+
+        sb.append(FOO);
+        assertEquals("NULLNULLfoo", sb.toString());
+
+        sb.append((String) null);
+        assertEquals("NULLNULLfooNULL", sb.toString());
+
+        sb.append("");
+        assertEquals("NULLNULLfooNULL", sb.toString());
+
+        sb.append("bar");
+        assertEquals("NULLNULLfooNULLbar", sb.toString());
+
+        sb.append((StringBuffer) null);
+        assertEquals("NULLNULLfooNULLbarNULL", sb.toString());
+
+        sb.append(new StringBuffer("baz"));
+        assertEquals("NULLNULLfooNULLbarNULLbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_Object() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendNull();
+        assertEquals("", sb.toString());
+
+        sb.append((Object) null);
+        assertEquals("", sb.toString());
+
+        sb.append(FOO);
+        assertEquals("foo", sb.toString());
+
+        sb.append((StringBuffer) null);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer("baz"));
+        assertEquals("foobaz", sb.toString());
+
+        sb.append(new StrBuilder("yes"));
+        assertEquals("foobazyes", sb.toString());
+
+        sb.append((CharSequence) "Seq");
+        assertEquals("foobazyesSeq", sb.toString());
+
+        sb.append(new StringBuilder("bld")); // Check it supports StringBuilder
+        assertEquals("foobazyesSeqbld", sb.toString());
+    }
+    
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuilder() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuilder("foo"));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuilder(""));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuilder("bar"));
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_String() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+
+        sb.append("");
+        assertEquals("foo", sb.toString());
+
+        sb.append("bar");
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_String_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("foo", 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append("bar", -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append("bar", 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append("bar", 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append("abcbardef", 3, 3);
+        assertEquals("foobar", sb.toString());
+
+        sb.append( (CharSequence)"abcbardef", 4, 3);
+        assertEquals("foobarard", sb.toString());
+    }
+    
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuilder_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((String) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuilder("foo"), 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new StringBuilder("bar"), -1, 1);
+            fail("append(StringBuilder, -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 3, 1);
+            fail("append(StringBuilder, 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 1, -1);
+            fail("append(StringBuilder,, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 1, 3);
+            fail("append(StringBuilder, 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), -1, 3);
+            fail("append(StringBuilder, -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuilder("bar"), 4, 0);
+            fail("append(StringBuilder, 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new StringBuilder("bar"), 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuilder("abcbardef"), 3, 3);
+        assertEquals("foobar", sb.toString());
+
+        sb.append( new StringBuilder("abcbardef"), 4, 3);
+        assertEquals("foobarard", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuffer() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StringBuffer) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuffer("foo"));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer(""));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer("bar"));
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StringBuffer_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StringBuffer) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StringBuffer("foo"), 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new StringBuffer("bar"), -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StringBuffer("bar"), 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new StringBuffer("bar"), 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StringBuffer("abcbardef"), 3, 3);
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StrBuilder() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StrBuilder) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StrBuilder("foo"));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StrBuilder(""));
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StrBuilder("bar"));
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_StrBuilder_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((StrBuilder) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new StrBuilder("foo"), 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new StrBuilder("bar"), -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new StrBuilder("bar"), 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new StrBuilder("bar"), 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new StrBuilder("abcbardef"), 3, 3);
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_CharArray() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((char[]) null);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new char[0]);
+        assertEquals("", sb.toString());
+
+        sb.append(new char[]{'f', 'o', 'o'});
+        assertEquals("foo", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_CharArray_int_int() {
+        StrBuilder sb = new StrBuilder();
+        sb.setNullText("NULL").append((char[]) null, 0, 1);
+        assertEquals("NULL", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append(new char[]{'f', 'o', 'o'}, 0, 3);
+        assertEquals("foo", sb.toString());
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, -1, 1);
+            fail("append(char[], -1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 3, 1);
+            fail("append(char[], 3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 1, -1);
+            fail("append(char[],, -1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 1, 3);
+            fail("append(char[], 1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, -1, 3);
+            fail("append(char[], -1, 3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.append(new char[]{'b', 'a', 'r'}, 4, 0);
+            fail("append(char[], 4, 0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.append(new char[]{'b', 'a', 'r'}, 3, 0);
+        assertEquals("foo", sb.toString());
+
+        sb.append(new char[]{'a', 'b', 'c', 'b', 'a', 'r', 'd', 'e', 'f'}, 3, 3);
+        assertEquals("foobar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_Boolean() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append(true);
+        assertEquals("true", sb.toString());
+
+        sb.append(false);
+        assertEquals("truefalse", sb.toString());
+
+        sb.append('!');
+        assertEquals("truefalse!", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_PrimitiveNumber() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append(0);
+        assertEquals("0", sb.toString());
+
+        sb.append(1L);
+        assertEquals("01", sb.toString());
+
+        sb.append(2.3f);
+        assertEquals("012.3", sb.toString());
+
+        sb.append(4.5d);
+        assertEquals("012.34.5", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_FormattedString() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final String str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("Hello %s", "Alice");
+        assertEquals("Hello Alice" + SEP, sb.toString());
+        assertEquals(2, count[0]);  // appendNewLine() calls append(String)
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_Object() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln((Object) null);
+        assertEquals("" + SEP, sb.toString());
+
+        sb.appendln(FOO);
+        assertEquals(SEP + "foo" + SEP, sb.toString());
+
+        sb.appendln(Integer.valueOf(6));
+        assertEquals(SEP + "foo" + SEP + "6" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_String() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final String str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo");
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(2, count[0]);  // appendNewLine() calls append(String)
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_String_int_int() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final String str, final int startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo", 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StringBuffer() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final StringBuffer str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuffer("foo"));
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StringBuilder() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final StringBuilder str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuilder("foo"));
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StringBuffer_int_int() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuffer("foo"), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StringBuilder_int_int() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StringBuilder("foo"), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StrBuilder() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final StrBuilder str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StrBuilder("foo"));
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_StrBuilder_int_int() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln(new StrBuilder("foo"), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_CharArray() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final char[] str) {
+                count[0]++;
+                return super.append(str);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo".toCharArray());
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_CharArray_int_int() {
+        final int[] count = new int[2];
+        final StrBuilder sb = new StrBuilder() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public StrBuilder append(final char[] str, final int startIndex, final int length) {
+                count[0]++;
+                return super.append(str, startIndex, length);
+            }
+            @Override
+            public StrBuilder appendNewLine() {
+                count[1]++;
+                return super.appendNewLine();
+            }
+        };
+        sb.appendln("foo".toCharArray(), 0, 3);
+        assertEquals("foo" + SEP, sb.toString());
+        assertEquals(1, count[0]);
+        assertEquals(1, count[1]);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_Boolean() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln(true);
+        assertEquals("true" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(false);
+        assertEquals("false" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendln_PrimitiveNumber() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendln(0);
+        assertEquals("0" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(1L);
+        assertEquals("1" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(2.3f);
+        assertEquals("2.3" + SEP, sb.toString());
+        
+        sb.clear();
+        sb.appendln(4.5d);
+        assertEquals("4.5" + SEP, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendPadding() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+
+        sb.appendPadding(-1, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.appendPadding(0, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.appendPadding(1, '-');
+        assertEquals("foo-", sb.toString());
+
+        sb.appendPadding(16, '-');
+        assertEquals(20, sb.length());
+        //            12345678901234567890
+        assertEquals("foo-----------------", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadLeft() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadLeft("foo", -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 1, '-');
+        assertEquals("o", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 2, '-');
+        assertEquals("oo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 3, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 4, '-');
+        assertEquals("-foo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft("foo", 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("-------foo", sb.toString());
+
+        sb.clear();
+        sb.setNullText("null");
+        sb.appendFixedWidthPadLeft(null, 5, '-');
+        assertEquals("-null", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadLeft_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadLeft(123, -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 1, '-');
+        assertEquals("3", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 2, '-');
+        assertEquals("23", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 3, '-');
+        assertEquals("123", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 4, '-');
+        assertEquals("-123", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadLeft(123, 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("-------123", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadRight() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight("foo", -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 1, '-');
+        assertEquals("f", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 2, '-');
+        assertEquals("fo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 3, '-');
+        assertEquals("foo", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 4, '-');
+        assertEquals("foo-", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight("foo", 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("foo-------", sb.toString());
+
+        sb.clear();
+        sb.setNullText("null");
+        sb.appendFixedWidthPadRight(null, 5, '-');
+        assertEquals("null-", sb.toString());
+    }
+
+    // See: http://issues.apache.org/jira/browse/LANG-299
+    @Test
+    public void testLang299() {
+        final StrBuilder sb = new StrBuilder(1);
+        sb.appendFixedWidthPadRight("foo", 1, '-');
+        assertEquals("f", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendFixedWidthPadRight_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight(123, -1, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 0, '-');
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 1, '-');
+        assertEquals("1", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 2, '-');
+        assertEquals("12", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 3, '-');
+        assertEquals("123", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 4, '-');
+        assertEquals("123-", sb.toString());
+
+        sb.clear();
+        sb.appendFixedWidthPadRight(123, 10, '-');
+        assertEquals(10, sb.length());
+        //            1234567890
+        assertEquals("123-------", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppend_FormattedString() {
+        StrBuilder sb;
+
+        sb = new StrBuilder();
+        sb.append("Hi", (Object[]) null);
+        assertEquals("Hi", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("Hi", "Alice");
+        assertEquals("Hi", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("Hi %s", "Alice");
+        assertEquals("Hi Alice", sb.toString());
+
+        sb = new StrBuilder();
+        sb.append("Hi %s %,d", "Alice", 5000);
+        // group separator depends on system locale
+        final char groupingSeparator = DecimalFormatSymbols.getInstance().getGroupingSeparator();
+        final String expected = "Hi Alice 5" + groupingSeparator + "000";
+        assertEquals(expected, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Array() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Object[]) null);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(new Object[0]);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(new Object[]{"foo", "bar", "baz"});
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendAll("foo", "bar", "baz");
+        assertEquals("foobarbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Collection() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Collection<?>) null);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Collections.EMPTY_LIST);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}));
+        assertEquals("foobarbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendAll_Iterator() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendAll((Iterator<?>) null);
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Collections.EMPTY_LIST.iterator());
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendAll(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator());
+        assertEquals("foobarbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparators_Array() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendWithSeparators((Object[]) null, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[0], ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, ",");
+        assertEquals("foo,bar,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[]{"foo", "bar", "baz"}, null);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
+        assertEquals("foo,,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparators_Collection() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendWithSeparators((Collection<?>) null, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Collections.EMPTY_LIST, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}), ",");
+        assertEquals("foo,bar,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}), null);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}), ",");
+        assertEquals("foo,,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparators_Iterator() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendWithSeparators((Iterator<?>) null, ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Collections.EMPTY_LIST.iterator(), ",");
+        assertEquals("", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator(), ",");
+        assertEquals("foo,bar,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", "bar", "baz"}).iterator(), null);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}).iterator(), ",");
+        assertEquals("foo,,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendWithSeparatorsWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("null");
+        sb.appendWithSeparators(new Object[]{"foo", null, "baz"}, ",");
+        assertEquals("foo,null,baz", sb.toString());
+
+        sb.clear();
+        sb.appendWithSeparators(Arrays.asList(new Object[]{"foo", null, "baz"}), ",");
+        assertEquals("foo,null,baz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_String() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(",");  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(",");
+        assertEquals("foo,", sb.toString());
+    }
+    
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_String_String() {
+        final StrBuilder sb = new StrBuilder();
+        final String startSeparator = "order by ";
+        final String standardSeparator = ",";
+        final String foo = "foo";
+        sb.appendSeparator(null, null);
+        assertEquals("", sb.toString());
+        sb.appendSeparator(standardSeparator, null);
+        assertEquals("", sb.toString());
+        sb.appendSeparator(standardSeparator, startSeparator); 
+        assertEquals(startSeparator, sb.toString());
+        sb.appendSeparator(null, null); 
+        assertEquals(startSeparator, sb.toString());
+        sb.appendSeparator(null, startSeparator); 
+        assertEquals(startSeparator, sb.toString());
+        sb.append(foo);
+        assertEquals(startSeparator + foo, sb.toString());
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertEquals(startSeparator + foo + standardSeparator, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_char() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(',');  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(',');
+        assertEquals("foo,", sb.toString());
+    }
+    @Test
+    public void testAppendSeparator_char_char() {
+        final StrBuilder sb = new StrBuilder();
+        final char startSeparator = ':';
+        final char standardSeparator = ',';
+        final String foo = "foo";
+        sb.appendSeparator(standardSeparator, startSeparator);  // no effect
+        assertEquals(String.valueOf(startSeparator), sb.toString());
+        sb.append(foo);
+        assertEquals(String.valueOf(startSeparator) + foo, sb.toString());
+        sb.appendSeparator(standardSeparator, startSeparator);
+        assertEquals(String.valueOf(startSeparator) + foo + standardSeparator, sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_String_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(",", 0);  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(",", 1);
+        assertEquals("foo,", sb.toString());
+        
+        sb.appendSeparator(",", -1);  // no effect
+        assertEquals("foo,", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendSeparator_char_int() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendSeparator(',', 0);  // no effect
+        assertEquals("", sb.toString());
+        sb.append("foo");
+        assertEquals("foo", sb.toString());
+        sb.appendSeparator(',', 1);
+        assertEquals("foo,", sb.toString());
+        
+        sb.appendSeparator(',', -1);  // no effect
+        assertEquals("foo,", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testInsert() {
+
+        final StrBuilder sb = new StrBuilder();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, FOO);
+            fail("insert(-1, Object) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, FOO);
+            fail("insert(7, Object) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (Object) null);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, FOO);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, "foo");
+            fail("insert(-1, String) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, "foo");
+            fail("insert(7, String) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (String) null);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, "foo");
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, new char[]{'f', 'o', 'o'});
+            fail("insert(-1, char[]) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, new char[]{'f', 'o', 'o'});
+            fail("insert(7, char[]) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (char[]) null);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[0]);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[]{'f', 'o', 'o'});
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
+            fail("insert(-1, char[], 3, 3) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
+            fail("insert(7, char[], 3, 3) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (char[]) null, 0, 0);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[0], 0, 0);
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, -1, 3);
+            fail("insert(0, char[], -1, 3) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 10, 3);
+            fail("insert(0, char[], 10, 3) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, -1);
+            fail("insert(0, char[], 0, -1) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 10);
+            fail("insert(0, char[], 0, 10) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 0, 0);
+        assertEquals("barbaz", sb.toString());
+
+        sb.insert(0, new char[]{'a', 'b', 'c', 'f', 'o', 'o', 'd', 'e', 'f'}, 3, 3);
+        assertEquals("foobarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, true);
+            fail("insert(-1, boolean) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, true);
+            fail("insert(7, boolean) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, true);
+        assertEquals("truebarbaz", sb.toString());
+
+        sb.insert(0, false);
+        assertEquals("falsetruebarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, '!');
+            fail("insert(-1, char) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, '!');
+            fail("insert(7, char) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, '!');
+        assertEquals("!barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 0);
+            fail("insert(-1, int) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 0);
+            fail("insert(7, int) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, '0');
+        assertEquals("0barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 1L);
+            fail("insert(-1, long) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 1L);
+            fail("insert(7, long) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, 1L);
+        assertEquals("1barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 2.3F);
+            fail("insert(-1, float) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 2.3F);
+            fail("insert(7, float) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, 2.3F);
+        assertEquals("2.3barbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, 4.5D);
+            fail("insert(-1, double) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, 4.5D);
+            fail("insert(7, double) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, 4.5D);
+        assertEquals("4.5barbaz", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testInsertWithNullText() {
+        final StrBuilder sb = new StrBuilder();
+        sb.setNullText("null");
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, FOO);
+            fail("insert(-1, Object) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, FOO);
+            fail("insert(7, Object) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (Object) null);
+        assertEquals("nullbarbaz", sb.toString());
+
+        sb.insert(0, FOO);
+        assertEquals("foonullbarbaz", sb.toString());
+
+        sb.clear();
+        sb.append("barbaz");
+        assertEquals("barbaz", sb.toString());
+
+        try {
+            sb.insert(-1, "foo");
+            fail("insert(-1, String) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        try {
+            sb.insert(7, "foo");
+            fail("insert(7, String) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.insert(0, (String) null);
+        assertEquals("nullbarbaz", sb.toString());
+
+        sb.insert(0, "foo");
+        assertEquals("foonullbarbaz", sb.toString());
+
+        sb.insert(0, (char[]) null);
+        assertEquals("nullfoonullbarbaz", sb.toString());
+
+        sb.insert(0, (char[]) null, 0, 0);
+        assertEquals("nullnullfoonullbarbaz", sb.toString());
+    }
+}


[38/50] [abbrv] [text] TEXT-65: created TEXT-68 removing TODO

Posted by ch...@apache.org.
TEXT-65: created TEXT-68 removing TODO


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/1063a8d5
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/1063a8d5
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/1063a8d5

Branch: refs/heads/release
Commit: 1063a8d5e70394a55f24e26136f5f044b32fff28
Parents: 5842b23
Author: Rob Tompkins <ch...@apache.org>
Authored: Fri Feb 17 08:39:05 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Fri Feb 17 08:39:05 2017 -0500

----------------------------------------------------------------------
 src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/1063a8d5/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java b/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
index 8fba4b4..a78a719 100644
--- a/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
@@ -114,7 +114,6 @@ public class UnicodeEscaper extends CodePointTranslator {
             }
         }
 
-        // TODO: Handle potential + sign per various Unicode escape implementations
         if (codepoint > 0xffff) {
             out.write(toUtf16Escape(codepoint));
         } else {


[13/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StrBuilderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrBuilderTest.java b/src/test/java/org/apache/commons/text/StrBuilderTest.java
new file mode 100644
index 0000000..a0c923b
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrBuilderTest.java
@@ -0,0 +1,2007 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.CharBuffer;
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link StrBuilder}.
+ */
+public class StrBuilderTest {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructors() {
+        final StrBuilder sb0 = new StrBuilder();
+        assertEquals(32, sb0.capacity());
+        assertEquals(0, sb0.length());
+        assertEquals(0, sb0.size());
+
+        final StrBuilder sb1 = new StrBuilder(32);
+        assertEquals(32, sb1.capacity());
+        assertEquals(0, sb1.length());
+        assertEquals(0, sb1.size());
+
+        final StrBuilder sb2 = new StrBuilder(0);
+        assertEquals(32, sb2.capacity());
+        assertEquals(0, sb2.length());
+        assertEquals(0, sb2.size());
+
+        final StrBuilder sb3 = new StrBuilder(-1);
+        assertEquals(32, sb3.capacity());
+        assertEquals(0, sb3.length());
+        assertEquals(0, sb3.size());
+
+        final StrBuilder sb4 = new StrBuilder(1);
+        assertEquals(1, sb4.capacity());
+        assertEquals(0, sb4.length());
+        assertEquals(0, sb4.size());
+
+        final StrBuilder sb5 = new StrBuilder((String) null);
+        assertEquals(32, sb5.capacity());
+        assertEquals(0, sb5.length());
+        assertEquals(0, sb5.size());
+
+        final StrBuilder sb6 = new StrBuilder("");
+        assertEquals(32, sb6.capacity());
+        assertEquals(0, sb6.length());
+        assertEquals(0, sb6.size());
+
+        final StrBuilder sb7 = new StrBuilder("foo");
+        assertEquals(35, sb7.capacity());
+        assertEquals(3, sb7.length());
+        assertEquals(3, sb7.size());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testChaining() {
+        final StrBuilder sb = new StrBuilder();
+        assertSame(sb, sb.setNewLineText(null));
+        assertSame(sb, sb.setNullText(null));
+        assertSame(sb, sb.setLength(1));
+        assertSame(sb, sb.setCharAt(0, 'a'));
+        assertSame(sb, sb.ensureCapacity(0));
+        assertSame(sb, sb.minimizeCapacity());
+        assertSame(sb, sb.clear());
+        assertSame(sb, sb.reverse());
+        assertSame(sb, sb.trim());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReadFromReader() throws Exception {
+        String s = "";
+        for (int i = 0; i < 100; ++i) {
+            final StrBuilder sb = new StrBuilder();
+            final int len = sb.readFrom(new StringReader(s));
+
+            assertEquals(s.length(), len);
+            assertEquals(s, sb.toString());
+
+            s += Integer.toString(i);
+        }
+    }
+
+    @Test
+    public void testReadFromReaderAppendsToEnd() throws Exception {
+        final StrBuilder sb = new StrBuilder("Test");
+        sb.readFrom(new StringReader(" 123"));
+        assertEquals("Test 123", sb.toString());
+    }
+
+    @Test
+    public void testReadFromCharBuffer() throws Exception {
+        String s = "";
+        for (int i = 0; i < 100; ++i) {
+            final StrBuilder sb = new StrBuilder();
+            final int len = sb.readFrom(CharBuffer.wrap(s));
+
+            assertEquals(s.length(), len);
+            assertEquals(s, sb.toString());
+
+            s += Integer.toString(i);
+        }
+    }
+
+    @Test
+    public void testReadFromCharBufferAppendsToEnd() throws Exception {
+        final StrBuilder sb = new StrBuilder("Test");
+        sb.readFrom(CharBuffer.wrap(" 123"));
+        assertEquals("Test 123", sb.toString());
+    }
+
+    @Test
+    public void testReadFromReadable() throws Exception {
+        String s = "";
+        for (int i = 0; i < 100; ++i) {
+            final StrBuilder sb = new StrBuilder();
+            final int len = sb.readFrom(new MockReadable(s));
+
+            assertEquals(s.length(), len);
+            assertEquals(s, sb.toString());
+
+            s += Integer.toString(i);
+        }
+    }
+
+    @Test
+    public void testReadFromReadableAppendsToEnd() throws Exception {
+        final StrBuilder sb = new StrBuilder("Test");
+        sb.readFrom(new MockReadable(" 123"));
+        assertEquals("Test 123", sb.toString());
+    }
+
+    private static class MockReadable implements Readable {
+
+        private final CharBuffer src;
+
+        public MockReadable(final String src) {
+            this.src = CharBuffer.wrap(src);
+        }
+
+        @Override
+        public int read(final CharBuffer cb) throws IOException {
+            return src.read(cb);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testGetSetNewLineText() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(null, sb.getNewLineText());
+
+        sb.setNewLineText("#");
+        assertEquals("#", sb.getNewLineText());
+
+        sb.setNewLineText("");
+        assertEquals("", sb.getNewLineText());
+
+        sb.setNewLineText((String) null);
+        assertEquals(null, sb.getNewLineText());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testGetSetNullText() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(null, sb.getNullText());
+
+        sb.setNullText("null");
+        assertEquals("null", sb.getNullText());
+
+        sb.setNullText("");
+        assertEquals(null, sb.getNullText());
+
+        sb.setNullText("NULL");
+        assertEquals("NULL", sb.getNullText());
+
+        sb.setNullText((String) null);
+        assertEquals(null, sb.getNullText());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCapacityAndLength() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(32, sb.capacity());
+        assertEquals(0, sb.length());
+        assertEquals(0, sb.size());
+        assertTrue(sb.isEmpty());
+
+        sb.minimizeCapacity();
+        assertEquals(0, sb.capacity());
+        assertEquals(0, sb.length());
+        assertEquals(0, sb.size());
+        assertTrue(sb.isEmpty());
+
+        sb.ensureCapacity(32);
+        assertTrue(sb.capacity() >= 32);
+        assertEquals(0, sb.length());
+        assertEquals(0, sb.size());
+        assertTrue(sb.isEmpty());
+
+        sb.append("foo");
+        assertTrue(sb.capacity() >= 32);
+        assertEquals(3, sb.length());
+        assertEquals(3, sb.size());
+        assertTrue(sb.isEmpty() == false);
+
+        sb.clear();
+        assertTrue(sb.capacity() >= 32);
+        assertEquals(0, sb.length());
+        assertEquals(0, sb.size());
+        assertTrue(sb.isEmpty());
+
+        sb.append("123456789012345678901234567890123");
+        assertTrue(sb.capacity() > 32);
+        assertEquals(33, sb.length());
+        assertEquals(33, sb.size());
+        assertTrue(sb.isEmpty() == false);
+
+        sb.ensureCapacity(16);
+        assertTrue(sb.capacity() > 16);
+        assertEquals(33, sb.length());
+        assertEquals(33, sb.size());
+        assertTrue(sb.isEmpty() == false);
+
+        sb.minimizeCapacity();
+        assertEquals(33, sb.capacity());
+        assertEquals(33, sb.length());
+        assertEquals(33, sb.size());
+        assertTrue(sb.isEmpty() == false);
+
+        try {
+            sb.setLength(-1);
+            fail("setLength(-1) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+
+        sb.setLength(33);
+        assertEquals(33, sb.capacity());
+        assertEquals(33, sb.length());
+        assertEquals(33, sb.size());
+        assertTrue(sb.isEmpty() == false);
+
+        sb.setLength(16);
+        assertTrue(sb.capacity() >= 16);
+        assertEquals(16, sb.length());
+        assertEquals(16, sb.size());
+        assertEquals("1234567890123456", sb.toString());
+        assertTrue(sb.isEmpty() == false);
+
+        sb.setLength(32);
+        assertTrue(sb.capacity() >= 32);
+        assertEquals(32, sb.length());
+        assertEquals(32, sb.size());
+        assertEquals("1234567890123456\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sb.toString());
+        assertTrue(sb.isEmpty() == false);
+
+        sb.setLength(0);
+        assertTrue(sb.capacity() >= 32);
+        assertEquals(0, sb.length());
+        assertEquals(0, sb.size());
+        assertTrue(sb.isEmpty());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testLength() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.length());
+        
+        sb.append("Hello");
+        assertEquals(5, sb.length());
+    }
+
+    @Test
+    public void testSetLength() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append("Hello");
+        sb.setLength(2);  // shorten
+        assertEquals("He", sb.toString());
+        sb.setLength(2);  // no change
+        assertEquals("He", sb.toString());
+        sb.setLength(3);  // lengthen
+        assertEquals("He\0", sb.toString());
+
+        try {
+            sb.setLength(-1);
+            fail("setLength(-1) expected StringIndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCapacity() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(sb.buffer.length, sb.capacity());
+        
+        sb.append("HelloWorldHelloWorldHelloWorldHelloWorld");
+        assertEquals(sb.buffer.length, sb.capacity());
+    }
+
+    @Test
+    public void testEnsureCapacity() {
+        final StrBuilder sb = new StrBuilder();
+        sb.ensureCapacity(2);
+        assertTrue(sb.capacity() >= 2);
+        
+        sb.ensureCapacity(-1);
+        assertTrue(sb.capacity() >= 0);
+        
+        sb.append("HelloWorld");
+        sb.ensureCapacity(40);
+        assertTrue(sb.capacity() >= 40);
+    }
+
+    @Test
+    public void testMinimizeCapacity() {
+        final StrBuilder sb = new StrBuilder();
+        sb.minimizeCapacity();
+        assertEquals(0, sb.capacity());
+        
+        sb.append("HelloWorld");
+        sb.minimizeCapacity();
+        assertEquals(10, sb.capacity());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSize() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.size());
+        
+        sb.append("Hello");
+        assertEquals(5, sb.size());
+    }
+
+    @Test
+    public void testIsEmpty() {
+        final StrBuilder sb = new StrBuilder();
+        assertTrue(sb.isEmpty());
+        
+        sb.append("Hello");
+        assertFalse(sb.isEmpty());
+        
+        sb.clear();
+        assertTrue(sb.isEmpty());
+    }
+
+    @Test
+    public void testClear() {
+        final StrBuilder sb = new StrBuilder();
+        sb.append("Hello");
+        sb.clear();
+        assertEquals(0, sb.length());
+        assertTrue(sb.buffer.length >= 5);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCharAt() {
+        final StrBuilder sb = new StrBuilder();
+        try {
+            sb.charAt(0);
+            fail("charAt(0) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            sb.charAt(-1);
+            fail("charAt(-1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        sb.append("foo");
+        assertEquals('f', sb.charAt(0));
+        assertEquals('o', sb.charAt(1));
+        assertEquals('o', sb.charAt(2));
+        try {
+            sb.charAt(-1);
+            fail("charAt(-1) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            sb.charAt(3);
+            fail("charAt(3) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSetCharAt() {
+        final StrBuilder sb = new StrBuilder();
+        try {
+            sb.setCharAt(0, 'f');
+            fail("setCharAt(0,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        try {
+            sb.setCharAt(-1, 'f');
+            fail("setCharAt(-1,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        sb.append("foo");
+        sb.setCharAt(0, 'b');
+        sb.setCharAt(1, 'a');
+        sb.setCharAt(2, 'r');
+        try {
+            sb.setCharAt(3, '!');
+            fail("setCharAt(3,) expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {
+            // expected
+        }
+        assertEquals("bar", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testDeleteCharAt() {
+        final StrBuilder sb = new StrBuilder("abc");
+        sb.deleteCharAt(0);
+        assertEquals("bc", sb.toString()); 
+        
+        try {
+            sb.deleteCharAt(1000);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testToCharArray() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.toCharArray().length);
+
+        char[] a = sb.toCharArray();
+        assertNotNull("toCharArray() result is null", a);
+        assertEquals("toCharArray() result is too large", 0, a.length);
+
+        sb.append("junit");
+        a = sb.toCharArray();
+        assertEquals("toCharArray() result incorrect length", 5, a.length);
+        assertTrue("toCharArray() result does not match", Arrays.equals("junit".toCharArray(), a));
+    }
+
+    @Test
+    public void testToCharArrayIntInt() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(0, sb.toCharArray(0, 0).length);
+
+        sb.append("junit");
+        char[] a = sb.toCharArray(0, 20); // too large test
+        assertEquals("toCharArray(int,int) result incorrect length", 5, a.length);
+        assertTrue("toCharArray(int,int) result does not match", Arrays.equals("junit".toCharArray(), a));
+
+        a = sb.toCharArray(0, 4);
+        assertEquals("toCharArray(int,int) result incorrect length", 4, a.length);
+        assertTrue("toCharArray(int,int) result does not match", Arrays.equals("juni".toCharArray(), a));
+
+        a = sb.toCharArray(0, 4);
+        assertEquals("toCharArray(int,int) result incorrect length", 4, a.length);
+        assertTrue("toCharArray(int,int) result does not match", Arrays.equals("juni".toCharArray(), a));
+
+        a = sb.toCharArray(0, 1);
+        assertNotNull("toCharArray(int,int) result is null", a);
+
+        try {
+            sb.toCharArray(-1, 5);
+            fail("no string index out of bound on -1");
+        } catch (final IndexOutOfBoundsException e) {
+        }
+
+        try {
+            sb.toCharArray(6, 5);
+            fail("no string index out of bound on -1");
+        } catch (final IndexOutOfBoundsException e) {
+        }
+    }
+
+    @Test
+    public void testGetChars ( ) {
+        final StrBuilder sb = new StrBuilder();
+        
+        char[] input = new char[10];
+        char[] a = sb.getChars(input);
+        assertSame (input, a);
+        assertTrue(Arrays.equals(new char[10], a));
+        
+        sb.append("junit");
+        a = sb.getChars(input);
+        assertSame(input, a);
+        assertTrue(Arrays.equals(new char[] {'j','u','n','i','t',0,0,0,0,0},a));
+        
+        a = sb.getChars(null);
+        assertNotSame(input,a);
+        assertEquals(5,a.length);
+        assertTrue(Arrays.equals("junit".toCharArray(),a));
+        
+        input = new char[5];
+        a = sb.getChars(input);
+        assertSame(input, a);
+        
+        input = new char[4];
+        a = sb.getChars(input);
+        assertNotSame(input, a);
+    }
+
+    @Test
+    public void testGetCharsIntIntCharArrayInt( ) {
+        final StrBuilder sb = new StrBuilder();
+               
+        sb.append("junit");
+        char[] a = new char[5];
+        sb.getChars(0,5,a,0);
+        assertTrue(Arrays.equals(new char[] {'j','u','n','i','t'},a));
+        
+        a = new char[5];
+        sb.getChars(0,2,a,3);
+        assertTrue(Arrays.equals(new char[] {0,0,0,'j','u'},a));
+        
+        try {
+            sb.getChars(-1,0,a,0);
+            fail("no exception");
+        }
+        catch (final IndexOutOfBoundsException e) {
+        }
+        
+        try {
+            sb.getChars(0,-1,a,0);
+            fail("no exception");
+        }
+        catch (final IndexOutOfBoundsException e) {
+        }
+        
+        try {
+            sb.getChars(0,20,a,0);
+            fail("no exception");
+        }
+        catch (final IndexOutOfBoundsException e) {
+        }
+        
+        try {
+            sb.getChars(4,2,a,0);
+            fail("no exception");
+        }
+        catch (final IndexOutOfBoundsException e) {
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testDeleteIntInt() {
+        StrBuilder sb = new StrBuilder("abc");
+        sb.delete(0, 1);
+        assertEquals("bc", sb.toString()); 
+        sb.delete(1, 2);
+        assertEquals("b", sb.toString());
+        sb.delete(0, 1);
+        assertEquals("", sb.toString()); 
+        sb.delete(0, 1000);
+        assertEquals("", sb.toString()); 
+        
+        try {
+            sb.delete(1, 2);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+        try {
+            sb.delete(-1, 1);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        sb = new StrBuilder("anything");
+        try {
+            sb.delete(2, 1);
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testDeleteAll_char() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.deleteAll('X');
+        assertEquals("abcbccba", sb.toString());
+        sb.deleteAll('a');
+        assertEquals("bcbccb", sb.toString());
+        sb.deleteAll('c');
+        assertEquals("bbb", sb.toString());
+        sb.deleteAll('b');
+        assertEquals("", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteAll('b');
+        assertEquals("", sb.toString());
+    }
+
+    @Test
+    public void testDeleteFirst_char() {
+        StrBuilder sb = new StrBuilder("abcba");
+        sb.deleteFirst('X');
+        assertEquals("abcba", sb.toString());
+        sb.deleteFirst('a');
+        assertEquals("bcba", sb.toString());
+        sb.deleteFirst('c');
+        assertEquals("bba", sb.toString());
+        sb.deleteFirst('b');
+        assertEquals("ba", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteFirst('b');
+        assertEquals("", sb.toString());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testDeleteAll_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.deleteAll((String) null);
+        assertEquals("abcbccba", sb.toString());
+        sb.deleteAll("");
+        assertEquals("abcbccba", sb.toString());
+        
+        sb.deleteAll("X");
+        assertEquals("abcbccba", sb.toString());
+        sb.deleteAll("a");
+        assertEquals("bcbccb", sb.toString());
+        sb.deleteAll("c");
+        assertEquals("bbb", sb.toString());
+        sb.deleteAll("b");
+        assertEquals("", sb.toString());
+
+        sb = new StrBuilder("abcbccba");
+        sb.deleteAll("bc");
+        assertEquals("acba", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteAll("bc");
+        assertEquals("", sb.toString());
+    }
+
+    @Test
+    public void testDeleteFirst_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.deleteFirst((String) null);
+        assertEquals("abcbccba", sb.toString());
+        sb.deleteFirst("");
+        assertEquals("abcbccba", sb.toString());
+
+        sb.deleteFirst("X");
+        assertEquals("abcbccba", sb.toString());
+        sb.deleteFirst("a");
+        assertEquals("bcbccba", sb.toString());
+        sb.deleteFirst("c");
+        assertEquals("bbccba", sb.toString());
+        sb.deleteFirst("b");
+        assertEquals("bccba", sb.toString());
+
+        sb = new StrBuilder("abcbccba");
+        sb.deleteFirst("bc");
+        assertEquals("abccba", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteFirst("bc");
+        assertEquals("", sb.toString());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testDeleteAll_StrMatcher() {
+        StrBuilder sb = new StrBuilder("A0xA1A2yA3");
+        sb.deleteAll((StrMatcher) null);
+        assertEquals("A0xA1A2yA3", sb.toString());
+        sb.deleteAll(A_NUMBER_MATCHER);
+        assertEquals("xy", sb.toString());
+
+        sb = new StrBuilder("Ax1");
+        sb.deleteAll(A_NUMBER_MATCHER);
+        assertEquals("Ax1", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteAll(A_NUMBER_MATCHER);
+        assertEquals("", sb.toString());
+    }
+
+    @Test
+    public void testDeleteFirst_StrMatcher() {
+        StrBuilder sb = new StrBuilder("A0xA1A2yA3");
+        sb.deleteFirst((StrMatcher) null);
+        assertEquals("A0xA1A2yA3", sb.toString());
+        sb.deleteFirst(A_NUMBER_MATCHER);
+        assertEquals("xA1A2yA3", sb.toString());
+
+        sb = new StrBuilder("Ax1");
+        sb.deleteFirst(A_NUMBER_MATCHER);
+        assertEquals("Ax1", sb.toString());
+
+        sb = new StrBuilder("");
+        sb.deleteFirst(A_NUMBER_MATCHER);
+        assertEquals("", sb.toString());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testReplace_int_int_String() {
+        StrBuilder sb = new StrBuilder("abc");
+        sb.replace(0, 1, "d");
+        assertEquals("dbc", sb.toString());
+        sb.replace(0, 1, "aaa");
+        assertEquals("aaabc", sb.toString());
+        sb.replace(0, 3, "");
+        assertEquals("bc", sb.toString());
+        sb.replace(1, 2, (String) null);
+        assertEquals("b", sb.toString());
+        sb.replace(1, 1000, "text");
+        assertEquals("btext", sb.toString());
+        sb.replace(0, 1000, "text");
+        assertEquals("text", sb.toString());
+        
+        sb = new StrBuilder("atext");
+        sb.replace(1, 1, "ny");
+        assertEquals("anytext", sb.toString());
+        try {
+            sb.replace(2, 1, "anything");
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        sb = new StrBuilder();
+        try {
+            sb.replace(1, 2, "anything");
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+        try {
+            sb.replace(-1, 1, "anything");
+            fail("Expected IndexOutOfBoundsException");
+        } catch (final IndexOutOfBoundsException e) {}
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReplaceAll_char_char() {
+        final StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceAll('x', 'y');
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll('a', 'd');
+        assertEquals("dbcbccbd", sb.toString());
+        sb.replaceAll('b', 'e');
+        assertEquals("dececced", sb.toString());
+        sb.replaceAll('c', 'f');
+        assertEquals("defeffed", sb.toString());
+        sb.replaceAll('d', 'd');
+        assertEquals("defeffed", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReplaceFirst_char_char() {
+        final StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceFirst('x', 'y');
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst('a', 'd');
+        assertEquals("dbcbccba", sb.toString());
+        sb.replaceFirst('b', 'e');
+        assertEquals("decbccba", sb.toString());
+        sb.replaceFirst('c', 'f');
+        assertEquals("defbccba", sb.toString());
+        sb.replaceFirst('d', 'd');
+        assertEquals("defbccba", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReplaceAll_String_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceAll((String) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll((String) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll("", null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll("", "anything");
+        assertEquals("abcbccba", sb.toString());
+        
+        sb.replaceAll("x", "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll("a", "d");
+        assertEquals("dbcbccbd", sb.toString());
+        sb.replaceAll("d", null);
+        assertEquals("bcbccb", sb.toString());
+        sb.replaceAll("cb", "-");
+        assertEquals("b-c-", sb.toString());
+        
+        sb = new StrBuilder("abcba");
+        sb.replaceAll("b", "xbx");
+        assertEquals("axbxcxbxa", sb.toString());
+        
+        sb = new StrBuilder("bb");
+        sb.replaceAll("b", "xbx");
+        assertEquals("xbxxbx", sb.toString());
+    }
+
+    @Test
+    public void testReplaceFirst_String_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceFirst((String) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst((String) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst("", null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst("", "anything");
+        assertEquals("abcbccba", sb.toString());
+        
+        sb.replaceFirst("x", "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst("a", "d");
+        assertEquals("dbcbccba", sb.toString());
+        sb.replaceFirst("d", null);
+        assertEquals("bcbccba", sb.toString());
+        sb.replaceFirst("cb", "-");
+        assertEquals("b-ccba", sb.toString());
+        
+        sb = new StrBuilder("abcba");
+        sb.replaceFirst("b", "xbx");
+        assertEquals("axbxcba", sb.toString());
+        
+        sb = new StrBuilder("bb");
+        sb.replaceFirst("b", "xbx");
+        assertEquals("xbxb", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReplaceAll_StrMatcher_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceAll((StrMatcher) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll((StrMatcher) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll(StrMatcher.noneMatcher(), null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll(StrMatcher.noneMatcher(), "anything");
+        assertEquals("abcbccba", sb.toString());
+        
+        sb.replaceAll(StrMatcher.charMatcher('x'), "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceAll(StrMatcher.charMatcher('a'), "d");
+        assertEquals("dbcbccbd", sb.toString());
+        sb.replaceAll(StrMatcher.charMatcher('d'), null);
+        assertEquals("bcbccb", sb.toString());
+        sb.replaceAll(StrMatcher.stringMatcher("cb"), "-");
+        assertEquals("b-c-", sb.toString());
+        
+        sb = new StrBuilder("abcba");
+        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("axbxcxbxa", sb.toString());
+        
+        sb = new StrBuilder("bb");
+        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("xbxxbx", sb.toString());
+        
+        sb = new StrBuilder("A1-A2A3-A4");
+        sb.replaceAll(A_NUMBER_MATCHER, "***");
+        assertEquals("***-******-***", sb.toString());
+
+        sb = new StrBuilder("Dear X, hello X.");
+        sb.replaceAll(StrMatcher.stringMatcher("X"), "012345678901234567");
+        assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString());
+    }
+
+    @Test
+    public void testReplaceFirst_StrMatcher_String() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replaceFirst((StrMatcher) null, null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst((StrMatcher) null, "anything");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.noneMatcher(), null);
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.noneMatcher(), "anything");
+        assertEquals("abcbccba", sb.toString());
+        
+        sb.replaceFirst(StrMatcher.charMatcher('x'), "y");
+        assertEquals("abcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.charMatcher('a'), "d");
+        assertEquals("dbcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.charMatcher('d'), null);
+        assertEquals("bcbccba", sb.toString());
+        sb.replaceFirst(StrMatcher.stringMatcher("cb"), "-");
+        assertEquals("b-ccba", sb.toString());
+        
+        sb = new StrBuilder("abcba");
+        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("axbxcba", sb.toString());
+        
+        sb = new StrBuilder("bb");
+        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
+        assertEquals("xbxb", sb.toString());
+        
+        sb = new StrBuilder("A1-A2A3-A4");
+        sb.replaceFirst(A_NUMBER_MATCHER, "***");
+        assertEquals("***-A2A3-A4", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReplace_StrMatcher_String_int_int_int_VaryMatcher() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replace((StrMatcher) null, "x", 0, sb.length(), -1);
+        assertEquals("abcbccba", sb.toString());
+        
+        sb.replace(StrMatcher.charMatcher('a'), "x", 0, sb.length(), -1);
+        assertEquals("xbcbccbx", sb.toString());
+        
+        sb.replace(StrMatcher.stringMatcher("cb"), "x", 0, sb.length(), -1);
+        assertEquals("xbxcxx", sb.toString());
+        
+        sb = new StrBuilder("A1-A2A3-A4");
+        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
+        assertEquals("***-******-***", sb.toString());
+        
+        sb = new StrBuilder();
+        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
+        assertEquals("", sb.toString());
+    }
+
+    @Test
+    public void testReplace_StrMatcher_String_int_int_int_VaryReplace() {
+        StrBuilder sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "cb", 0, sb.length(), -1);
+        assertEquals("abcbccba", sb.toString());
+        
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "-", 0, sb.length(), -1);
+        assertEquals("ab-c-a", sb.toString());
+        
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "+++", 0, sb.length(), -1);
+        assertEquals("ab+++c+++a", sb.toString());
+        
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), "", 0, sb.length(), -1);
+        assertEquals("abca", sb.toString());
+        
+        sb = new StrBuilder("abcbccba");
+        sb.replace(StrMatcher.stringMatcher("cb"), null, 0, sb.length(), -1);
+        assertEquals("abca", sb.toString());
+    }
+
+    @Test
+    public void testReplace_StrMatcher_String_int_int_int_VaryStartIndex() {
+        StrBuilder sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, sb.length(), -1);
+        assertEquals("-x--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 1, sb.length(), -1);
+        assertEquals("aax--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, sb.length(), -1);
+        assertEquals("aax--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 3, sb.length(), -1);
+        assertEquals("aax--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 4, sb.length(), -1);
+        assertEquals("aaxa-ay-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 5, sb.length(), -1);
+        assertEquals("aaxaa-y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 6, sb.length(), -1);
+        assertEquals("aaxaaaay-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 7, sb.length(), -1);
+        assertEquals("aaxaaaay-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 8, sb.length(), -1);
+        assertEquals("aaxaaaay-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 9, sb.length(), -1);
+        assertEquals("aaxaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 10, sb.length(), -1);
+        assertEquals("aaxaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        try {
+            sb.replace(StrMatcher.stringMatcher("aa"), "-", 11, sb.length(), -1);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        assertEquals("aaxaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        try {
+            sb.replace(StrMatcher.stringMatcher("aa"), "-", -1, sb.length(), -1);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        assertEquals("aaxaaaayaa", sb.toString());
+    }
+
+    @Test
+    public void testReplace_StrMatcher_String_int_int_int_VaryEndIndex() {
+        StrBuilder sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 0, -1);
+        assertEquals("aaxaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 2, -1);
+        assertEquals("-xaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 3, -1);
+        assertEquals("-xaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 4, -1);
+        assertEquals("-xaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 5, -1);
+        assertEquals("-x-aayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 6, -1);
+        assertEquals("-x-aayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 7, -1);
+        assertEquals("-x--yaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 8, -1);
+        assertEquals("-x--yaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 9, -1);
+        assertEquals("-x--yaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
+        assertEquals("-x--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 1000, -1);
+        assertEquals("-x--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        try {
+            sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, 1, -1);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        assertEquals("aaxaaaayaa", sb.toString());
+    }
+
+    @Test
+    public void testReplace_StrMatcher_String_int_int_int_VaryCount() {
+        StrBuilder sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
+        assertEquals("-x--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 0);
+        assertEquals("aaxaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 1);
+        assertEquals("-xaaaayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 2);
+        assertEquals("-x-aayaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 3);
+        assertEquals("-x--yaa", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 4);
+        assertEquals("-x--y-", sb.toString());
+        
+        sb = new StrBuilder("aaxaaaayaa");
+        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 5);
+        assertEquals("-x--y-", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReverse() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals("", sb.reverse().toString());
+        
+        sb.clear().append(true);
+        assertEquals("eurt", sb.reverse().toString());
+        assertEquals("true", sb.reverse().toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTrim() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals("", sb.reverse().toString());
+        
+        sb.clear().append(" \u0000 ");
+        assertEquals("", sb.trim().toString());
+        
+        sb.clear().append(" \u0000 a b c");
+        assertEquals("a b c", sb.trim().toString());
+        
+        sb.clear().append("a b c \u0000 ");
+        assertEquals("a b c", sb.trim().toString());
+        
+        sb.clear().append(" \u0000 a b c \u0000 ");
+        assertEquals("a b c", sb.trim().toString());
+        
+        sb.clear().append("a b c");
+        assertEquals("a b c", sb.trim().toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testStartsWith() {
+        final StrBuilder sb = new StrBuilder();
+        assertFalse(sb.startsWith("a"));
+        assertFalse(sb.startsWith(null));
+        assertTrue(sb.startsWith(""));
+        sb.append("abc");
+        assertTrue(sb.startsWith("a"));
+        assertTrue(sb.startsWith("ab"));
+        assertTrue(sb.startsWith("abc"));
+        assertFalse(sb.startsWith("cba"));
+    }
+
+    @Test
+    public void testEndsWith() {
+        final StrBuilder sb = new StrBuilder();
+        assertFalse(sb.endsWith("a"));
+        assertFalse(sb.endsWith("c"));
+        assertTrue(sb.endsWith(""));
+        assertFalse(sb.endsWith(null));
+        sb.append("abc");
+        assertTrue(sb.endsWith("c"));
+        assertTrue(sb.endsWith("bc"));
+        assertTrue(sb.endsWith("abc"));
+        assertFalse(sb.endsWith("cba"));
+        assertFalse(sb.endsWith("abcd"));
+        assertFalse(sb.endsWith(" abc"));
+        assertFalse(sb.endsWith("abc "));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSubSequenceIntInt() {
+       final StrBuilder sb = new StrBuilder ("hello goodbye");
+       // Start index is negative
+       try {
+            sb.subSequence(-1, 5);
+            fail();
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        // End index is negative
+       try {
+            sb.subSequence(2, -1);
+            fail();
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        // End index greater than length()
+        try {
+            sb.subSequence(2, sb.length() + 1);
+            fail();
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        // Start index greater then end index
+        try {
+            sb.subSequence(3, 2);
+            fail();
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        // Normal cases
+        assertEquals ("hello", sb.subSequence(0, 5));
+        assertEquals ("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
+        assertEquals ("goodbye", sb.subSequence(6, 13));
+        assertEquals ("hello goodbye".subSequence(6,13), sb.subSequence(6, 13));
+    }
+
+    @Test
+    public void testSubstringInt() {
+        final StrBuilder sb = new StrBuilder ("hello goodbye");
+        assertEquals ("goodbye", sb.substring(6));
+        assertEquals ("hello goodbye".substring(6), sb.substring(6));
+        assertEquals ("hello goodbye", sb.substring(0));
+        assertEquals ("hello goodbye".substring(0), sb.substring(0));
+        try {
+            sb.substring(-1);
+            fail ();
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        try {
+            sb.substring(15);
+            fail ();
+        } catch (final IndexOutOfBoundsException e) {}
+    
+    }
+    
+    @Test
+    public void testSubstringIntInt() {
+        final StrBuilder sb = new StrBuilder ("hello goodbye");
+        assertEquals ("hello", sb.substring(0, 5));
+        assertEquals ("hello goodbye".substring(0, 6), sb.substring(0, 6));
+        
+        assertEquals ("goodbye", sb.substring(6, 13));
+        assertEquals ("hello goodbye".substring(6,13), sb.substring(6, 13));
+        
+        assertEquals ("goodbye", sb.substring(6, 20));
+        
+        try {
+            sb.substring(-1, 5);
+            fail();
+        } catch (final IndexOutOfBoundsException e) {}
+        
+        try {
+            sb.substring(15, 20);
+            fail();
+        } catch (final IndexOutOfBoundsException e) {}
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testMidString() {
+        final StrBuilder sb = new StrBuilder("hello goodbye hello");
+        assertEquals("goodbye", sb.midString(6, 7));
+        assertEquals("hello", sb.midString(0, 5));
+        assertEquals("hello", sb.midString(-5, 5));
+        assertEquals("", sb.midString(0, -1));
+        assertEquals("", sb.midString(20, 2));
+        assertEquals("hello", sb.midString(14, 22));
+    }
+
+    @Test
+    public void testRightString() {
+        final StrBuilder sb = new StrBuilder("left right");
+        assertEquals("right", sb.rightString(5));
+        assertEquals("", sb.rightString(0));
+        assertEquals("", sb.rightString(-5));
+        assertEquals("left right", sb.rightString(15));
+    }
+
+    @Test
+    public void testLeftString() {
+        final StrBuilder sb = new StrBuilder("left right");
+        assertEquals("left", sb.leftString(4));
+        assertEquals("", sb.leftString(0));
+        assertEquals("", sb.leftString(-5));
+        assertEquals("left right", sb.leftString(15));
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testContains_char() {
+        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
+        assertTrue(sb.contains('a'));
+        assertTrue(sb.contains('o'));
+        assertTrue(sb.contains('z'));
+        assertFalse(sb.contains('1'));
+    }
+
+    @Test
+    public void testContains_String() {
+        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
+        assertTrue(sb.contains("a"));
+        assertTrue(sb.contains("pq"));
+        assertTrue(sb.contains("z"));
+        assertFalse(sb.contains("zyx"));
+        assertFalse(sb.contains((String) null));
+    }
+
+    @Test
+    public void testContains_StrMatcher() {
+        StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
+        assertTrue(sb.contains(StrMatcher.charMatcher('a')));
+        assertTrue(sb.contains(StrMatcher.stringMatcher("pq")));
+        assertTrue(sb.contains(StrMatcher.charMatcher('z')));
+        assertFalse(sb.contains(StrMatcher.stringMatcher("zy")));
+        assertFalse(sb.contains((StrMatcher) null));
+
+        sb = new StrBuilder();
+        assertFalse(sb.contains(A_NUMBER_MATCHER));
+        sb.append("B A1 C");
+        assertTrue(sb.contains(A_NUMBER_MATCHER));
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testIndexOf_char() {
+        final StrBuilder sb = new StrBuilder("abab");
+        assertEquals(0, sb.indexOf('a'));
+        
+        // should work like String#indexOf
+        assertEquals("abab".indexOf('a'), sb.indexOf('a'));
+
+        assertEquals(1, sb.indexOf('b'));
+        assertEquals("abab".indexOf('b'), sb.indexOf('b'));
+
+        assertEquals(-1, sb.indexOf('z'));
+    }
+
+    @Test
+    public void testIndexOf_char_int() {
+        StrBuilder sb = new StrBuilder("abab");
+        assertEquals(0, sb.indexOf('a', -1));
+        assertEquals(0, sb.indexOf('a', 0));
+        assertEquals(2, sb.indexOf('a', 1));
+        assertEquals(-1, sb.indexOf('a', 4));
+        assertEquals(-1, sb.indexOf('a', 5));
+
+        // should work like String#indexOf
+        assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
+
+        assertEquals(3, sb.indexOf('b', 2));
+        assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
+
+        assertEquals(-1, sb.indexOf('z', 2));
+
+        sb = new StrBuilder("xyzabc");
+        assertEquals(2, sb.indexOf('z', 0));
+        assertEquals(-1, sb.indexOf('z', 3));
+    }
+
+    @Test
+    public void testLastIndexOf_char() {
+        final StrBuilder sb = new StrBuilder("abab");
+        
+        assertEquals (2, sb.lastIndexOf('a'));
+        //should work like String#lastIndexOf
+        assertEquals ("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
+        
+        assertEquals(3, sb.lastIndexOf('b'));
+        assertEquals ("abab".lastIndexOf('b'), sb.lastIndexOf('b'));
+        
+        assertEquals (-1, sb.lastIndexOf('z'));
+    }
+
+    @Test
+    public void testLastIndexOf_char_int() {
+        StrBuilder sb = new StrBuilder("abab");
+        assertEquals(-1, sb.lastIndexOf('a', -1));
+        assertEquals(0, sb.lastIndexOf('a', 0));
+        assertEquals(0, sb.lastIndexOf('a', 1));
+
+        // should work like String#lastIndexOf
+        assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1));
+
+        assertEquals(1, sb.lastIndexOf('b', 2));
+        assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2));
+
+        assertEquals(-1, sb.lastIndexOf('z', 2));
+
+        sb = new StrBuilder("xyzabc");
+        assertEquals(2, sb.lastIndexOf('z', sb.length()));
+        assertEquals(-1, sb.lastIndexOf('z', 1));
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testIndexOf_String() {
+        final StrBuilder sb = new StrBuilder("abab");
+        
+        assertEquals(0, sb.indexOf("a"));
+        //should work like String#indexOf
+        assertEquals("abab".indexOf("a"), sb.indexOf("a"));
+        
+        assertEquals(0, sb.indexOf("ab"));
+        //should work like String#indexOf
+        assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
+        
+        assertEquals(1, sb.indexOf("b"));
+        assertEquals("abab".indexOf("b"), sb.indexOf("b"));
+        
+        assertEquals(1, sb.indexOf("ba"));
+        assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
+        
+        assertEquals(-1, sb.indexOf("z"));
+        
+        assertEquals(-1, sb.indexOf((String) null));
+    }
+
+    @Test
+    public void testIndexOf_String_int() {
+        StrBuilder sb = new StrBuilder("abab");
+        assertEquals(0, sb.indexOf("a", -1));
+        assertEquals(0, sb.indexOf("a", 0));
+        assertEquals(2, sb.indexOf("a", 1));
+        assertEquals(2, sb.indexOf("a", 2));
+        assertEquals(-1, sb.indexOf("a", 3));
+        assertEquals(-1, sb.indexOf("a", 4));
+        assertEquals(-1, sb.indexOf("a", 5));
+        
+        assertEquals(-1, sb.indexOf("abcdef", 0));
+        assertEquals(0, sb.indexOf("", 0));
+        assertEquals(1, sb.indexOf("", 1));
+        
+        //should work like String#indexOf
+        assertEquals ("abab".indexOf("a", 1), sb.indexOf("a", 1));
+        
+        assertEquals(2, sb.indexOf("ab", 1));
+        //should work like String#indexOf
+        assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
+        
+        assertEquals(3, sb.indexOf("b", 2));
+        assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
+        
+        assertEquals(1, sb.indexOf("ba", 1));
+        assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
+        
+        assertEquals(-1, sb.indexOf("z", 2));
+        
+        sb = new StrBuilder("xyzabc");
+        assertEquals(2, sb.indexOf("za", 0));
+        assertEquals(-1, sb.indexOf("za", 3));
+        
+        assertEquals(-1, sb.indexOf((String) null, 2));
+    }
+
+    @Test
+    public void testLastIndexOf_String() {
+        final StrBuilder sb = new StrBuilder("abab");
+        
+        assertEquals(2, sb.lastIndexOf("a"));
+        //should work like String#lastIndexOf
+        assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a"));
+        
+        assertEquals(2, sb.lastIndexOf("ab"));
+        //should work like String#lastIndexOf
+        assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab"));
+        
+        assertEquals(3, sb.lastIndexOf("b"));
+        assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b"));
+        
+        assertEquals(1, sb.lastIndexOf("ba"));
+        assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba"));
+        
+        assertEquals(-1, sb.lastIndexOf("z"));
+        
+        assertEquals(-1, sb.lastIndexOf((String) null));
+    }
+
+    @Test
+    public void testLastIndexOf_String_int() {
+        StrBuilder sb = new StrBuilder("abab");
+        assertEquals(-1, sb.lastIndexOf("a", -1));
+        assertEquals(0, sb.lastIndexOf("a", 0));
+        assertEquals(0, sb.lastIndexOf("a", 1));
+        assertEquals(2, sb.lastIndexOf("a", 2));
+        assertEquals(2, sb.lastIndexOf("a", 3));
+        assertEquals(2, sb.lastIndexOf("a", 4));
+        assertEquals(2, sb.lastIndexOf("a", 5));
+        
+        assertEquals(-1, sb.lastIndexOf("abcdef", 3));
+        assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3));
+        assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1));
+        
+        //should work like String#lastIndexOf
+        assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1));
+        
+        assertEquals(0, sb.lastIndexOf("ab", 1));
+        //should work like String#lastIndexOf
+        assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1));
+        
+        assertEquals(1, sb.lastIndexOf("b", 2));
+        assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2));
+        
+        assertEquals(1, sb.lastIndexOf("ba", 2));
+        assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2));
+        
+        assertEquals(-1, sb.lastIndexOf("z", 2));
+        
+        sb = new StrBuilder("xyzabc");
+        assertEquals(2, sb.lastIndexOf("za", sb.length()));
+        assertEquals(-1, sb.lastIndexOf("za", 1));
+        
+        assertEquals(-1, sb.lastIndexOf((String) null, 2));
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testIndexOf_StrMatcher() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(-1, sb.indexOf((StrMatcher) null));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a')));
+        
+        sb.append("ab bd");
+        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a')));
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b')));
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher()));
+        assertEquals(4, sb.indexOf(StrMatcher.charMatcher('d')));
+        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher()));
+        assertEquals(-1, sb.indexOf((StrMatcher) null));
+        
+        sb.append(" A1 junction");
+        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
+    }
+
+    @Test
+    public void testIndexOf_StrMatcher_int() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(-1, sb.indexOf((StrMatcher) null, 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 0));
+        
+        sb.append("ab bd");
+        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), -2));
+        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 20));
+        
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), -1));
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 0));
+        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 1));
+        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 2));
+        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 3));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 4));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 5));
+        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 6));
+        
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), -2));
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 0));
+        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 2));
+        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 4));
+        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 20));
+        
+        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher(), 0));
+        assertEquals(-1, sb.indexOf((StrMatcher) null, 0));
+        
+        sb.append(" A1 junction with A2");
+        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
+        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
+        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
+        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
+        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
+        assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
+    }
+
+    @Test
+    public void testLastIndexOf_StrMatcher() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a')));
+        
+        sb.append("ab bd");
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a')));
+        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b')));
+        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher()));
+        assertEquals(4, sb.lastIndexOf(StrMatcher.charMatcher('d')));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher()));
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
+        
+        sb.append(" A1 junction");
+        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
+    }
+
+    @Test
+    public void testLastIndexOf_StrMatcher_int() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 2));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -1));
+        
+        sb.append("ab bd");
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -2));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
+        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 20));
+        
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), -1));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 0));
+        assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 1));
+        assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 2));
+        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 3));
+        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 4));
+        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 5));
+        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 6));
+        
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), -2));
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), 0));
+        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 2));
+        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 4));
+        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 20));
+        
+        assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher(), 0));
+        assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 0));
+        
+        sb.append(" A1 junction with A2");
+        assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5));
+        assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1 is outside bounds
+        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7));
+        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22));
+        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2 is outside bounds
+        assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24));
+    }
+
+    static final StrMatcher A_NUMBER_MATCHER = new StrMatcher() {
+        @Override
+        public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
+            if (buffer[pos] == 'A') {
+                pos++;
+                if (pos < bufferEnd && buffer[pos] >= '0' && buffer[pos] <= '9') {
+                    return 2;
+                }
+            }
+            return 0;
+        }
+    };
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAsTokenizer() throws Exception {
+        // from Javadoc
+        final StrBuilder b = new StrBuilder();
+        b.append("a b ");
+        final StrTokenizer t = b.asTokenizer();
+        
+        final String[] tokens1 = t.getTokenArray();
+        assertEquals(2, tokens1.length);
+        assertEquals("a", tokens1[0]);
+        assertEquals("b", tokens1[1]);
+        assertEquals(2, t.size());
+        
+        b.append("c d ");
+        final String[] tokens2 = t.getTokenArray();
+        assertEquals(2, tokens2.length);
+        assertEquals("a", tokens2[0]);
+        assertEquals("b", tokens2[1]);
+        assertEquals(2, t.size());
+        assertEquals("a", t.next());
+        assertEquals("b", t.next());
+        
+        t.reset();
+        final String[] tokens3 = t.getTokenArray();
+        assertEquals(4, tokens3.length);
+        assertEquals("a", tokens3[0]);
+        assertEquals("b", tokens3[1]);
+        assertEquals("c", tokens3[2]);
+        assertEquals("d", tokens3[3]);
+        assertEquals(4, t.size());
+        assertEquals("a", t.next());
+        assertEquals("b", t.next());
+        assertEquals("c", t.next());
+        assertEquals("d", t.next());
+        
+        assertEquals("a b c d ", t.getContent());
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void testAsReader() throws Exception {
+        final StrBuilder sb = new StrBuilder("some text");
+        Reader reader = sb.asReader();
+        assertTrue(reader.ready());
+        final char[] buf = new char[40];
+        assertEquals(9, reader.read(buf));
+        assertEquals("some text", new String(buf, 0, 9));
+        
+        assertEquals(-1, reader.read());
+        assertFalse(reader.ready());
+        assertEquals(0, reader.skip(2));
+        assertEquals(0, reader.skip(-1));
+        
+        assertTrue(reader.markSupported());
+        reader = sb.asReader();
+        assertEquals('s', reader.read());
+        reader.mark(-1);
+        char[] array = new char[3];
+        assertEquals(3, reader.read(array, 0, 3));
+        assertEquals('o', array[0]);
+        assertEquals('m', array[1]);
+        assertEquals('e', array[2]);
+        reader.reset();
+        assertEquals(1, reader.read(array, 1, 1));
+        assertEquals('o', array[0]);
+        assertEquals('o', array[1]);
+        assertEquals('e', array[2]);
+        assertEquals(2, reader.skip(2));
+        assertEquals(' ', reader.read());
+        
+        assertTrue(reader.ready());
+        reader.close();
+        assertTrue(reader.ready());
+        
+        reader = sb.asReader();
+        array = new char[3];
+        try {
+            reader.read(array, -1, 0);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        try {
+            reader.read(array, 0, -1);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        try {
+            reader.read(array, 100, 1);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        try {
+            reader.read(array, 0, 100);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        try {
+            reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE);
+            fail();
+        } catch (final IndexOutOfBoundsException ex) {}
+        
+        assertEquals(0, reader.read(array, 0, 0));
+        assertEquals(0, array[0]);
+        assertEquals(0, array[1]);
+        assertEquals(0, array[2]);
+        
+        reader.skip(9);
+        assertEquals(-1, reader.read(array, 0, 1));
+        
+        reader.reset();
+        array = new char[30];
+        assertEquals(9, reader.read(array, 0, 30));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAsWriter() throws Exception {
+        final StrBuilder sb = new StrBuilder("base");
+        final Writer writer = sb.asWriter();
+        
+        writer.write('l');
+        assertEquals("basel", sb.toString());
+        
+        writer.write(new char[] {'i', 'n'});
+        assertEquals("baselin", sb.toString());
+        
+        writer.write(new char[] {'n', 'e', 'r'}, 1, 2);
+        assertEquals("baseliner", sb.toString());
+        
+        writer.write(" rout");
+        assertEquals("baseliner rout", sb.toString());
+        
+        writer.write("ping that server", 1, 3);
+        assertEquals("baseliner routing", sb.toString());
+        
+        writer.flush();  // no effect
+        assertEquals("baseliner routing", sb.toString());
+        
+        writer.close();  // no effect
+        assertEquals("baseliner routing", sb.toString());
+        
+        writer.write(" hi");  // works after close
+        assertEquals("baseliner routing hi", sb.toString());
+        
+        sb.setLength(4);  // mix and match
+        writer.write('d');
+        assertEquals("based", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testEqualsIgnoreCase() {
+        final StrBuilder sb1 = new StrBuilder();
+        final StrBuilder sb2 = new StrBuilder();
+        assertTrue(sb1.equalsIgnoreCase(sb1));
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+        assertTrue(sb2.equalsIgnoreCase(sb2));
+        
+        sb1.append("abc");
+        assertFalse(sb1.equalsIgnoreCase(sb2));
+        
+        sb2.append("ABC");
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+        
+        sb2.clear().append("abc");
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+        assertTrue(sb1.equalsIgnoreCase(sb1));
+        assertTrue(sb2.equalsIgnoreCase(sb2));
+        
+        sb2.clear().append("aBc");
+        assertTrue(sb1.equalsIgnoreCase(sb2));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testEquals() {
+        final StrBuilder sb1 = new StrBuilder();
+        final StrBuilder sb2 = new StrBuilder();
+        assertTrue(sb1.equals(sb2));
+        assertTrue(sb1.equals(sb1));
+        assertTrue(sb2.equals(sb2));
+        assertTrue(sb1.equals((Object) sb2));
+        
+        sb1.append("abc");
+        assertFalse(sb1.equals(sb2));
+        assertFalse(sb1.equals((Object) sb2));
+        
+        sb2.append("ABC");
+        assertFalse(sb1.equals(sb2));
+        assertFalse(sb1.equals((Object) sb2));
+        
+        sb2.clear().append("abc");
+        assertTrue(sb1.equals(sb2));
+        assertTrue(sb1.equals((Object) sb2));
+        
+        assertFalse(sb1.equals(Integer.valueOf(1)));
+        assertFalse(sb1.equals("abc"));
+    }
+
+    @Test
+    public void test_LANG_1131_EqualsWithNullStrBuilder() throws Exception {
+        final StrBuilder sb = new StrBuilder();
+        final StrBuilder other = null;
+        assertFalse(sb.equals(other));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testHashCode() {
+        final StrBuilder sb = new StrBuilder();
+        final int hc1a = sb.hashCode();
+        final int hc1b = sb.hashCode();
+        assertEquals(0, hc1a);
+        assertEquals(hc1a, hc1b);
+        
+        sb.append("abc");
+        final int hc2a = sb.hashCode();
+        final int hc2b = sb.hashCode();
+        assertTrue(hc2a != 0);
+        assertEquals(hc2a, hc2b);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testToString() {
+        final StrBuilder sb = new StrBuilder("abc");
+        assertEquals("abc", sb.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testToStringBuffer() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
+        
+        sb.append("junit");
+        assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testToStringBuilder() {
+        final StrBuilder sb = new StrBuilder();
+        assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString());
+        
+        sb.append("junit");
+        assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testLang294() {
+        final StrBuilder sb = new StrBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
+        sb.deleteAll("\n%BLAH%");
+        assertEquals("\nDo more stuff\neven more stuff\n", sb.toString()); 
+    }
+
+    @Test
+    public void testIndexOfLang294() {
+        final StrBuilder sb = new StrBuilder("onetwothree");
+        sb.deleteFirst("three");
+        assertEquals(-1, sb.indexOf("three"));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testLang295() {
+        final StrBuilder sb = new StrBuilder("onetwothree");
+        sb.deleteFirst("three");
+        assertFalse( "The contains(char) method is looking beyond the end of the string", sb.contains('h'));
+        assertEquals( "The indexOf(char) method is looking beyond the end of the string", -1, sb.indexOf('h'));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testLang412Right() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadRight(null, 10, '*');
+        assertEquals( "Failed to invoke appendFixedWidthPadRight correctly", "**********", sb.toString());
+    }
+
+    @Test
+    public void testLang412Left() {
+        final StrBuilder sb = new StrBuilder();
+        sb.appendFixedWidthPadLeft(null, 10, '*');
+        assertEquals( "Failed to invoke appendFixedWidthPadLeft correctly", "**********", sb.toString());
+    }
+
+    @Test
+    public void testAsBuilder() {
+        final StrBuilder sb = new StrBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
+        assertEquals(sb.toString(), sb.build());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendCharBuffer() {
+        final StrBuilder sb1 = new StrBuilder();
+        final CharBuffer buf = CharBuffer.allocate(10);
+        buf.append("0123456789");
+        buf.flip();
+        sb1.append(buf);
+        assertEquals("0123456789", sb1.toString());
+
+        final StrBuilder sb2 = new StrBuilder();
+        sb2.append(buf, 1, 8);
+        assertEquals("12345678", sb2.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testAppendToWriter() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final StringWriter writer = new StringWriter();
+        writer.append("Test ");
+
+        sb.appendTo(writer);
+
+        assertEquals("Test 1234567890", writer.toString());
+    }
+
+    @Test
+    public void testAppendToStringBuilder() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final StringBuilder builder = new StringBuilder("Test ");
+
+        sb.appendTo(builder);
+
+        assertEquals("Test 1234567890", builder.toString());
+    }
+
+    @Test
+    public void testAppendToStringBuffer() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final StringBuffer buffer = new StringBuffer("Test ");
+
+        sb.appendTo(buffer);
+
+        assertEquals("Test 1234567890", buffer.toString());
+    }
+
+    @Test
+    public void testAppendToCharBuffer() throws Exception {
+        final StrBuilder sb = new StrBuilder("1234567890");
+        final String text = "Test ";
+        final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
+        buffer.put(text);
+
+        sb.appendTo(buffer);
+
+        buffer.flip();
+        assertEquals("Test 1234567890", buffer.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StrLookupTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrLookupTest.java b/src/test/java/org/apache/commons/text/StrLookupTest.java
new file mode 100644
index 0000000..dfd8933
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrLookupTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.junit.Test;
+
+/**
+ * Test class for {@link StrLookup}.
+ */
+public class StrLookupTest  {
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testNoneLookup() {
+        assertEquals(null, StrLookup.noneLookup().lookup(null));
+        assertEquals(null, StrLookup.noneLookup().lookup(""));
+        assertEquals(null, StrLookup.noneLookup().lookup("any"));
+    }
+
+    @Test
+    public void testSystemProperiesLookup() {
+        assertEquals(System.getProperty("os.name"), StrLookup.systemPropertiesLookup().lookup("os.name"));
+        assertEquals(null, StrLookup.systemPropertiesLookup().lookup(""));
+        assertEquals(null, StrLookup.systemPropertiesLookup().lookup("other"));
+        try {
+            StrLookup.systemPropertiesLookup().lookup(null);
+            fail();
+        } catch (final NullPointerException ex) {
+            // expected
+        }
+    }
+
+    /**
+     * Tests that a lookup object for system properties can deal with a full
+     * replacement of the system properties object. This test is related to
+     * LANG-1055.
+     */
+    @Test
+    public void testSystemPropertiesLookupReplacedProperties() {
+        final Properties oldProperties = System.getProperties();
+        final String osName = "os.name";
+        final String newOsName = oldProperties.getProperty(osName) + "_changed";
+
+        final StrLookup<String> sysLookup = StrLookup.systemPropertiesLookup();
+        final Properties newProps = new Properties();
+        newProps.setProperty(osName, newOsName);
+        System.setProperties(newProps);
+        try {
+            assertEquals("Changed properties not detected", newOsName, sysLookup.lookup(osName));
+        } finally {
+            System.setProperties(oldProperties);
+        }
+    }
+
+    /**
+     * Tests that a lookup object for system properties sees changes on system
+     * properties. This test is related to LANG-1141.
+     */
+    @Test
+    public void testSystemPropertiesLookupUpdatedProperty() {
+        final String osName = "os.name";
+        final String oldOs = System.getProperty(osName);
+        final String newOsName = oldOs + "_changed";
+
+        final StrLookup<String> sysLookup = StrLookup.systemPropertiesLookup();
+        System.setProperty(osName, newOsName);
+        try {
+            assertEquals("Changed properties not detected", newOsName, sysLookup.lookup(osName));
+        } finally {
+            System.setProperty(osName, oldOs);
+        }
+    }
+
+    @Test
+    public void testMapLookup() {
+        final Map<String, Object> map = new HashMap<>();
+        map.put("key", "value");
+        map.put("number", Integer.valueOf(2));
+        assertEquals("value", StrLookup.mapLookup(map).lookup("key"));
+        assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
+        assertEquals(null, StrLookup.mapLookup(map).lookup(null));
+        assertEquals(null, StrLookup.mapLookup(map).lookup(""));
+        assertEquals(null, StrLookup.mapLookup(map).lookup("other"));
+    }
+
+    @Test
+    public void testMapLookup_nullMap() {
+        final Map<String, ?> map = null;
+        assertEquals(null, StrLookup.mapLookup(map).lookup(null));
+        assertEquals(null, StrLookup.mapLookup(map).lookup(""));
+        assertEquals(null, StrLookup.mapLookup(map).lookup("any"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StrMatcherTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrMatcherTest.java b/src/test/java/org/apache/commons/text/StrMatcherTest.java
new file mode 100644
index 0000000..2b365e0
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrMatcherTest.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link StrMatcher}.
+ */
+public class StrMatcherTest  {
+
+    private static final char[] BUFFER1 = "0,1\t2 3\n\r\f\u0000'\"".toCharArray();
+
+    private static final char[] BUFFER2 = "abcdef".toCharArray();
+
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCommaMatcher() {
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        assertSame(matcher, StrMatcher.commaMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 0));
+        assertEquals(1, matcher.isMatch(BUFFER1, 1));
+        assertEquals(0, matcher.isMatch(BUFFER1, 2));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTabMatcher() {
+        final StrMatcher matcher = StrMatcher.tabMatcher();
+        assertSame(matcher, StrMatcher.tabMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 2));
+        assertEquals(1, matcher.isMatch(BUFFER1, 3));
+        assertEquals(0, matcher.isMatch(BUFFER1, 4));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSpaceMatcher() {
+        final StrMatcher matcher = StrMatcher.spaceMatcher();
+        assertSame(matcher, StrMatcher.spaceMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 4));
+        assertEquals(1, matcher.isMatch(BUFFER1, 5));
+        assertEquals(0, matcher.isMatch(BUFFER1, 6));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSplitMatcher() {
+        final StrMatcher matcher = StrMatcher.splitMatcher();
+        assertSame(matcher, StrMatcher.splitMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 2));
+        assertEquals(1, matcher.isMatch(BUFFER1, 3));
+        assertEquals(0, matcher.isMatch(BUFFER1, 4));
+        assertEquals(1, matcher.isMatch(BUFFER1, 5));
+        assertEquals(0, matcher.isMatch(BUFFER1, 6));
+        assertEquals(1, matcher.isMatch(BUFFER1, 7));
+        assertEquals(1, matcher.isMatch(BUFFER1, 8));
+        assertEquals(1, matcher.isMatch(BUFFER1, 9));
+        assertEquals(0, matcher.isMatch(BUFFER1, 10));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTrimMatcher() {
+        final StrMatcher matcher = StrMatcher.trimMatcher();
+        assertSame(matcher, StrMatcher.trimMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 2));
+        assertEquals(1, matcher.isMatch(BUFFER1, 3));
+        assertEquals(0, matcher.isMatch(BUFFER1, 4));
+        assertEquals(1, matcher.isMatch(BUFFER1, 5));
+        assertEquals(0, matcher.isMatch(BUFFER1, 6));
+        assertEquals(1, matcher.isMatch(BUFFER1, 7));
+        assertEquals(1, matcher.isMatch(BUFFER1, 8));
+        assertEquals(1, matcher.isMatch(BUFFER1, 9));
+        assertEquals(1, matcher.isMatch(BUFFER1, 10));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testSingleQuoteMatcher() {
+        final StrMatcher matcher = StrMatcher.singleQuoteMatcher();
+        assertSame(matcher, StrMatcher.singleQuoteMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 10));
+        assertEquals(1, matcher.isMatch(BUFFER1, 11));
+        assertEquals(0, matcher.isMatch(BUFFER1, 12));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testDoubleQuoteMatcher() {
+        final StrMatcher matcher = StrMatcher.doubleQuoteMatcher();
+        assertSame(matcher, StrMatcher.doubleQuoteMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 11));
+        assertEquals(1, matcher.isMatch(BUFFER1, 12));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testQuoteMatcher() {
+        final StrMatcher matcher = StrMatcher.quoteMatcher();
+        assertSame(matcher, StrMatcher.quoteMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 10));
+        assertEquals(1, matcher.isMatch(BUFFER1, 11));
+        assertEquals(1, matcher.isMatch(BUFFER1, 12));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testNoneMatcher() {
+        final StrMatcher matcher = StrMatcher.noneMatcher();
+        assertSame(matcher, StrMatcher.noneMatcher());
+        assertEquals(0, matcher.isMatch(BUFFER1, 0));
+        assertEquals(0, matcher.isMatch(BUFFER1, 1));
+        assertEquals(0, matcher.isMatch(BUFFER1, 2));
+        assertEquals(0, matcher.isMatch(BUFFER1, 3));
+        assertEquals(0, matcher.isMatch(BUFFER1, 4));
+        assertEquals(0, matcher.isMatch(BUFFER1, 5));
+        assertEquals(0, matcher.isMatch(BUFFER1, 6));
+        assertEquals(0, matcher.isMatch(BUFFER1, 7));
+        assertEquals(0, matcher.isMatch(BUFFER1, 8));
+        assertEquals(0, matcher.isMatch(BUFFER1, 9));
+        assertEquals(0, matcher.isMatch(BUFFER1, 10));
+        assertEquals(0, matcher.isMatch(BUFFER1, 11));
+        assertEquals(0, matcher.isMatch(BUFFER1, 12));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCharMatcher_char() {
+        final StrMatcher matcher = StrMatcher.charMatcher('c');
+        assertEquals(0, matcher.isMatch(BUFFER2, 0));
+        assertEquals(0, matcher.isMatch(BUFFER2, 1));
+        assertEquals(1, matcher.isMatch(BUFFER2, 2));
+        assertEquals(0, matcher.isMatch(BUFFER2, 3));
+        assertEquals(0, matcher.isMatch(BUFFER2, 4));
+        assertEquals(0, matcher.isMatch(BUFFER2, 5));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCharSetMatcher_String() {
+        final StrMatcher matcher = StrMatcher.charSetMatcher("ace");
+        assertEquals(1, matcher.isMatch(BUFFER2, 0));
+        assertEquals(0, matcher.isMatch(BUFFER2, 1));
+        assertEquals(1, matcher.isMatch(BUFFER2, 2));
+        assertEquals(0, matcher.isMatch(BUFFER2, 3));
+        assertEquals(1, matcher.isMatch(BUFFER2, 4));
+        assertEquals(0, matcher.isMatch(BUFFER2, 5));
+        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher(""));
+        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher((String) null));
+        assertTrue(StrMatcher.charSetMatcher("a") instanceof StrMatcher.CharMatcher);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testCharSetMatcher_charArray() {
+        final StrMatcher matcher = StrMatcher.charSetMatcher("ace".toCharArray());
+        assertEquals(1, matcher.isMatch(BUFFER2, 0));
+        assertEquals(0, matcher.isMatch(BUFFER2, 1));
+        assertEquals(1, matcher.isMatch(BUFFER2, 2));
+        assertEquals(0, matcher.isMatch(BUFFER2, 3));
+        assertEquals(1, matcher.isMatch(BUFFER2, 4));
+        assertEquals(0, matcher.isMatch(BUFFER2, 5));
+        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher(new char[0]));
+        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher((char[]) null));
+        assertTrue(StrMatcher.charSetMatcher("a".toCharArray()) instanceof StrMatcher.CharMatcher);
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testStringMatcher_String() {
+        final StrMatcher matcher = StrMatcher.stringMatcher("bc");
+        assertEquals(0, matcher.isMatch(BUFFER2, 0));
+        assertEquals(2, matcher.isMatch(BUFFER2, 1));
+        assertEquals(0, matcher.isMatch(BUFFER2, 2));
+        assertEquals(0, matcher.isMatch(BUFFER2, 3));
+        assertEquals(0, matcher.isMatch(BUFFER2, 4));
+        assertEquals(0, matcher.isMatch(BUFFER2, 5));
+        assertSame(StrMatcher.noneMatcher(), StrMatcher.stringMatcher(""));
+        assertSame(StrMatcher.noneMatcher(), StrMatcher.stringMatcher((String) null));
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testMatcherIndices() {
+        // remember that the API contract is tight for the isMatch() method
+        // all the onus is on the caller, so invalid inputs are not
+        // the concern of StrMatcher, and are not bugs
+        final StrMatcher matcher = StrMatcher.stringMatcher("bc");
+        assertEquals(2, matcher.isMatch(BUFFER2, 1, 1, BUFFER2.length));
+        assertEquals(2, matcher.isMatch(BUFFER2, 1, 0, 3));
+        assertEquals(0, matcher.isMatch(BUFFER2, 1, 0, 2));
+    }
+
+}


[22/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/StrTokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StrTokenizer.java b/src/main/java/org/apache/commons/text/beta/StrTokenizer.java
deleted file mode 100644
index 87e09ba..0000000
--- a/src/main/java/org/apache/commons/text/beta/StrTokenizer.java
+++ /dev/null
@@ -1,1118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.NoSuchElementException;
-
-/**
- * Tokenizes a string based based on delimiters (separators)
- * and supporting quoting and ignored character concepts.
- * <p>
- * This class can split a String into many smaller strings. It aims
- * to do a similar job to {@link java.util.StringTokenizer StringTokenizer},
- * however it offers much more control and flexibility including implementing
- * the <code>ListIterator</code> interface. By default, it is set up
- * like <code>StringTokenizer</code>.
- * <p>
- * The input String is split into a number of <i>tokens</i>.
- * Each token is separated from the next String by a <i>delimiter</i>.
- * One or more delimiter characters must be specified.
- * <p>
- * Each token may be surrounded by quotes.
- * The <i>quote</i> matcher specifies the quote character(s).
- * A quote may be escaped within a quoted section by duplicating itself.
- * <p>
- * Between each token and the delimiter are potentially characters that need trimming.
- * The <i>trimmer</i> matcher specifies these characters.
- * One usage might be to trim whitespace characters.
- * <p>
- * At any point outside the quotes there might potentially be invalid characters.
- * The <i>ignored</i> matcher specifies these characters to be removed.
- * One usage might be to remove new line characters.
- * <p>
- * Empty tokens may be removed or returned as null.
- * <pre>
- * "a,b,c"         - Three tokens "a","b","c"   (comma delimiter)
- * " a, b , c "    - Three tokens "a","b","c"   (default CSV processing trims whitespace)
- * "a, ", b ,", c" - Three tokens "a, " , " b ", ", c" (quoted text untouched)
- * </pre>
- * <p>
- *
- * This tokenizer has the following properties and options:
- *
- * <table summary="Tokenizer Properties">
- *  <tr>
- *   <th>Property</th><th>Type</th><th>Default</th>
- *  </tr>
- *  <tr>
- *   <td>delim</td><td>CharSetMatcher</td><td>{ \t\n\r\f}</td>
- *  </tr>
- *  <tr>
- *   <td>quote</td><td>NoneMatcher</td><td>{}</td>
- *  </tr>
- *  <tr>
- *   <td>ignore</td><td>NoneMatcher</td><td>{}</td>
- *  </tr>
- *  <tr>
- *   <td>emptyTokenAsNull</td><td>boolean</td><td>false</td>
- *  </tr>
- *  <tr>
- *   <td>ignoreEmptyTokens</td><td>boolean</td><td>true</td>
- *  </tr>
- * </table>
- *
- * @since 1.0
- */
-public class StrTokenizer implements ListIterator<String>, Cloneable {
-
-    private static final StrTokenizer CSV_TOKENIZER_PROTOTYPE;
-    private static final StrTokenizer TSV_TOKENIZER_PROTOTYPE;
-    static {
-        CSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
-        CSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.commaMatcher());
-        CSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
-        CSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
-        CSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
-        CSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
-        CSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
-
-        TSV_TOKENIZER_PROTOTYPE = new StrTokenizer();
-        TSV_TOKENIZER_PROTOTYPE.setDelimiterMatcher(StrMatcher.tabMatcher());
-        TSV_TOKENIZER_PROTOTYPE.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
-        TSV_TOKENIZER_PROTOTYPE.setIgnoredMatcher(StrMatcher.noneMatcher());
-        TSV_TOKENIZER_PROTOTYPE.setTrimmerMatcher(StrMatcher.trimMatcher());
-        TSV_TOKENIZER_PROTOTYPE.setEmptyTokenAsNull(false);
-        TSV_TOKENIZER_PROTOTYPE.setIgnoreEmptyTokens(false);
-    }
-
-    /** The text to work on. */
-    private char chars[];
-    /** The parsed tokens */
-    private String tokens[];
-    /** The current iteration position */
-    private int tokenPos;
-
-    /** The delimiter matcher */
-    private StrMatcher delimMatcher = StrMatcher.splitMatcher();
-    /** The quote matcher */
-    private StrMatcher quoteMatcher = StrMatcher.noneMatcher();
-    /** The ignored matcher */
-    private StrMatcher ignoredMatcher = StrMatcher.noneMatcher();
-    /** The trimmer matcher */
-    private StrMatcher trimmerMatcher = StrMatcher.noneMatcher();
-
-    /** Whether to return empty tokens as null */
-    private boolean emptyAsNull = false;
-    /** Whether to ignore empty tokens */
-    private boolean ignoreEmptyTokens = true;
-
-    //-----------------------------------------------------------------------
-
-    /**
-     * Returns a clone of <code>CSV_TOKENIZER_PROTOTYPE</code>.
-     *
-     * @return a clone of <code>CSV_TOKENIZER_PROTOTYPE</code>.
-     */
-    private static StrTokenizer getCSVClone() {
-        return (StrTokenizer) CSV_TOKENIZER_PROTOTYPE.clone();
-    }
-
-    /**
-     * Gets a new tokenizer instance which parses Comma Separated Value strings
-     * initializing it with the given input.  The default for CSV processing
-     * will be trim whitespace from both ends (which can be overridden with
-     * the setTrimmer method).
-     * <p>
-     * You must call a "reset" method to set the string which you want to parse.
-     * @return a new tokenizer instance which parses Comma Separated Value strings
-     */
-    public static StrTokenizer getCSVInstance() {
-        return getCSVClone();
-    }
-
-    /**
-     * Gets a new tokenizer instance which parses Comma Separated Value strings
-     * initializing it with the given input.  The default for CSV processing
-     * will be trim whitespace from both ends (which can be overridden with
-     * the setTrimmer method).
-     *
-     * @param input  the text to parse
-     * @return a new tokenizer instance which parses Comma Separated Value strings
-     */
-    public static StrTokenizer getCSVInstance(final String input) {
-        final StrTokenizer tok = getCSVClone();
-        tok.reset(input);
-        return tok;
-    }
-
-    /**
-     * Gets a new tokenizer instance which parses Comma Separated Value strings
-     * initializing it with the given input.  The default for CSV processing
-     * will be trim whitespace from both ends (which can be overridden with
-     * the setTrimmer method).
-     *
-     * @param input  the text to parse
-     * @return a new tokenizer instance which parses Comma Separated Value strings
-     */
-    public static StrTokenizer getCSVInstance(final char[] input) {
-        final StrTokenizer tok = getCSVClone();
-        tok.reset(input);
-        return tok;
-    }
-
-    /**
-     * Returns a clone of <code>TSV_TOKENIZER_PROTOTYPE</code>.
-     *
-     * @return a clone of <code>TSV_TOKENIZER_PROTOTYPE</code>.
-     */
-    private static StrTokenizer getTSVClone() {
-        return (StrTokenizer) TSV_TOKENIZER_PROTOTYPE.clone();
-    }
-
-
-    /**
-     * Gets a new tokenizer instance which parses Tab Separated Value strings.
-     * The default for CSV processing will be trim whitespace from both ends
-     * (which can be overridden with the setTrimmer method).
-     * <p>
-     * You must call a "reset" method to set the string which you want to parse.
-     * @return a new tokenizer instance which parses Tab Separated Value strings.
-     */
-    public static StrTokenizer getTSVInstance() {
-        return getTSVClone();
-    }
-
-    /**
-     * Gets a new tokenizer instance which parses Tab Separated Value strings.
-     * The default for CSV processing will be trim whitespace from both ends
-     * (which can be overridden with the setTrimmer method).
-     * @param input  the string to parse
-     * @return a new tokenizer instance which parses Tab Separated Value strings.
-     */
-    public static StrTokenizer getTSVInstance(final String input) {
-        final StrTokenizer tok = getTSVClone();
-        tok.reset(input);
-        return tok;
-    }
-
-    /**
-     * Gets a new tokenizer instance which parses Tab Separated Value strings.
-     * The default for CSV processing will be trim whitespace from both ends
-     * (which can be overridden with the setTrimmer method).
-     * @param input  the string to parse
-     * @return a new tokenizer instance which parses Tab Separated Value strings.
-     */
-    public static StrTokenizer getTSVInstance(final char[] input) {
-        final StrTokenizer tok = getTSVClone();
-        tok.reset(input);
-        return tok;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Constructs a tokenizer splitting on space, tab, newline and formfeed
-     * as per StringTokenizer, but with no text to tokenize.
-     * <p>
-     * This constructor is normally used with {@link #reset(String)}.
-     */
-    public StrTokenizer() {
-        super();
-        this.chars = null;
-    }
-
-    /**
-     * Constructs a tokenizer splitting on space, tab, newline and formfeed
-     * as per StringTokenizer.
-     *
-     * @param input  the string which is to be parsed
-     */
-    public StrTokenizer(final String input) {
-        super();
-        if (input != null) {
-            chars = input.toCharArray();
-        } else {
-            chars = null;
-        }
-    }
-
-    /**
-     * Constructs a tokenizer splitting on the specified delimiter character.
-     *
-     * @param input  the string which is to be parsed
-     * @param delim  the field delimiter character
-     */
-    public StrTokenizer(final String input, final char delim) {
-        this(input);
-        setDelimiterChar(delim);
-    }
-
-    /**
-     * Constructs a tokenizer splitting on the specified delimiter string.
-     *
-     * @param input  the string which is to be parsed
-     * @param delim  the field delimiter string
-     */
-    public StrTokenizer(final String input, final String delim) {
-        this(input);
-        setDelimiterString(delim);
-    }
-
-    /**
-     * Constructs a tokenizer splitting using the specified delimiter matcher.
-     *
-     * @param input  the string which is to be parsed
-     * @param delim  the field delimiter matcher
-     */
-    public StrTokenizer(final String input, final StrMatcher delim) {
-        this(input);
-        setDelimiterMatcher(delim);
-    }
-
-    /**
-     * Constructs a tokenizer splitting on the specified delimiter character
-     * and handling quotes using the specified quote character.
-     *
-     * @param input  the string which is to be parsed
-     * @param delim  the field delimiter character
-     * @param quote  the field quoted string character
-     */
-    public StrTokenizer(final String input, final char delim, final char quote) {
-        this(input, delim);
-        setQuoteChar(quote);
-    }
-
-    /**
-     * Constructs a tokenizer splitting using the specified delimiter matcher
-     * and handling quotes using the specified quote matcher.
-     *
-     * @param input  the string which is to be parsed
-     * @param delim  the field delimiter matcher
-     * @param quote  the field quoted string matcher
-     */
-    public StrTokenizer(final String input, final StrMatcher delim, final StrMatcher quote) {
-        this(input, delim);
-        setQuoteMatcher(quote);
-    }
-
-    /**
-     * Constructs a tokenizer splitting on space, tab, newline and formfeed
-     * as per StringTokenizer.
-     *
-     * @param input  the string which is to be parsed, not cloned
-     */
-    public StrTokenizer(final char[] input) {
-        super();
-        if (input == null) {
-            this.chars = null;
-        } else {
-            this.chars = input.clone();
-        }
-    }
-
-    /**
-     * Constructs a tokenizer splitting on the specified character.
-     *
-     * @param input  the string which is to be parsed, not cloned
-     * @param delim the field delimiter character
-     */
-    public StrTokenizer(final char[] input, final char delim) {
-        this(input);
-        setDelimiterChar(delim);
-    }
-
-    /**
-     * Constructs a tokenizer splitting on the specified string.
-     *
-     * @param input  the string which is to be parsed, not cloned
-     * @param delim the field delimiter string
-     */
-    public StrTokenizer(final char[] input, final String delim) {
-        this(input);
-        setDelimiterString(delim);
-    }
-
-    /**
-     * Constructs a tokenizer splitting using the specified delimiter matcher.
-     *
-     * @param input  the string which is to be parsed, not cloned
-     * @param delim  the field delimiter matcher
-     */
-    public StrTokenizer(final char[] input, final StrMatcher delim) {
-        this(input);
-        setDelimiterMatcher(delim);
-    }
-
-    /**
-     * Constructs a tokenizer splitting on the specified delimiter character
-     * and handling quotes using the specified quote character.
-     *
-     * @param input  the string which is to be parsed, not cloned
-     * @param delim  the field delimiter character
-     * @param quote  the field quoted string character
-     */
-    public StrTokenizer(final char[] input, final char delim, final char quote) {
-        this(input, delim);
-        setQuoteChar(quote);
-    }
-
-    /**
-     * Constructs a tokenizer splitting using the specified delimiter matcher
-     * and handling quotes using the specified quote matcher.
-     *
-     * @param input  the string which is to be parsed, not cloned
-     * @param delim  the field delimiter character
-     * @param quote  the field quoted string character
-     */
-    public StrTokenizer(final char[] input, final StrMatcher delim, final StrMatcher quote) {
-        this(input, delim);
-        setQuoteMatcher(quote);
-    }
-
-    // API
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the number of tokens found in the String.
-     *
-     * @return the number of matched tokens
-     */
-    public int size() {
-        checkTokenized();
-        return tokens.length;
-    }
-
-    /**
-     * Gets the next token from the String.
-     * Equivalent to {@link #next()} except it returns null rather than
-     * throwing {@link NoSuchElementException} when no tokens remain.
-     *
-     * @return the next sequential token, or null when no more tokens are found
-     */
-    public String nextToken() {
-        if (hasNext()) {
-            return tokens[tokenPos++];
-        }
-        return null;
-    }
-
-    /**
-     * Gets the previous token from the String.
-     *
-     * @return the previous sequential token, or null when no more tokens are found
-     */
-    public String previousToken() {
-        if (hasPrevious()) {
-            return tokens[--tokenPos];
-        }
-        return null;
-    }
-
-    /**
-     * Gets a copy of the full token list as an independent modifiable array.
-     *
-     * @return the tokens as a String array
-     */
-    public String[] getTokenArray() {
-        checkTokenized();
-        return tokens.clone();
-    }
-
-    /**
-     * Gets a copy of the full token list as an independent modifiable list.
-     *
-     * @return the tokens as a String array
-     */
-    public List<String> getTokenList() {
-        checkTokenized();
-        final List<String> list = new ArrayList<>(tokens.length);
-        for (final String element : tokens) {
-            list.add(element);
-        }
-        return list;
-    }
-
-    /**
-     * Resets this tokenizer, forgetting all parsing and iteration already completed.
-     * <p>
-     * This method allows the same tokenizer to be reused for the same String.
-     *
-     * @return this, to enable chaining
-     */
-    public StrTokenizer reset() {
-        tokenPos = 0;
-        tokens = null;
-        return this;
-    }
-
-    /**
-     * Reset this tokenizer, giving it a new input string to parse.
-     * In this manner you can re-use a tokenizer with the same settings
-     * on multiple input lines.
-     *
-     * @param input  the new string to tokenize, null sets no text to parse
-     * @return this, to enable chaining
-     */
-    public StrTokenizer reset(final String input) {
-        reset();
-        if (input != null) {
-            this.chars = input.toCharArray();
-        } else {
-            this.chars = null;
-        }
-        return this;
-    }
-
-    /**
-     * Reset this tokenizer, giving it a new input string to parse.
-     * In this manner you can re-use a tokenizer with the same settings
-     * on multiple input lines.
-     *
-     * @param input  the new character array to tokenize, not cloned, null sets no text to parse
-     * @return this, to enable chaining
-     */
-    public StrTokenizer reset(final char[] input) {
-        reset();
-        if (input != null) {
-            this.chars = input.clone();
-        } else {
-            this.chars = null;
-        }
-        return this;
-    }
-
-    // ListIterator
-    //-----------------------------------------------------------------------
-    /**
-     * Checks whether there are any more tokens.
-     *
-     * @return true if there are more tokens
-     */
-    @Override
-    public boolean hasNext() {
-        checkTokenized();
-        return tokenPos < tokens.length;
-    }
-
-    /**
-     * Gets the next token.
-     *
-     * @return the next String token
-     * @throws NoSuchElementException if there are no more elements
-     */
-    @Override
-    public String next() {
-        if (hasNext()) {
-            return tokens[tokenPos++];
-        }
-        throw new NoSuchElementException();
-    }
-
-    /**
-     * Gets the index of the next token to return.
-     *
-     * @return the next token index
-     */
-    @Override
-    public int nextIndex() {
-        return tokenPos;
-    }
-
-    /**
-     * Checks whether there are any previous tokens that can be iterated to.
-     *
-     * @return true if there are previous tokens
-     */
-    @Override
-    public boolean hasPrevious() {
-        checkTokenized();
-        return tokenPos > 0;
-    }
-
-    /**
-     * Gets the token previous to the last returned token.
-     *
-     * @return the previous token
-     */
-    @Override
-    public String previous() {
-        if (hasPrevious()) {
-            return tokens[--tokenPos];
-        }
-        throw new NoSuchElementException();
-    }
-
-    /**
-     * Gets the index of the previous token.
-     *
-     * @return the previous token index
-     */
-    @Override
-    public int previousIndex() {
-        return tokenPos - 1;
-    }
-
-    /**
-     * Unsupported ListIterator operation.
-     *
-     * @throws UnsupportedOperationException always
-     */
-    @Override
-    public void remove() {
-        throw new UnsupportedOperationException("remove() is unsupported");
-    }
-
-    /**
-     * Unsupported ListIterator operation.
-     * @param obj this parameter ignored.
-     * @throws UnsupportedOperationException always
-     */
-    @Override
-    public void set(final String obj) {
-        throw new UnsupportedOperationException("set() is unsupported");
-    }
-
-    /**
-     * Unsupported ListIterator operation.
-     * @param obj this parameter ignored.
-     * @throws UnsupportedOperationException always
-     */
-    @Override
-    public void add(final String obj) {
-        throw new UnsupportedOperationException("add() is unsupported");
-    }
-
-    // Implementation
-    //-----------------------------------------------------------------------
-    /**
-     * Checks if tokenization has been done, and if not then do it.
-     */
-    private void checkTokenized() {
-        if (tokens == null) {
-            if (chars == null) {
-                // still call tokenize as subclass may do some work
-                final List<String> split = tokenize(null, 0, 0);
-                tokens = split.toArray(new String[split.size()]);
-            } else {
-                final List<String> split = tokenize(chars, 0, chars.length);
-                tokens = split.toArray(new String[split.size()]);
-            }
-        }
-    }
-
-    /**
-     * Internal method to performs the tokenization.
-     * <p>
-     * Most users of this class do not need to call this method. This method
-     * will be called automatically by other (public) methods when required.
-     * <p>
-     * This method exists to allow subclasses to add code before or after the
-     * tokenization. For example, a subclass could alter the character array,
-     * offset or count to be parsed, or call the tokenizer multiple times on
-     * multiple strings. It is also be possible to filter the results.
-     * <p>
-     * <code>StrTokenizer</code> will always pass a zero offset and a count
-     * equal to the length of the array to this method, however a subclass
-     * may pass other values, or even an entirely different array.
-     *
-     * @param srcChars  the character array being tokenized, may be null
-     * @param offset  the start position within the character array, must be valid
-     * @param count  the number of characters to tokenize, must be valid
-     * @return the modifiable list of String tokens, unmodifiable if null array or zero count
-     */
-    protected List<String> tokenize(final char[] srcChars, final int offset, final int count) {
-        if (srcChars == null || count == 0) {
-            return Collections.emptyList();
-        }
-        final StrBuilder buf = new StrBuilder();
-        final List<String> tokenList = new ArrayList<>();
-        int pos = offset;
-
-        // loop around the entire buffer
-        while (pos >= 0 && pos < count) {
-            // find next token
-            pos = readNextToken(srcChars, pos, count, buf, tokenList);
-
-            // handle case where end of string is a delimiter
-            if (pos >= count) {
-                addToken(tokenList, "");
-            }
-        }
-        return tokenList;
-    }
-
-    /**
-     * Adds a token to a list, paying attention to the parameters we've set.
-     *
-     * @param list  the list to add to
-     * @param tok  the token to add
-     */
-    private void addToken(final List<String> list, String tok) {
-        if (tok == null || tok.length() == 0) {
-            if (isIgnoreEmptyTokens()) {
-                return;
-            }
-            if (isEmptyTokenAsNull()) {
-                tok = null;
-            }
-        }
-        list.add(tok);
-    }
-
-    /**
-     * Reads character by character through the String to get the next token.
-     *
-     * @param srcChars  the character array being tokenized
-     * @param start  the first character of field
-     * @param len  the length of the character array being tokenized
-     * @param workArea  a temporary work area
-     * @param tokenList  the list of parsed tokens
-     * @return the starting position of the next field (the character
-     *  immediately after the delimiter), or -1 if end of string found
-     */
-    private int readNextToken(final char[] srcChars, int start, final int len, final StrBuilder workArea, final List<String> tokenList) {
-        // skip all leading whitespace, unless it is the
-        // field delimiter or the quote character
-        while (start < len) {
-            final int removeLen = Math.max(
-                    getIgnoredMatcher().isMatch(srcChars, start, start, len),
-                    getTrimmerMatcher().isMatch(srcChars, start, start, len));
-            if (removeLen == 0 ||
-                getDelimiterMatcher().isMatch(srcChars, start, start, len) > 0 ||
-                getQuoteMatcher().isMatch(srcChars, start, start, len) > 0) {
-                break;
-            }
-            start += removeLen;
-        }
-
-        // handle reaching end
-        if (start >= len) {
-            addToken(tokenList, "");
-            return -1;
-        }
-
-        // handle empty token
-        final int delimLen = getDelimiterMatcher().isMatch(srcChars, start, start, len);
-        if (delimLen > 0) {
-            addToken(tokenList, "");
-            return start + delimLen;
-        }
-
-        // handle found token
-        final int quoteLen = getQuoteMatcher().isMatch(srcChars, start, start, len);
-        if (quoteLen > 0) {
-            return readWithQuotes(srcChars, start + quoteLen, len, workArea, tokenList, start, quoteLen);
-        }
-        return readWithQuotes(srcChars, start, len, workArea, tokenList, 0, 0);
-    }
-
-    /**
-     * Reads a possibly quoted string token.
-     *
-     * @param srcChars  the character array being tokenized
-     * @param start  the first character of field
-     * @param len  the length of the character array being tokenized
-     * @param workArea  a temporary work area
-     * @param tokenList  the list of parsed tokens
-     * @param quoteStart  the start position of the matched quote, 0 if no quoting
-     * @param quoteLen  the length of the matched quote, 0 if no quoting
-     * @return the starting position of the next field (the character
-     *  immediately after the delimiter, or if end of string found,
-     *  then the length of string
-     */
-    private int readWithQuotes(final char[] srcChars, final int start, final int len, final StrBuilder workArea,
-                               final List<String> tokenList, final int quoteStart, final int quoteLen) {
-        // Loop until we've found the end of the quoted
-        // string or the end of the input
-        workArea.clear();
-        int pos = start;
-        boolean quoting = quoteLen > 0;
-        int trimStart = 0;
-
-        while (pos < len) {
-            // quoting mode can occur several times throughout a string
-            // we must switch between quoting and non-quoting until we
-            // encounter a non-quoted delimiter, or end of string
-            if (quoting) {
-                // In quoting mode
-
-                // If we've found a quote character, see if it's
-                // followed by a second quote.  If so, then we need
-                // to actually put the quote character into the token
-                // rather than end the token.
-                if (isQuote(srcChars, pos, len, quoteStart, quoteLen)) {
-                    if (isQuote(srcChars, pos + quoteLen, len, quoteStart, quoteLen)) {
-                        // matched pair of quotes, thus an escaped quote
-                        workArea.append(srcChars, pos, quoteLen);
-                        pos += quoteLen * 2;
-                        trimStart = workArea.size();
-                        continue;
-                    }
-
-                    // end of quoting
-                    quoting = false;
-                    pos += quoteLen;
-                    continue;
-                }
-
-                // copy regular character from inside quotes
-                workArea.append(srcChars[pos++]);
-                trimStart = workArea.size();
-
-            } else {
-                // Not in quoting mode
-
-                // check for delimiter, and thus end of token
-                final int delimLen = getDelimiterMatcher().isMatch(srcChars, pos, start, len);
-                if (delimLen > 0) {
-                    // return condition when end of token found
-                    addToken(tokenList, workArea.substring(0, trimStart));
-                    return pos + delimLen;
-                }
-
-                // check for quote, and thus back into quoting mode
-                if (quoteLen > 0 && isQuote(srcChars, pos, len, quoteStart, quoteLen)) {
-                    quoting = true;
-                    pos += quoteLen;
-                    continue;
-                }
-
-                // check for ignored (outside quotes), and ignore
-                final int ignoredLen = getIgnoredMatcher().isMatch(srcChars, pos, start, len);
-                if (ignoredLen > 0) {
-                    pos += ignoredLen;
-                    continue;
-                }
-
-                // check for trimmed character
-                // don't yet know if its at the end, so copy to workArea
-                // use trimStart to keep track of trim at the end
-                final int trimmedLen = getTrimmerMatcher().isMatch(srcChars, pos, start, len);
-                if (trimmedLen > 0) {
-                    workArea.append(srcChars, pos, trimmedLen);
-                    pos += trimmedLen;
-                    continue;
-                }
-
-                // copy regular character from outside quotes
-                workArea.append(srcChars[pos++]);
-                trimStart = workArea.size();
-            }
-        }
-
-        // return condition when end of string found
-        addToken(tokenList, workArea.substring(0, trimStart));
-        return -1;
-    }
-
-    /**
-     * Checks if the characters at the index specified match the quote
-     * already matched in readNextToken().
-     *
-     * @param srcChars  the character array being tokenized
-     * @param pos  the position to check for a quote
-     * @param len  the length of the character array being tokenized
-     * @param quoteStart  the start position of the matched quote, 0 if no quoting
-     * @param quoteLen  the length of the matched quote, 0 if no quoting
-     * @return true if a quote is matched
-     */
-    private boolean isQuote(final char[] srcChars, final int pos, final int len, final int quoteStart, final int quoteLen) {
-        for (int i = 0; i < quoteLen; i++) {
-            if (pos + i >= len || srcChars[pos + i] != srcChars[quoteStart + i]) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    // Delimiter
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the field delimiter matcher.
-     *
-     * @return the delimiter matcher in use
-     */
-    public StrMatcher getDelimiterMatcher() {
-        return this.delimMatcher;
-    }
-
-    /**
-     * Sets the field delimiter matcher.
-     * <p>
-     * The delimitier is used to separate one token from another.
-     *
-     * @param delim  the delimiter matcher to use
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setDelimiterMatcher(final StrMatcher delim) {
-        if (delim == null) {
-            this.delimMatcher = StrMatcher.noneMatcher();
-        } else {
-            this.delimMatcher = delim;
-        }
-        return this;
-    }
-
-    /**
-     * Sets the field delimiter character.
-     *
-     * @param delim  the delimiter character to use
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setDelimiterChar(final char delim) {
-        return setDelimiterMatcher(StrMatcher.charMatcher(delim));
-    }
-
-    /**
-     * Sets the field delimiter string.
-     *
-     * @param delim  the delimiter string to use
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setDelimiterString(final String delim) {
-        return setDelimiterMatcher(StrMatcher.stringMatcher(delim));
-    }
-
-    // Quote
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the quote matcher currently in use.
-     * <p>
-     * The quote character is used to wrap data between the tokens.
-     * This enables delimiters to be entered as data.
-     * The default value is '"' (double quote).
-     *
-     * @return the quote matcher in use
-     */
-    public StrMatcher getQuoteMatcher() {
-        return quoteMatcher;
-    }
-
-    /**
-     * Set the quote matcher to use.
-     * <p>
-     * The quote character is used to wrap data between the tokens.
-     * This enables delimiters to be entered as data.
-     *
-     * @param quote  the quote matcher to use, null ignored
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setQuoteMatcher(final StrMatcher quote) {
-        if (quote != null) {
-            this.quoteMatcher = quote;
-        }
-        return this;
-    }
-
-    /**
-     * Sets the quote character to use.
-     * <p>
-     * The quote character is used to wrap data between the tokens.
-     * This enables delimiters to be entered as data.
-     *
-     * @param quote  the quote character to use
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setQuoteChar(final char quote) {
-        return setQuoteMatcher(StrMatcher.charMatcher(quote));
-    }
-
-    // Ignored
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the ignored character matcher.
-     * <p>
-     * These characters are ignored when parsing the String, unless they are
-     * within a quoted region.
-     * The default value is not to ignore anything.
-     *
-     * @return the ignored matcher in use
-     */
-    public StrMatcher getIgnoredMatcher() {
-        return ignoredMatcher;
-    }
-
-    /**
-     * Set the matcher for characters to ignore.
-     * <p>
-     * These characters are ignored when parsing the String, unless they are
-     * within a quoted region.
-     *
-     * @param ignored  the ignored matcher to use, null ignored
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setIgnoredMatcher(final StrMatcher ignored) {
-        if (ignored != null) {
-            this.ignoredMatcher = ignored;
-        }
-        return this;
-    }
-
-    /**
-     * Set the character to ignore.
-     * <p>
-     * This character is ignored when parsing the String, unless it is
-     * within a quoted region.
-     *
-     * @param ignored  the ignored character to use
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setIgnoredChar(final char ignored) {
-        return setIgnoredMatcher(StrMatcher.charMatcher(ignored));
-    }
-
-    // Trimmer
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the trimmer character matcher.
-     * <p>
-     * These characters are trimmed off on each side of the delimiter
-     * until the token or quote is found.
-     * The default value is not to trim anything.
-     *
-     * @return the trimmer matcher in use
-     */
-    public StrMatcher getTrimmerMatcher() {
-        return trimmerMatcher;
-    }
-
-    /**
-     * Sets the matcher for characters to trim.
-     * <p>
-     * These characters are trimmed off on each side of the delimiter
-     * until the token or quote is found.
-     *
-     * @param trimmer  the trimmer matcher to use, null ignored
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setTrimmerMatcher(final StrMatcher trimmer) {
-        if (trimmer != null) {
-            this.trimmerMatcher = trimmer;
-        }
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets whether the tokenizer currently returns empty tokens as null.
-     * The default for this property is false.
-     *
-     * @return true if empty tokens are returned as null
-     */
-    public boolean isEmptyTokenAsNull() {
-        return this.emptyAsNull;
-    }
-
-    /**
-     * Sets whether the tokenizer should return empty tokens as null.
-     * The default for this property is false.
-     *
-     * @param emptyAsNull  whether empty tokens are returned as null
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setEmptyTokenAsNull(final boolean emptyAsNull) {
-        this.emptyAsNull = emptyAsNull;
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets whether the tokenizer currently ignores empty tokens.
-     * The default for this property is true.
-     *
-     * @return true if empty tokens are not returned
-     */
-    public boolean isIgnoreEmptyTokens() {
-        return ignoreEmptyTokens;
-    }
-
-    /**
-     * Sets whether the tokenizer should ignore and not return empty tokens.
-     * The default for this property is true.
-     *
-     * @param ignoreEmptyTokens  whether empty tokens are not returned
-     * @return this, to enable chaining
-     */
-    public StrTokenizer setIgnoreEmptyTokens(final boolean ignoreEmptyTokens) {
-        this.ignoreEmptyTokens = ignoreEmptyTokens;
-        return this;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the String content that the tokenizer is parsing.
-     *
-     * @return the string content being parsed
-     */
-    public String getContent() {
-        if (chars == null) {
-            return null;
-        }
-        return new String(chars);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Creates a new instance of this Tokenizer. The new instance is reset so
-     * that it will be at the start of the token list.
-     * If a {@link CloneNotSupportedException} is caught, return <code>null</code>.
-     * 
-     * @return a new instance of this Tokenizer which has been reset.
-     */
-    @Override
-    public Object clone() {
-        try {
-            return cloneReset();
-        } catch (final CloneNotSupportedException ex) {
-            return null;
-        }
-    }
-
-    /**
-     * Creates a new instance of this Tokenizer. The new instance is reset so that
-     * it will be at the start of the token list.
-     * 
-     * @return a new instance of this Tokenizer which has been reset.
-     * @throws CloneNotSupportedException if there is a problem cloning
-     */
-    Object cloneReset() throws CloneNotSupportedException {
-        // this method exists to enable 100% test coverage
-        final StrTokenizer cloned = (StrTokenizer) super.clone();
-        if (cloned.chars != null) {
-            cloned.chars = cloned.chars.clone();
-        }
-        cloned.reset();
-        return cloned;
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Gets the String content that the tokenizer is parsing.
-     *
-     * @return the string content being parsed
-     */
-    @Override
-    public String toString() {
-        if (tokens == null) {
-            return "StrTokenizer[not tokenized yet]";
-        }
-        return "StrTokenizer" + getTokenList();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/StringEscapeUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/StringEscapeUtils.java b/src/main/java/org/apache/commons/text/beta/StringEscapeUtils.java
deleted file mode 100644
index d6f8ded..0000000
--- a/src/main/java/org/apache/commons/text/beta/StringEscapeUtils.java
+++ /dev/null
@@ -1,959 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.text.beta.translate.AggregateTranslator;
-import org.apache.commons.text.beta.translate.CharSequenceTranslator;
-import org.apache.commons.text.beta.translate.CsvTranslators;
-import org.apache.commons.text.beta.translate.EntityArrays;
-import org.apache.commons.text.beta.translate.JavaUnicodeEscaper;
-import org.apache.commons.text.beta.translate.LookupTranslator;
-import org.apache.commons.text.beta.translate.NumericEntityEscaper;
-import org.apache.commons.text.beta.translate.NumericEntityUnescaper;
-import org.apache.commons.text.beta.translate.OctalUnescaper;
-import org.apache.commons.text.beta.translate.SingleLookupTranslator;
-import org.apache.commons.text.beta.translate.UnicodeUnescaper;
-import org.apache.commons.text.beta.translate.UnicodeUnpairedSurrogateRemover;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * <p>Escapes and unescapes {@code String}s for
- * Java, Java Script, HTML and XML.</p>
- *
- * <p>#ThreadSafe#</p>
- *
- *
- * <p>
- * This code has been adapted from Apache Commons Lang 3.5.
- * </p>
- *
- * @since 1.0
- */
-public class StringEscapeUtils {
-
-    /* ESCAPE TRANSLATORS */
-
-    /**
-     * Translator object for escaping Java.
-     *
-     * While {@link #escapeJava(String)} is the expected method of use, this
-     * object allows the Java escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_JAVA;
-    static {
-        Map<CharSequence, CharSequence> escapeJavaMap = new HashMap<>();
-        escapeJavaMap.put("\"", "\\\"");
-        escapeJavaMap.put("\\", "\\\\");
-        ESCAPE_JAVA = new AggregateTranslator(
-                new LookupTranslator(Collections.unmodifiableMap(escapeJavaMap)),
-                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
-                JavaUnicodeEscaper.outsideOf(32, 0x7f)
-        );
-    }
-
-    /**
-     * Translator object for escaping EcmaScript/JavaScript.
-     *
-     * While {@link #escapeEcmaScript(String)} is the expected method of use, this
-     * object allows the EcmaScript escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_ECMASCRIPT;
-    static {
-        Map<CharSequence, CharSequence> escapeEcmaScriptMap = new HashMap<>();
-        escapeEcmaScriptMap.put("'", "\\'");
-        escapeEcmaScriptMap.put("\"", "\\\"");
-        escapeEcmaScriptMap.put("\\", "\\\\");
-        escapeEcmaScriptMap.put("/", "\\/");
-        ESCAPE_ECMASCRIPT = new AggregateTranslator(
-                new LookupTranslator(Collections.unmodifiableMap(escapeEcmaScriptMap)),
-                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
-                JavaUnicodeEscaper.outsideOf(32, 0x7f)
-        );
-    }
-
-    /**
-     * Translator object for escaping Json.
-     *
-     * While {@link #escapeJson(String)} is the expected method of use, this
-     * object allows the Json escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_JSON;
-    static {
-        Map<CharSequence, CharSequence> escapeJsonMap = new HashMap<>();
-        escapeJsonMap.put("\"", "\\\"");
-        escapeJsonMap.put("\\", "\\\\");
-        escapeJsonMap.put("/", "\\/");
-        ESCAPE_JSON = new AggregateTranslator(
-                new LookupTranslator(Collections.unmodifiableMap(escapeJsonMap)),
-                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_ESCAPE),
-                JavaUnicodeEscaper.outsideOf(32, 0x7f)
-        );
-    }
-
-    /**
-     * Translator object for escaping XML 1.0.
-     *
-     * While {@link #escapeXml10(String)} is the expected method of use, this
-     * object allows the XML escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_XML10;
-    static {
-        Map<CharSequence, CharSequence> escapeXml10Map = new HashMap<>();
-        escapeXml10Map.put("\u0000", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0001", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0002", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0003", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0004", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0005", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0006", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0007", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0008", StringUtils.EMPTY);
-        escapeXml10Map.put("\u000b", StringUtils.EMPTY);
-        escapeXml10Map.put("\u000c", StringUtils.EMPTY);
-        escapeXml10Map.put("\u000e", StringUtils.EMPTY);
-        escapeXml10Map.put("\u000f", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0010", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0011", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0012", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0013", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0014", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0015", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0016", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0017", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0018", StringUtils.EMPTY);
-        escapeXml10Map.put("\u0019", StringUtils.EMPTY);
-        escapeXml10Map.put("\u001a", StringUtils.EMPTY);
-        escapeXml10Map.put("\u001b", StringUtils.EMPTY);
-        escapeXml10Map.put("\u001c", StringUtils.EMPTY);
-        escapeXml10Map.put("\u001d", StringUtils.EMPTY);
-        escapeXml10Map.put("\u001e", StringUtils.EMPTY);
-        escapeXml10Map.put("\u001f", StringUtils.EMPTY);
-        escapeXml10Map.put("\ufffe", StringUtils.EMPTY);
-        escapeXml10Map.put("\uffff", StringUtils.EMPTY);
-        ESCAPE_XML10 = new AggregateTranslator(
-                new LookupTranslator(EntityArrays.BASIC_ESCAPE),
-                new LookupTranslator(EntityArrays.APOS_ESCAPE),
-                new LookupTranslator(Collections.unmodifiableMap(escapeXml10Map)),
-                NumericEntityEscaper.between(0x7f, 0x84),
-                NumericEntityEscaper.between(0x86, 0x9f),
-                new UnicodeUnpairedSurrogateRemover()
-        );
-    }
-
-    /**
-     * Translator object for escaping XML 1.1.
-     *
-     * While {@link #escapeXml11(String)} is the expected method of use, this
-     * object allows the XML escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_XML11;
-    static {
-        Map<CharSequence, CharSequence> escapeXml11Map = new HashMap<>();
-        escapeXml11Map.put("\u0000", StringUtils.EMPTY);
-        escapeXml11Map.put("\u000b", "&#11;");
-        escapeXml11Map.put("\u000c", "&#12;");
-        escapeXml11Map.put("\ufffe", StringUtils.EMPTY);
-        escapeXml11Map.put("\uffff", StringUtils.EMPTY);
-        ESCAPE_XML11 = new AggregateTranslator(
-                new LookupTranslator(EntityArrays.BASIC_ESCAPE),
-                new LookupTranslator(EntityArrays.APOS_ESCAPE),
-                new LookupTranslator(Collections.unmodifiableMap(escapeXml11Map)),
-                NumericEntityEscaper.between(0x1, 0x8),
-                NumericEntityEscaper.between(0xe, 0x1f),
-                NumericEntityEscaper.between(0x7f, 0x84),
-                NumericEntityEscaper.between(0x86, 0x9f),
-                new UnicodeUnpairedSurrogateRemover()
-        );
-    }
-
-    /**
-     * Translator object for escaping HTML version 3.0.
-     *
-     * While {@link #escapeHtml3(String)} is the expected method of use, this
-     * object allows the HTML escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_HTML3 =
-            new AggregateTranslator(
-                    new LookupTranslator(EntityArrays.BASIC_ESCAPE),
-                    new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE)
-            );
-
-    /**
-     * The improved translator object for escaping HTML version 3.0.
-     * The 'improved' part of this translator is that it checks if the html is already translated.
-     * This check prevents double, triple, or recursive translations.
-     *
-     * While {@link #escapeHtml3Once(String)} is the expected method of use, this
-     * object allows the HTML escaping functionality to be used
-     * as the foundation for a custom translator.
-     *
-     * Note that, multiple lookup tables should be passed to this translator
-     * instead of passing multiple instances of this translator to the
-     * AggregateTranslator. Because, a SingleLookupTranslator only checks the values of the
-     * lookup table passed to that instance while deciding whether a value is
-     * already translated or not.
-     */
-    public static final CharSequenceTranslator ESCAPE_HTML3_ONCE =
-            new SingleLookupTranslator(EntityArrays.BASIC_ESCAPE, EntityArrays.ISO8859_1_ESCAPE);
-
-
-    /**
-     * Translator object for escaping HTML version 4.0.
-     *
-     * While {@link #escapeHtml4(String)} is the expected method of use, this
-     * object allows the HTML escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_HTML4 =
-            new AggregateTranslator(
-                    new LookupTranslator(EntityArrays.BASIC_ESCAPE),
-                    new LookupTranslator(EntityArrays.ISO8859_1_ESCAPE),
-                    new LookupTranslator(EntityArrays.HTML40_EXTENDED_ESCAPE)
-            );
-
-    /**
-     * The improved translator object for escaping HTML version 4.0.
-     * The 'improved' part of this translator is that it checks if the html is already translated.
-     * This check prevents double, triple, or recursive translations.
-     *
-     * While {@link #escapeHtml4Once(String)} is the expected method of use, this
-     * object allows the HTML escaping functionality to be used
-     * as the foundation for a custom translator.
-     *
-     * Note that, multiple lookup tables should be passed to this translator
-     * instead of passing multiple instances of this translator to the
-     * AggregateTranslator. Because, a SingleLookupTranslator only checks the values of the
-     * lookup table passed to that instance while deciding whether a value is
-     * already translated or not.
-     */
-    public static final CharSequenceTranslator ESCAPE_HTML4_ONCE =
-            new SingleLookupTranslator(
-                    EntityArrays.BASIC_ESCAPE,
-                    EntityArrays.ISO8859_1_ESCAPE,
-                    EntityArrays.HTML40_EXTENDED_ESCAPE
-            );
-
-    /**
-     * Translator object for escaping individual Comma Separated Values.
-     *
-     * While {@link #escapeCsv(String)} is the expected method of use, this
-     * object allows the CSV escaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator ESCAPE_CSV = new CsvTranslators.CsvEscaper();
-
-    /**
-     * Translator object for escaping Shell command language.
-     *
-     * @see <a href="http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Language</a>
-     */
-    public static final CharSequenceTranslator ESCAPE_XSI;
-    static {
-        Map<CharSequence, CharSequence> escapeXsiMap = new HashMap<>();
-        escapeXsiMap.put("|", "\\|");
-        escapeXsiMap.put("&", "\\&");
-        escapeXsiMap.put(";", "\\;");
-        escapeXsiMap.put("<", "\\<");
-        escapeXsiMap.put(">", "\\>");
-        escapeXsiMap.put("(", "\\(");
-        escapeXsiMap.put(")", "\\)");
-        escapeXsiMap.put("$", "\\$");
-        escapeXsiMap.put("`", "\\`");
-        escapeXsiMap.put("\\", "\\\\");
-        escapeXsiMap.put("\"", "\\\"");
-        escapeXsiMap.put("'", "\\'");
-        escapeXsiMap.put(" ", "\\ ");
-        escapeXsiMap.put("\t", "\\\t");
-        escapeXsiMap.put("\r\n", "");
-        escapeXsiMap.put("\n", "");
-        escapeXsiMap.put("*", "\\*");
-        escapeXsiMap.put("?", "\\?");
-        escapeXsiMap.put("[", "\\[");
-        escapeXsiMap.put("#", "\\#");
-        escapeXsiMap.put("~", "\\~");
-        escapeXsiMap.put("=", "\\=");
-        escapeXsiMap.put("%", "\\%");
-        ESCAPE_XSI = new LookupTranslator(
-                Collections.unmodifiableMap(escapeXsiMap)
-        );
-    }
-
-    /* UNESCAPE TRANSLATORS */
-
-    /**
-     * Translator object for unescaping escaped Java.
-     *
-     * While {@link #unescapeJava(String)} is the expected method of use, this
-     * object allows the Java unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    // TODO: throw "illegal character: \92" as an Exception if a \ on the end of the Java (as per the compiler)?
-    public static final CharSequenceTranslator UNESCAPE_JAVA;
-    static {
-        Map<CharSequence, CharSequence> unescapeJavaMap = new HashMap<>();
-        unescapeJavaMap.put("\\\\", "\\");
-        unescapeJavaMap.put("\\\"", "\"");
-        unescapeJavaMap.put("\\'", "'");
-        unescapeJavaMap.put("\\", "");
-        UNESCAPE_JAVA = new AggregateTranslator(
-                new OctalUnescaper(),     // .between('\1', '\377'),
-                new UnicodeUnescaper(),
-                new LookupTranslator(EntityArrays.JAVA_CTRL_CHARS_UNESCAPE),
-                new LookupTranslator(Collections.unmodifiableMap(unescapeJavaMap))
-        );
-    }
-
-    /**
-     * Translator object for unescaping escaped EcmaScript.
-     *
-     * While {@link #unescapeEcmaScript(String)} is the expected method of use, this
-     * object allows the EcmaScript unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_ECMASCRIPT = UNESCAPE_JAVA;
-
-    /**
-     * Translator object for unescaping escaped Json.
-     *
-     * While {@link #unescapeJson(String)} is the expected method of use, this
-     * object allows the Json unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_JSON = UNESCAPE_JAVA;
-
-    /**
-     * Translator object for unescaping escaped HTML 3.0.
-     *
-     * While {@link #unescapeHtml3(String)} is the expected method of use, this
-     * object allows the HTML unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_HTML3 =
-            new AggregateTranslator(
-                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
-                    new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
-                    new NumericEntityUnescaper()
-            );
-
-    /**
-     * Translator object for unescaping escaped HTML 4.0.
-     *
-     * While {@link #unescapeHtml4(String)} is the expected method of use, this
-     * object allows the HTML unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_HTML4 =
-            new AggregateTranslator(
-                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
-                    new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
-                    new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE),
-                    new NumericEntityUnescaper()
-            );
-
-    /**
-     * Translator object for unescaping escaped XML.
-     *
-     * While {@link #unescapeXml(String)} is the expected method of use, this
-     * object allows the XML unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_XML =
-            new AggregateTranslator(
-                    new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
-                    new LookupTranslator(EntityArrays.APOS_UNESCAPE),
-                    new NumericEntityUnescaper()
-            );
-
-    /**
-     * Translator object for unescaping escaped Comma Separated Value entries.
-     *
-     * While {@link #unescapeCsv(String)} is the expected method of use, this
-     * object allows the CSV unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_CSV = new CsvTranslators.CsvUnescaper();
-
-    /**
-     * Translator object for unescaping escaped XSI Value entries.
-     *
-     * While {@link #unescapeXSI(String)}  is the expected method of use, this
-     * object allows the XSI unescaping functionality to be used
-     * as the foundation for a custom translator.
-     */
-    public static final CharSequenceTranslator UNESCAPE_XSI = new XsiUnescaper();
-
-    /**
-     * Translator object for unescaping backslash escaped entries.
-     */
-    static class XsiUnescaper extends CharSequenceTranslator {
-
-        /**
-         * Escaped backslash constant.
-         */
-        private static final char BACKSLASH = '\\';
-
-        @Override
-        public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
-
-            if (index != 0) {
-                throw new IllegalStateException("XsiUnescaper should never reach the [1] index");
-            }
-
-            String s = input.toString();
-
-            int segmentStart = 0;
-            int searchOffset = 0;
-            while (true) {
-                int pos = s.indexOf(BACKSLASH, searchOffset);
-                if (pos == -1) {
-                    if (segmentStart < s.length()) {
-                        out.write(s.substring(segmentStart));
-                    }
-                    break;
-                }
-                if (pos > segmentStart) {
-                    out.write(s.substring(segmentStart, pos));
-                }
-                segmentStart = pos + 1;
-                searchOffset = pos + 2;
-            }
-
-            return Character.codePointCount(input, 0, input.length());
-        }
-    }
-
-    /* Helper functions */
-
-    /**
-     * <p>{@code StringEscapeUtils} instances should NOT be constructed in
-     * standard programming.</p>
-     *
-     * <p>Instead, the class should be used as:</p>
-     * <pre>StringEscapeUtils.escapeJava("foo");</pre>
-     *
-     * <p>This constructor is public to permit tools that require a JavaBean
-     * instance to operate.</p>
-     */
-    public StringEscapeUtils() {
-        super();
-    }
-
-    /**
-     * <p>Convenience wrapper for {@link java.lang.StringBuilder} providing escape methods.</p>
-     *
-     * <p>Example:</p>
-     * <pre>
-     * new Builder(ESCAPE_HTML4)
-     *      .append("&lt;p&gt;")
-     *      .escape("This is paragraph 1 and special chars like &amp; get escaped.")
-     *      .append("&lt;/p&gt;&lt;p&gt;")
-     *      .escape("This is paragraph 2 &amp; more...")
-     *      .append("&lt;/p&gt;")
-     *      .toString()
-     * </pre>
-     *
-     */
-    public static final class Builder {
-
-        /**
-         * StringBuilder to be used in the Builder class.
-         */
-        private final StringBuilder sb;
-
-        /**
-         * CharSequenceTranslator to be used in the Builder class.
-         */
-        private final CharSequenceTranslator translator;
-
-        /**
-         * Builder constructor.
-         *
-         * @param translator a CharSequenceTranslator.
-         */
-        private Builder(final CharSequenceTranslator translator) {
-            this.sb = new StringBuilder();
-            this.translator = translator;
-        }
-
-        /**
-         * <p>Escape {@code input} according to the given {@link CharSequenceTranslator}.</p>
-         *
-         * @param input the String to escape
-         * @return {@code this}, to enable chaining
-         */
-        public Builder escape(final String input) {
-            sb.append(translator.translate(input));
-            return this;
-        }
-
-        /**
-         * Literal append, no escaping being done.
-         *
-         * @param input the String to append
-         * @return {@code this}, to enable chaining
-         */
-        public Builder append(final String input) {
-            sb.append(input);
-            return this;
-        }
-
-        /**
-         * <p>Return the escaped string.</p>
-         *
-         * @return the escaped string
-         */
-        @Override
-        public String toString() {
-            return sb.toString();
-        }
-    }
-
-    /**
-     * Get a {@link Builder}.
-     * @param translator the text translator
-     * @return {@link Builder}
-     */
-    public static StringEscapeUtils.Builder builder(final CharSequenceTranslator translator) {
-        return new Builder(translator);
-    }
-
-    // Java and JavaScript
-    //--------------------------------------------------------------------------
-    /**
-     * <p>Escapes the characters in a {@code String} using Java String rules.</p>
-     *
-     * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
-     *
-     * <p>So a tab becomes the characters {@code '\\'} and
-     * {@code 't'}.</p>
-     *
-     * <p>The only difference between Java strings and JavaScript strings
-     * is that in JavaScript, a single quote and forward-slash (/) are escaped.</p>
-     *
-     * <p>Example:</p>
-     * <pre>
-     * input string: He didn't say, "Stop!"
-     * output string: He didn't say, \"Stop!\"
-     * </pre>
-     *
-     * @param input  String to escape values in, may be null
-     * @return String with escaped values, {@code null} if null string input
-     */
-    public static final String escapeJava(final String input) {
-        return ESCAPE_JAVA.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using EcmaScript String rules.</p>
-     * <p>Escapes any values it finds into their EcmaScript String form.
-     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
-     *
-     * <p>So a tab becomes the characters {@code '\\'} and
-     * {@code 't'}.</p>
-     *
-     * <p>The only difference between Java strings and EcmaScript strings
-     * is that in EcmaScript, a single quote and forward-slash (/) are escaped.</p>
-     *
-     * <p>Note that EcmaScript is best known by the JavaScript and ActionScript dialects. </p>
-     *
-     * <p>Example:</p>
-     * <pre>
-     * input string: He didn't say, "Stop!"
-     * output string: He didn\'t say, \"Stop!\"
-     * </pre>
-     *
-     * <b>Security Note.</b> We only provide backslash escaping in this method. For example, {@code '\"'} has the output
-     * {@code '\\\"'} which could result in potential issues in the case where the string being escaped is being used
-     * in an HTML tag like {@code <select onmouseover="..." />}. If you wish to have more rigorous string escaping, you
-     * may consider the
-     * <a href="https://www.owasp.org/index.php/Category:OWASP_Enterprise_Security_API_JAVA">ESAPI Libraries</a>.
-     * Further, you can view the <a href="https://github.com/esapi">ESAPI GitHub Org</a>.
-     *
-     * @param input  String to escape values in, may be null
-     * @return String with escaped values, {@code null} if null string input
-     */
-    public static final String escapeEcmaScript(final String input) {
-        return ESCAPE_ECMASCRIPT.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using Json String rules.</p>
-     * <p>Escapes any values it finds into their Json String form.
-     * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.) </p>
-     *
-     * <p>So a tab becomes the characters {@code '\\'} and
-     * {@code 't'}.</p>
-     *
-     * <p>The only difference between Java strings and Json strings
-     * is that in Json, forward-slash (/) is escaped.</p>
-     *
-     * <p>See http://www.ietf.org/rfc/rfc4627.txt for further details. </p>
-     *
-     * <p>Example:</p>
-     * <pre>
-     * input string: He didn't say, "Stop!"
-     * output string: He didn't say, \"Stop!\"
-     * </pre>
-     *
-     * @param input  String to escape values in, may be null
-     * @return String with escaped values, {@code null} if null string input
-     */
-    public static final String escapeJson(final String input) {
-        return ESCAPE_JSON.translate(input);
-    }
-
-    /**
-     * <p>Unescapes any Java literals found in the {@code String}.
-     * For example, it will turn a sequence of {@code '\'} and
-     * {@code 'n'} into a newline character, unless the {@code '\'}
-     * is preceded by another {@code '\'}.</p>
-     *
-     * @param input  the {@code String} to unescape, may be null
-     * @return a new unescaped {@code String}, {@code null} if null string input
-     */
-    public static final String unescapeJava(final String input) {
-        return UNESCAPE_JAVA.translate(input);
-    }
-
-    /**
-     * <p>Unescapes any EcmaScript literals found in the {@code String}.</p>
-     *
-     * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
-     * into a newline character, unless the {@code '\'} is preceded by another
-     * {@code '\'}.</p>
-     *
-     * @see #unescapeJava(String)
-     * @param input  the {@code String} to unescape, may be null
-     * @return A new unescaped {@code String}, {@code null} if null string input
-     */
-    public static final String unescapeEcmaScript(final String input) {
-        return UNESCAPE_ECMASCRIPT.translate(input);
-    }
-
-    /**
-     * <p>Unescapes any Json literals found in the {@code String}.</p>
-     *
-     * <p>For example, it will turn a sequence of {@code '\'} and {@code 'n'}
-     * into a newline character, unless the {@code '\'} is preceded by another
-     * {@code '\'}.</p>
-     *
-     * @see #unescapeJava(String)
-     * @param input  the {@code String} to unescape, may be null
-     * @return A new unescaped {@code String}, {@code null} if null string input
-     */
-    public static final String unescapeJson(final String input) {
-        return UNESCAPE_JSON.translate(input);
-    }
-
-    // HTML and XML
-    //--------------------------------------------------------------------------
-    /**
-     * <p>Escapes the characters in a {@code String} using HTML entities.</p>
-     *
-     * <p>
-     * For example:
-     * </p>
-     * <p><code>"bread" &amp; "butter"</code></p>
-     * becomes:
-     * <p>
-     * <code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code>.
-     * </p>
-     *
-     * <p>Supports all known HTML 4.0 entities, including funky accents.
-     * Note that the commonly used apostrophe escape character (&amp;apos;)
-     * is not a legal entity and so is not supported). </p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     *
-     * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
-     * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
-     * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
-     * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
-     * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
-     */
-    public static final String escapeHtml4(final String input) {
-        return ESCAPE_HTML4.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using HTML entities.
-     * But escapes them only once. i.e. does not escape already escaped characters.</p>
-     *
-     * <p>
-     * For example:
-     * </p>
-     * <p><code>"bread" &amp; "butter"</code></p>
-     * becomes:
-     * <p>
-     * <code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code>.
-     * </p>
-     *
-     * <p>
-     * But:
-     * </p>
-     * <p><code>&amp;quot;bread&amp;quot; &amp;amp; &amp;quot;butter&amp;quot;</code></p>
-     * remains unaffected.
-     *
-     * <p>Supports all known HTML 4.0 entities, including funky accents.
-     * Note that the commonly used apostrophe escape character (&amp;apos;)
-     * is not a legal entity and so is not supported). </p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     *
-     * @see <a href="http://hotwired.lycos.com/webmonkey/reference/special_characters/">ISO Entities</a>
-     * @see <a href="http://www.w3.org/TR/REC-html32#latin1">HTML 3.2 Character Entities for ISO Latin-1</a>
-     * @see <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">HTML 4.0 Character entity references</a>
-     * @see <a href="http://www.w3.org/TR/html401/charset.html#h-5.3">HTML 4.01 Character References</a>
-     * @see <a href="http://www.w3.org/TR/html401/charset.html#code-position">HTML 4.01 Code positions</a>
-     */
-    public static final String escapeHtml4Once(final String input) {
-        return ESCAPE_HTML4_ONCE.translate(input);
-    }
-
-
-    /**
-     * <p>Escapes the characters in a {@code String} using HTML entities.</p>
-     * <p>Supports only the HTML 3.0 entities. </p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     */
-    public static final String escapeHtml3(final String input) {
-        return ESCAPE_HTML3.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using HTML entities.
-     * But escapes them only once. i.e. does not escape already escaped characters.</p>
-     * <p>Supports only the HTML 3.0 entities. </p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     */
-    public static final String escapeHtml3Once(final String input) {
-        return ESCAPE_HTML3_ONCE.translate(input);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * <p>Unescapes a string containing entity escapes to a string
-     * containing the actual Unicode characters corresponding to the
-     * escapes. Supports HTML 4.0 entities.</p>
-     *
-     * <p>For example, the string {@code "&lt;Fran&ccedil;ais&gt;"}
-     * will become {@code "<Fran\ufffdais>"}</p>
-     *
-     * <p>If an entity is unrecognized, it is left alone, and inserted
-     * verbatim into the result string. e.g. {@code "&gt;&zzzz;x"} will
-     * become {@code ">&zzzz;x"}.</p>
-     *
-     * @param input  the {@code String} to unescape, may be null
-     * @return a new unescaped {@code String}, {@code null} if null string input
-     */
-    public static final String unescapeHtml4(final String input) {
-        return UNESCAPE_HTML4.translate(input);
-    }
-
-    /**
-     * <p>Unescapes a string containing entity escapes to a string
-     * containing the actual Unicode characters corresponding to the
-     * escapes. Supports only HTML 3.0 entities.</p>
-     *
-     * @param input  the {@code String} to unescape, may be null
-     * @return a new unescaped {@code String}, {@code null} if null string input
-     */
-    public static final String unescapeHtml3(final String input) {
-        return UNESCAPE_HTML3.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using XML entities.</p>
-     *
-     * <p>For example: {@code "bread" & "butter"} =&gt;
-     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
-     * </p>
-     *
-     * <p>Note that XML 1.0 is a text-only format: it cannot represent control
-     * characters or unpaired Unicode surrogate codepoints, even after escaping.
-     * {@code escapeXml10} will remove characters that do not fit in the
-     * following ranges:</p>
-     *
-     * <p>{@code #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}</p>
-     *
-     * <p>Though not strictly necessary, {@code escapeXml10} will escape
-     * characters in the following ranges:</p>
-     *
-     * <p>{@code [#x7F-#x84] | [#x86-#x9F]}</p>
-     *
-     * <p>The returned string can be inserted into a valid XML 1.0 or XML 1.1
-     * document. If you want to allow more non-text characters in an XML 1.1
-     * document, use {@link #escapeXml11(String)}.</p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     * @see #unescapeXml(java.lang.String)
-     */
-    public static String escapeXml10(final String input) {
-        return ESCAPE_XML10.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using XML entities.</p>
-     *
-     * <p>For example: {@code "bread" & "butter"} =&gt;
-     * {@code &quot;bread&quot; &amp; &quot;butter&quot;}.
-     * </p>
-     *
-     * <p>XML 1.1 can represent certain control characters, but it cannot represent
-     * the null byte or unpaired Unicode surrogate codepoints, even after escaping.
-     * {@code escapeXml11} will remove characters that do not fit in the following
-     * ranges:</p>
-     *
-     * <p>{@code [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]}</p>
-     *
-     * <p>{@code escapeXml11} will escape characters in the following ranges:</p>
-     *
-     * <p>{@code [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F]}</p>
-     *
-     * <p>The returned string can be inserted into a valid XML 1.1 document. Do not
-     * use it for XML 1.0 documents.</p>
-     *
-     * @param input  the {@code String} to escape, may be null
-     * @return a new escaped {@code String}, {@code null} if null string input
-     * @see #unescapeXml(java.lang.String)
-     */
-    public static String escapeXml11(final String input) {
-        return ESCAPE_XML11.translate(input);
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * <p>Unescapes a string containing XML entity escapes to a string
-     * containing the actual Unicode characters corresponding to the
-     * escapes.</p>
-     *
-     * <p>Supports only the five basic XML entities (gt, lt, quot, amp, apos).
-     * Does not support DTDs or external entities.</p>
-     *
-     * <p>Note that numerical \\u Unicode codes are unescaped to their respective
-     *    Unicode characters. This may change in future releases. </p>
-     *
-     * @param input  the {@code String} to unescape, may be null
-     * @return a new unescaped {@code String}, {@code null} if null string input
-     * @see #escapeXml10(String)
-     * @see #escapeXml11(String)
-     */
-    public static final String unescapeXml(final String input) {
-        return UNESCAPE_XML.translate(input);
-    }
-
-    //-----------------------------------------------------------------------
-
-    /**
-     * <p>Returns a {@code String} value for a CSV column enclosed in double quotes,
-     * if required.</p>
-     *
-     * <p>If the value contains a comma, newline or double quote, then the
-     *    String value is returned enclosed in double quotes.</p>
-     *
-     * <p>Any double quote characters in the value are escaped with another double quote.</p>
-     *
-     * <p>If the value does not contain a comma, newline or double quote, then the
-     *    String value is returned unchanged.</p>
-     *
-     * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
-     * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
-     *
-     * @param input the input CSV column String, may be null
-     * @return the input String, enclosed in double quotes if the value contains a comma,
-     * newline or double quote, {@code null} if null string input
-     */
-    public static final String escapeCsv(final String input) {
-        return ESCAPE_CSV.translate(input);
-    }
-
-    /**
-     * <p>Returns a {@code String} value for an unescaped CSV column. </p>
-     *
-     * <p>If the value is enclosed in double quotes, and contains a comma, newline
-     *    or double quote, then quotes are removed.
-     * </p>
-     *
-     * <p>Any double quote escaped characters (a pair of double quotes) are unescaped
-     *    to just one double quote. </p>
-     *
-     * <p>If the value is not enclosed in double quotes, or is and does not contain a
-     *    comma, newline or double quote, then the String value is returned unchanged.</p>
-     *
-     * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia</a> and
-     * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
-     *
-     * @param input the input CSV column String, may be null
-     * @return the input String, with enclosing double quotes removed and embedded double
-     * quotes unescaped, {@code null} if null string input
-     */
-    public static final String unescapeCsv(final String input) {
-        return UNESCAPE_CSV.translate(input);
-    }
-
-    /**
-     * <p>Escapes the characters in a {@code String} using XSI rules.</p>
-     *
-     * <p><b>Beware!</b> In most cases you don't want to escape shell commands but use multi-argument
-     * methods provided by {@link java.lang.ProcessBuilder} or {@link java.lang.Runtime#exec(String[])}
-     * instead.</p>
-     *
-     * <p>Example:</p>
-     * <pre>
-     * input string: He didn't say, "Stop!"
-     * output string: He\ didn\'t\ say,\ \"Stop!\"
-     * </pre>
-     *
-     * @see <a href="http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html">Shell Command Language</a>
-     * @param input  String to escape values in, may be null
-     * @return String with escaped values, {@code null} if null string input
-     */
-    public static final String escapeXSI(final String input) {
-        return ESCAPE_XSI.translate(input);
-    }
-
-    /**
-     * <p>Unescapes the characters in a {@code String} using XSI rules.</p>
-     *
-     * @see StringEscapeUtils#escapeXSI(String)
-     * @param input  the {@code String} to unescape, may be null
-     * @return a new unescaped {@code String}, {@code null} if null string input
-     */
-    public static final String unescapeXSI(final String input) {
-        return UNESCAPE_XSI.translate(input);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/CommandVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/CommandVisitor.java b/src/main/java/org/apache/commons/text/beta/diff/CommandVisitor.java
deleted file mode 100644
index 0fdecbb..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/CommandVisitor.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-/**
- * This interface should be implemented by user object to walk
- * through {@link EditScript EditScript} objects.
- * <p>
- * Users should implement this interface in order to walk through
- * the {@link EditScript EditScript} object created by the comparison
- * of two sequences. This is a direct application of the visitor
- * design pattern. The {@link EditScript#visit EditScript.visit}
- * method takes an object implementing this interface as an argument,
- * it will perform the loop over all commands in the script and the
- * proper methods of the user class will be called as the commands are
- * encountered.
- * </p>
- * <p>
- * The implementation of the user visitor class will depend on the
- * need. Here are two examples.
- * </p>
- * <p>
- * The first example is a visitor that build the longest common
- * subsequence:
- * </p>
- * <pre>
- * import org.apache.commons.text.diff.CommandVisitor;
- *
- * import java.util.ArrayList;
- *
- * public class LongestCommonSubSequence implements CommandVisitor {
- *
- *   public LongestCommonSubSequence() {
- *     a = new ArrayList();
- *   }
- *
- *   public void visitInsertCommand(Object object) {
- *   }
- *
- *   public void visitKeepCommand(Object object) {
- *     a.add(object);
- *   }
- *
- *   public void visitDeleteCommand(Object object) {
- *   }
- *
- *   public Object[] getSubSequence() {
- *     return a.toArray();
- *   }
- *
- *   private ArrayList a;
- *
- * }
- * </pre>
- * <p>
- * The second example is a visitor that shows the commands and the way
- * they transform the first sequence into the second one:
- * <pre>
- * import org.apache.commons.text.diff.CommandVisitor;
- *
- * import java.util.Arrays;
- * import java.util.ArrayList;
- * import java.util.Iterator;
- *
- * public class ShowVisitor implements CommandVisitor {
- *
- *   public ShowVisitor(Object[] sequence1) {
- *     v = new ArrayList();
- *     v.addAll(Arrays.asList(sequence1));
- *     index = 0;
- *   }
- *
- *   public void visitInsertCommand(Object object) {
- *     v.insertElementAt(object, index++);
- *     display("insert", object);
- *   }
- *
- *   public void visitKeepCommand(Object object) {
- *     ++index;
- *     display("keep  ", object);
- *   }
- *
- *   public void visitDeleteCommand(Object object) {
- *     v.remove(index);
- *     display("delete", object);
- *   }
- *
- *   private void display(String commandName, Object object) {
- *     System.out.println(commandName + " " + object + ": " + this);
- *   }
- *
- *   public String toString() {
- *     StringBuffer buffer = new StringBuffer();
- *     for (Iterator iter = v.iterator(); iter.hasNext();) {
- *       buffer.append(' ').append(iter.next());
- *     }
- *     return buffer.toString();
- *   }
- *
- *   private ArrayList v;
- *   private int index;
- *
- * }
- * </pre>
- *
- * @param <T> object type
- * @since 1.0
- */
-public interface CommandVisitor<T> {
-
-    /**
-     * Method called when an insert command is encountered.
-     *
-     * @param object object to insert (this object comes from the second sequence)
-     */
-    void visitInsertCommand(T object);
-
-    /**
-     * Method called when a keep command is encountered.
-     *
-     * @param object object to keep (this object comes from the first sequence)
-     */
-    void visitKeepCommand(T object);
-
-    /**
-     * Method called when a delete command is encountered.
-     *
-     * @param object object to delete (this object comes from the first sequence)
-     */
-    void visitDeleteCommand(T object);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/diff/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/diff/DeleteCommand.java b/src/main/java/org/apache/commons/text/beta/diff/DeleteCommand.java
deleted file mode 100644
index 71bd418..0000000
--- a/src/main/java/org/apache/commons/text/beta/diff/DeleteCommand.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-
-/**
- * Command representing the deletion of one object of the first sequence.
- * <p>
- * When one object of the first sequence has no corresponding object in the
- * second sequence at the right place, the {@link EditScript edit script}
- * transforming the first sequence into the second sequence uses an instance of
- * this class to represent the deletion of this object. The objects embedded in
- * these type of commands always come from the first sequence.
- * </p>
- *
- * @see StringsComparator
- * @see EditScript
- *
- * @param <T> object type
- * @since 1.0
- */
-public class DeleteCommand<T> extends EditCommand<T> {
-
-    /**
-     * Simple constructor. Creates a new instance of {@link DeleteCommand}.
-     *
-     * @param object  the object of the first sequence that should be deleted
-     */
-    public DeleteCommand(final T object) {
-        super(object);
-    }
-
-    /**
-     * Accept a visitor. When a <code>DeleteCommand</code> accepts a visitor, it calls
-     * its {@link CommandVisitor#visitDeleteCommand visitDeleteCommand} method.
-     *
-     * @param visitor  the visitor to be accepted
-     */
-    @Override
-    public void accept(final CommandVisitor<T> visitor) {
-        visitor.visitDeleteCommand(getObject());
-    }
-}


[44/50] [abbrv] [text] TEXT-69: Removing unneeded parentheses

Posted by ch...@apache.org.
TEXT-69: Removing unneeded parentheses


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/867c38f1
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/867c38f1
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/867c38f1

Branch: refs/heads/release
Commit: 867c38f10665e78f5b2acfbb9d0dc8bfc1bd6fe6
Parents: 0ccf70e
Author: Rob Tompkins <ch...@apache.org>
Authored: Wed Feb 22 13:21:28 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Wed Feb 22 13:21:28 2017 -0500

----------------------------------------------------------------------
 .../java/org/apache/commons/text/translate/LookupTranslator.java   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/867c38f1/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/LookupTranslator.java b/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
index 51cafd9..532c877 100644
--- a/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
@@ -64,7 +64,7 @@ public class LookupTranslator extends CharSequenceTranslator {
         while (it.hasNext()) {
             Map.Entry<CharSequence, CharSequence> pair = it.next();
             this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
-            this.prefixSet.add((pair.getKey()).charAt(0));
+            this.prefixSet.add(pair.getKey().charAt(0));
             final int sz = pair.getKey().length();
             if (sz < _shortest) {
                 _shortest = sz;


[17/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/LevenshteinDetailedDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/LevenshteinDetailedDistance.java b/src/main/java/org/apache/commons/text/similarity/LevenshteinDetailedDistance.java
new file mode 100644
index 0000000..00b2689
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/LevenshteinDetailedDistance.java
@@ -0,0 +1,519 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.Arrays;
+
+/**
+ * An algorithm for measuring the difference between two character sequences.
+ *
+ * <p>
+ * This is the number of changes needed to change one sequence into another,
+ * where each change is a single character modification (deletion, insertion
+ * or substitution).
+ * </p>
+ *
+ * @since 1.0
+ */
+public class LevenshteinDetailedDistance implements EditDistance<LevenshteinResults> {
+
+    /**
+     * Default instance.
+     */
+    private static final LevenshteinDetailedDistance DEFAULT_INSTANCE = new LevenshteinDetailedDistance();
+    /**
+     * Threshold.
+     */
+    private final Integer threshold;
+
+    /**
+     * <p>
+     * This returns the default instance that uses a version
+     * of the algorithm that does not use a threshold parameter.
+     * </p>
+     *
+     * @see LevenshteinDetailedDistance#getDefaultInstance()
+     */
+    public LevenshteinDetailedDistance() {
+        this(null);
+    }
+
+    /**
+     * If the threshold is not null, distance calculations will be limited to a maximum length.
+     *
+     * <p>If the threshold is null, the unlimited version of the algorithm will be used.</p>
+     *
+     * @param threshold If this is null then distances calculations will not be limited. This may not be negative.
+     */
+    public LevenshteinDetailedDistance(final Integer threshold) {
+        if (threshold != null && threshold < 0) {
+            throw new IllegalArgumentException("Threshold must not be negative");
+        }
+        this.threshold = threshold;
+    }
+
+    /**
+     * <p>Find the Levenshtein distance between two Strings.</p>
+     *
+     * <p>A higher score indicates a greater distance.</p>
+     *
+     * <p>The previous implementation of the Levenshtein distance algorithm
+     * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
+     *
+     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
+     * which can occur when my Java implementation is used with very large strings.<br>
+     * This implementation of the Levenshtein distance algorithm
+     * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
+     *
+     * <pre>
+     * distance.apply(null, *)             = IllegalArgumentException
+     * distance.apply(*, null)             = IllegalArgumentException
+     * distance.apply("","")               = 0
+     * distance.apply("","a")              = 1
+     * distance.apply("aaapppp", "")       = 7
+     * distance.apply("frog", "fog")       = 1
+     * distance.apply("fly", "ant")        = 3
+     * distance.apply("elephant", "hippo") = 7
+     * distance.apply("hippo", "elephant") = 7
+     * distance.apply("hippo", "zzzzzzzz") = 8
+     * distance.apply("hello", "hallo")    = 1
+     * </pre>
+     *
+     * @param left the first string, must not be null
+     * @param right the second string, must not be null
+     * @return result distance, or -1
+     * @throws IllegalArgumentException if either String input {@code null}
+     */
+    @Override
+    public LevenshteinResults apply(final CharSequence left, final CharSequence right) {
+        if (threshold != null) {
+            return limitedCompare(left, right, threshold);
+        }
+        return unlimitedCompare(left, right);
+    }
+
+    /**
+     * Gets the default instance.
+     *
+     * @return the default instace
+     */
+    public static LevenshteinDetailedDistance getDefaultInstance() {
+        return DEFAULT_INSTANCE;
+    }
+
+    /**
+     * Gets the distance threshold.
+     *
+     * @return the distance threshold
+     */
+    public Integer getThreshold() {
+        return threshold;
+    }
+
+    /**
+     * Find the Levenshtein distance between two CharSequences if it's less than or
+     * equal to a given threshold.
+     *
+     * <p>
+     * This implementation follows from Algorithms on Strings, Trees and
+     * Sequences by Dan Gusfield and Chas Emerick's implementation of the
+     * Levenshtein distance algorithm from <a
+     * href="http://www.merriampark.com/ld.htm"
+     * >http://www.merriampark.com/ld.htm</a>
+     * </p>
+     *
+     * <pre>
+     * limitedCompare(null, *, *)             = IllegalArgumentException
+     * limitedCompare(*, null, *)             = IllegalArgumentException
+     * limitedCompare(*, *, -1)               = IllegalArgumentException
+     * limitedCompare("","", 0)               = 0
+     * limitedCompare("aaapppp", "", 8)       = 7
+     * limitedCompare("aaapppp", "", 7)       = 7
+     * limitedCompare("aaapppp", "", 6))      = -1
+     * limitedCompare("elephant", "hippo", 7) = 7
+     * limitedCompare("elephant", "hippo", 6) = -1
+     * limitedCompare("hippo", "elephant", 7) = 7
+     * limitedCompare("hippo", "elephant", 6) = -1
+     * </pre>
+     *
+     * @param left the first string, must not be null
+     * @param right the second string, must not be null
+     * @param threshold the target threshold, must not be negative
+     * @return result distance, or -1
+     */
+    private static LevenshteinResults limitedCompare(CharSequence left,
+                                                     CharSequence right,
+                                                     final int threshold) { //NOPMD
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+        if (threshold < 0) {
+            throw new IllegalArgumentException("Threshold must not be negative");
+        }
+
+        /*
+         * This implementation only computes the distance if it's less than or
+         * equal to the threshold value, returning -1 if it's greater. The
+         * advantage is performance: unbounded distance is O(nm), but a bound of
+         * k allows us to reduce it to O(km) time by only computing a diagonal
+         * stripe of width 2k + 1 of the cost table. It is also possible to use
+         * this to compute the unbounded Levenshtein distance by starting the
+         * threshold at 1 and doubling each time until the distance is found;
+         * this is O(dm), where d is the distance.
+         *
+         * One subtlety comes from needing to ignore entries on the border of
+         * our stripe eg. p[] = |#|#|#|* d[] = *|#|#|#| We must ignore the entry
+         * to the left of the leftmost member We must ignore the entry above the
+         * rightmost member
+         *
+         * Another subtlety comes from our stripe running off the matrix if the
+         * strings aren't of the same size. Since string s is always swapped to
+         * be the shorter of the two, the stripe will always run off to the
+         * upper right instead of the lower left of the matrix.
+         *
+         * As a concrete example, suppose s is of length 5, t is of length 7,
+         * and our threshold is 1. In this case we're going to walk a stripe of
+         * length 3. The matrix would look like so:
+         *
+         * <pre>
+         *    1 2 3 4 5
+         * 1 |#|#| | | |
+         * 2 |#|#|#| | |
+         * 3 | |#|#|#| |
+         * 4 | | |#|#|#|
+         * 5 | | | |#|#|
+         * 6 | | | | |#|
+         * 7 | | | | | |
+         * </pre>
+         *
+         * Note how the stripe leads off the table as there is no possible way
+         * to turn a string of length 5 into one of length 7 in edit distance of
+         * 1.
+         *
+         * Additionally, this implementation decreases memory usage by using two
+         * single-dimensional arrays and swapping them back and forth instead of
+         * allocating an entire n by m matrix. This requires a few minor
+         * changes, such as immediately returning when it's detected that the
+         * stripe has run off the matrix and initially filling the arrays with
+         * large values so that entries we don't compute are ignored.
+         *
+         * See Algorithms on Strings, Trees and Sequences by Dan Gusfield for
+         * some discussion.
+         */
+
+        int n = left.length(); // length of left
+        int m = right.length(); // length of right
+
+        // if one string is empty, the edit distance is necessarily the length of the other
+        if (n == 0) {
+            return m <= threshold ? new LevenshteinResults(m, m, 0, 0) : new LevenshteinResults(-1, 0, 0, 0);
+        } else if (m == 0) {
+            return n <= threshold ? new LevenshteinResults(n, 0, n, 0) : new LevenshteinResults(-1, 0, 0, 0);
+        }
+
+        boolean swapped = false;
+        if (n > m) {
+            // swap the two strings to consume less memory
+            final CharSequence tmp = left;
+            left = right;
+            right = tmp;
+            n = m;
+            m = right.length();
+            swapped = true;
+        }
+
+        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
+        int[] d = new int[n + 1]; // cost array, horizontally
+        int[] tempD; // placeholder to assist in swapping p and d
+        final int[][] matrix = new int[m + 1][n + 1];
+
+        //filling the first row and first column values in the matrix
+        for (int index = 0; index <= n; index++) {
+            matrix[0][index] = index;
+        }
+        for (int index = 0; index <= m; index++) {
+            matrix[index][0] = index;
+        }
+
+        // fill in starting table values
+        final int boundary = Math.min(n, threshold) + 1;
+        for (int i = 0; i < boundary; i++) {
+            p[i] = i;
+        }
+        // these fills ensure that the value above the rightmost entry of our
+        // stripe will be ignored in following loop iterations
+        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
+        Arrays.fill(d, Integer.MAX_VALUE);
+
+        // iterates through t
+        for (int j = 1; j <= m; j++) {
+            final char rightJ = right.charAt(j - 1); // jth character of right
+            d[0] = j;
+
+            // compute stripe indices, constrain to array size
+            final int min = Math.max(1, j - threshold);
+            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(
+                    n, j + threshold);
+
+            // the stripe may lead off of the table if s and t are of different sizes
+            if (min > max) {
+                return new LevenshteinResults(-1, 0, 0, 0);
+            }
+
+            // ignore entry left of leftmost
+            if (min > 1) {
+                d[min - 1] = Integer.MAX_VALUE;
+            }
+
+            // iterates through [min, max] in s
+            for (int i = min; i <= max; i++) {
+                if (left.charAt(i - 1) == rightJ) {
+                    // diagonally left and up
+                    d[i] = p[i - 1];
+                } else {
+                    // 1 + minimum of cell to the left, to the top, diagonally left and up
+                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
+                }
+                matrix[j][i] = d[i];
+            }
+
+            // copy current distance counts to 'previous row' distance counts
+            tempD = p;
+            p = d;
+            d = tempD;
+        }
+
+        // if p[n] is greater than the threshold, there's no guarantee on it being the correct distance
+        if (p[n] <= threshold) {
+            return findDetailedResults(left, right, matrix, swapped);
+        }
+        return new LevenshteinResults(-1, 0, 0, 0);
+    }
+
+    /**
+     * <p>Find the Levenshtein distance between two Strings.</p>
+     *
+     * <p>A higher score indicates a greater distance.</p>
+     *
+     * <p>The previous implementation of the Levenshtein distance algorithm
+     * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
+     *
+     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
+     * which can occur when my Java implementation is used with very large strings.<br>
+     * This implementation of the Levenshtein distance algorithm
+     * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
+     *
+     * <pre>
+     * unlimitedCompare(null, *)             = IllegalArgumentException
+     * unlimitedCompare(*, null)             = IllegalArgumentException
+     * unlimitedCompare("","")               = 0
+     * unlimitedCompare("","a")              = 1
+     * unlimitedCompare("aaapppp", "")       = 7
+     * unlimitedCompare("frog", "fog")       = 1
+     * unlimitedCompare("fly", "ant")        = 3
+     * unlimitedCompare("elephant", "hippo") = 7
+     * unlimitedCompare("hippo", "elephant") = 7
+     * unlimitedCompare("hippo", "zzzzzzzz") = 8
+     * unlimitedCompare("hello", "hallo")    = 1
+     * </pre>
+     *
+     * @param left the first String, must not be null
+     * @param right the second String, must not be null
+     * @return result distance, or -1
+     * @throws IllegalArgumentException if either String input {@code null}
+     */
+    private static LevenshteinResults unlimitedCompare(CharSequence left, CharSequence right) {
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+
+        /*
+           The difference between this impl. and the previous is that, rather
+           than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
+           we maintain two single-dimensional arrays of length s.length() + 1.  The first, d,
+           is the 'current working' distance array that maintains the newest distance cost
+           counts as we iterate through the characters of String s.  Each time we increment
+           the index of String t we are comparing, d is copied to p, the second int[].  Doing so
+           allows us to retain the previous cost counts as required by the algorithm (taking
+           the minimum of the cost count to the left, up one, and diagonally up and to the left
+           of the current cost count being calculated).  (Note that the arrays aren't really
+           copied anymore, just switched...this is clearly much better than cloning an array
+           or doing a System.arraycopy() each time  through the outer loop.)
+
+           Effectively, the difference between the two implementations is this one does not
+           cause an out of memory condition when calculating the LD over two very large strings.
+         */
+
+        int n = left.length(); // length of left
+        int m = right.length(); // length of right
+
+        if (n == 0) {
+            return new LevenshteinResults(m, m, 0, 0);
+        } else if (m == 0) {
+            return new LevenshteinResults(n, 0, n, 0);
+        }
+        boolean swapped = false;
+        if (n > m) {
+            // swap the input strings to consume less memory
+            final CharSequence tmp = left;
+            left = right;
+            right = tmp;
+            n = m;
+            m = right.length();
+            swapped = true;
+        }
+
+        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
+        int[] d = new int[n + 1]; // cost array, horizontally
+        int[] tempD; //placeholder to assist in swapping p and d
+        final int[][] matrix = new int[m + 1][n + 1];
+
+        // filling the first row and first column values in the matrix
+        for (int index = 0; index <= n; index++) {
+            matrix[0][index] = index;
+        }
+        for (int index = 0; index <= m; index++) {
+            matrix[index][0] = index;
+        }
+
+        // indexes into strings left and right
+        int i; // iterates through left
+        int j; // iterates through right
+
+        char rightJ; // jth character of right
+
+        int cost; // cost
+        for (i = 0; i <= n; i++) {
+            p[i] = i;
+        }
+
+        for (j = 1; j <= m; j++) {
+            rightJ = right.charAt(j - 1);
+            d[0] = j;
+
+            for (i = 1; i <= n; i++) {
+                cost = left.charAt(i - 1) == rightJ ? 0 : 1;
+                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
+                d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
+                //filling the matrix
+                matrix[j][i] = d[i];
+            }
+
+            // copy current distance counts to 'previous row' distance counts
+            tempD = p;
+            p = d;
+            d = tempD;
+        }
+        return findDetailedResults(left, right, matrix, swapped);
+    }
+
+    /**
+     * Finds count for each of the three [insert, delete, substitute] operations
+     * needed. This is based on the matrix formed based on the two character
+     * sequence.
+     *
+     * @param left character sequence which need to be converted from
+     * @param right character sequence which need to be converted to
+     * @param matrix two dimensional array containing
+     * @param swapped tells whether the value for left character sequence and right
+     *            character sequence were swapped to save memory
+     * @return result object containing the count of insert, delete and substitute and total count needed
+     */
+    private static LevenshteinResults findDetailedResults(final CharSequence left,
+                                                          final CharSequence right,
+                                                          final int[][] matrix,
+                                                          final boolean swapped) {
+
+        int delCount = 0;
+        int addCount = 0;
+        int subCount = 0;
+
+        int rowIndex = right.length();
+        int columnIndex = left.length();
+
+        int dataAtLeft = 0;
+        int dataAtTop = 0;
+        int dataAtDiagonal = 0;
+        int data = 0;
+        boolean deleted = false;
+        boolean added = false;
+
+        while (rowIndex >= 0 && columnIndex >= 0) {
+
+            if (columnIndex == 0) {
+                dataAtLeft = -1;
+            } else {
+                dataAtLeft = matrix[rowIndex][columnIndex - 1];
+            }
+            if (rowIndex == 0) {
+                dataAtTop = -1;
+            } else {
+                dataAtTop = matrix[rowIndex - 1][columnIndex];
+            }
+            if (rowIndex > 0 && columnIndex > 0) {
+                dataAtDiagonal = matrix[rowIndex - 1][columnIndex - 1];
+            } else {
+                dataAtDiagonal = -1;
+            }
+            if (dataAtLeft == -1 && dataAtTop == -1 && dataAtDiagonal == -1) {
+                break;
+            }
+            data = matrix[rowIndex][columnIndex];
+
+            // case in which the character at left and right are the same,
+            // in this case none of the counters will be incremented.
+            if (columnIndex > 0 && rowIndex > 0 && left.charAt(columnIndex - 1) == right.charAt(rowIndex - 1)) {
+                columnIndex--;
+                rowIndex--;
+                continue;
+            }
+
+            // handling insert and delete cases.
+            deleted = false;
+            added = false;
+            if (data - 1 == dataAtLeft && (data <= dataAtDiagonal && data <= dataAtTop)
+                    || (dataAtDiagonal == -1 && dataAtTop == -1)) { // NOPMD
+                columnIndex--;
+                if (swapped) {
+                    addCount++;
+                    added = true;
+                } else {
+                    delCount++;
+                    deleted = true;
+                }
+            } else if (data - 1 == dataAtTop && (data <= dataAtDiagonal && data <= dataAtLeft)
+                    || (dataAtDiagonal == -1 && dataAtLeft == -1)) { // NOPMD
+                rowIndex--;
+                if (swapped) {
+                    delCount++;
+                    deleted = true;
+                } else {
+                    addCount++;
+                    added = true;
+                }
+            }
+
+            // substituted case
+            if (!added && !deleted) {
+                subCount++;
+                columnIndex--;
+                rowIndex--;
+            }
+        }
+        return new LevenshteinResults(addCount + delCount + subCount, addCount, delCount, subCount);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/LevenshteinDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/LevenshteinDistance.java b/src/main/java/org/apache/commons/text/similarity/LevenshteinDistance.java
new file mode 100644
index 0000000..f3ef298
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/LevenshteinDistance.java
@@ -0,0 +1,396 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.Arrays;
+
+/**
+ * An algorithm for measuring the difference between two character sequences.
+ *
+ * <p>
+ * This is the number of changes needed to change one sequence into another,
+ * where each change is a single character modification (deletion, insertion
+ * or substitution).
+ * </p>
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Lang 3.3.
+ * </p>
+ *
+ * @since 1.0
+ */
+public class LevenshteinDistance implements EditDistance<Integer> {
+
+    /**
+     * Default instance.
+     */
+    private static final LevenshteinDistance DEFAULT_INSTANCE = new LevenshteinDistance();
+
+    /**
+     * Threshold.
+     */
+    private final Integer threshold;
+
+    /**
+     * <p>
+     * This returns the default instance that uses a version
+     * of the algorithm that does not use a threshold parameter.
+     * </p>
+     *
+     * @see LevenshteinDistance#getDefaultInstance()
+     */
+    public LevenshteinDistance() {
+        this(null);
+    }
+
+    /**
+     * <p>
+     * If the threshold is not null, distance calculations will be limited to a maximum length.
+     * If the threshold is null, the unlimited version of the algorithm will be used.
+     * </p>
+     *
+     * @param threshold
+     *        If this is null then distances calculations will not be limited.
+     *        This may not be negative.
+     */
+    public LevenshteinDistance(final Integer threshold) {
+        if (threshold != null && threshold < 0) {
+            throw new IllegalArgumentException("Threshold must not be negative");
+        }
+        this.threshold = threshold;
+    }
+
+    /**
+     * <p>Find the Levenshtein distance between two Strings.</p>
+     *
+     * <p>A higher score indicates a greater distance.</p>
+     *
+     * <p>The previous implementation of the Levenshtein distance algorithm
+     * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
+     *
+     * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
+     * which can occur when my Java implementation is used with very large strings.<br>
+     * This implementation of the Levenshtein distance algorithm
+     * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
+     *
+     * <pre>
+     * distance.apply(null, *)             = IllegalArgumentException
+     * distance.apply(*, null)             = IllegalArgumentException
+     * distance.apply("","")               = 0
+     * distance.apply("","a")              = 1
+     * distance.apply("aaapppp", "")       = 7
+     * distance.apply("frog", "fog")       = 1
+     * distance.apply("fly", "ant")        = 3
+     * distance.apply("elephant", "hippo") = 7
+     * distance.apply("hippo", "elephant") = 7
+     * distance.apply("hippo", "zzzzzzzz") = 8
+     * distance.apply("hello", "hallo")    = 1
+     * </pre>
+     *
+     * @param left the first string, must not be null
+     * @param right the second string, must not be null
+     * @return result distance, or -1
+     * @throws IllegalArgumentException if either String input {@code null}
+     */
+    @Override
+    public Integer apply(final CharSequence left, final CharSequence right) {
+        if (threshold != null) {
+            return limitedCompare(left, right, threshold);
+        }
+        return unlimitedCompare(left, right);
+    }
+
+    /**
+     * Gets the default instance.
+     *
+     * @return the default instace
+     */
+    public static LevenshteinDistance getDefaultInstance() {
+        return DEFAULT_INSTANCE;
+    }
+
+    /**
+     * Gets the distance threshold.
+     *
+     * @return the distance threshold
+     */
+    public Integer getThreshold() {
+        return threshold;
+    }
+
+    /**
+     * Find the Levenshtein distance between two CharSequences if it's less than or
+     * equal to a given threshold.
+     *
+     * <p>
+     * This implementation follows from Algorithms on Strings, Trees and
+     * Sequences by Dan Gusfield and Chas Emerick's implementation of the
+     * Levenshtein distance algorithm from <a
+     * href="http://www.merriampark.com/ld.htm"
+     * >http://www.merriampark.com/ld.htm</a>
+     * </p>
+     *
+     * <pre>
+     * limitedCompare(null, *, *)             = IllegalArgumentException
+     * limitedCompare(*, null, *)             = IllegalArgumentException
+     * limitedCompare(*, *, -1)               = IllegalArgumentException
+     * limitedCompare("","", 0)               = 0
+     * limitedCompare("aaapppp", "", 8)       = 7
+     * limitedCompare("aaapppp", "", 7)       = 7
+     * limitedCompare("aaapppp", "", 6))      = -1
+     * limitedCompare("elephant", "hippo", 7) = 7
+     * limitedCompare("elephant", "hippo", 6) = -1
+     * limitedCompare("hippo", "elephant", 7) = 7
+     * limitedCompare("hippo", "elephant", 6) = -1
+     * </pre>
+     *
+     * @param left the first string, must not be null
+     * @param right the second string, must not be null
+     * @param threshold the target threshold, must not be negative
+     * @return result distance, or -1
+     */
+    private static int limitedCompare(CharSequence left, CharSequence right, final int threshold) { // NOPMD
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+        if (threshold < 0) {
+            throw new IllegalArgumentException("Threshold must not be negative");
+        }
+
+        /*
+         * This implementation only computes the distance if it's less than or
+         * equal to the threshold value, returning -1 if it's greater. The
+         * advantage is performance: unbounded distance is O(nm), but a bound of
+         * k allows us to reduce it to O(km) time by only computing a diagonal
+         * stripe of width 2k + 1 of the cost table. It is also possible to use
+         * this to compute the unbounded Levenshtein distance by starting the
+         * threshold at 1 and doubling each time until the distance is found;
+         * this is O(dm), where d is the distance.
+         *
+         * One subtlety comes from needing to ignore entries on the border of
+         * our stripe eg. p[] = |#|#|#|* d[] = *|#|#|#| We must ignore the entry
+         * to the left of the leftmost member We must ignore the entry above the
+         * rightmost member
+         *
+         * Another subtlety comes from our stripe running off the matrix if the
+         * strings aren't of the same size. Since string s is always swapped to
+         * be the shorter of the two, the stripe will always run off to the
+         * upper right instead of the lower left of the matrix.
+         *
+         * As a concrete example, suppose s is of length 5, t is of length 7,
+         * and our threshold is 1. In this case we're going to walk a stripe of
+         * length 3. The matrix would look like so:
+         *
+         * <pre>
+         *    1 2 3 4 5
+         * 1 |#|#| | | |
+         * 2 |#|#|#| | |
+         * 3 | |#|#|#| |
+         * 4 | | |#|#|#|
+         * 5 | | | |#|#|
+         * 6 | | | | |#|
+         * 7 | | | | | |
+         * </pre>
+         *
+         * Note how the stripe leads off the table as there is no possible way
+         * to turn a string of length 5 into one of length 7 in edit distance of
+         * 1.
+         *
+         * Additionally, this implementation decreases memory usage by using two
+         * single-dimensional arrays and swapping them back and forth instead of
+         * allocating an entire n by m matrix. This requires a few minor
+         * changes, such as immediately returning when it's detected that the
+         * stripe has run off the matrix and initially filling the arrays with
+         * large values so that entries we don't compute are ignored.
+         *
+         * See Algorithms on Strings, Trees and Sequences by Dan Gusfield for
+         * some discussion.
+         */
+
+        int n = left.length(); // length of left
+        int m = right.length(); // length of right
+
+        // if one string is empty, the edit distance is necessarily the length
+        // of the other
+        if (n == 0) {
+            return m <= threshold ? m : -1;
+        } else if (m == 0) {
+            return n <= threshold ? n : -1;
+        }
+
+        if (n > m) {
+            // swap the two strings to consume less memory
+            final CharSequence tmp = left;
+            left = right;
+            right = tmp;
+            n = m;
+            m = right.length();
+        }
+
+        int[] p = new int[n + 1]; // 'previous' cost array, horizontally
+        int[] d = new int[n + 1]; // cost array, horizontally
+        int[] tempD; // placeholder to assist in swapping p and d
+
+        // fill in starting table values
+        final int boundary = Math.min(n, threshold) + 1;
+        for (int i = 0; i < boundary; i++) {
+            p[i] = i;
+        }
+        // these fills ensure that the value above the rightmost entry of our
+        // stripe will be ignored in following loop iterations
+        Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
+        Arrays.fill(d, Integer.MAX_VALUE);
+
+        // iterates through t
+        for (int j = 1; j <= m; j++) {
+            final char rightJ = right.charAt(j - 1); // jth character of right
+            d[0] = j;
+
+            // compute stripe indices, constrain to array size
+            final int min = Math.max(1, j - threshold);
+            final int max = j > Integer.MAX_VALUE - threshold ? n : Math.min(
+                    n, j + threshold);
+
+            // the stripe may lead off of the table if s and t are of different
+            // sizes
+            if (min > max) {
+                return -1;
+            }
+
+            // ignore entry left of leftmost
+            if (min > 1) {
+                d[min - 1] = Integer.MAX_VALUE;
+            }
+
+            // iterates through [min, max] in s
+            for (int i = min; i <= max; i++) {
+                if (left.charAt(i - 1) == rightJ) {
+                    // diagonally left and up
+                    d[i] = p[i - 1];
+                } else {
+                    // 1 + minimum of cell to the left, to the top, diagonally
+                    // left and up
+                    d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
+                }
+            }
+
+            // copy current distance counts to 'previous row' distance counts
+            tempD = p;
+            p = d;
+            d = tempD;
+        }
+
+        // if p[n] is greater than the threshold, there's no guarantee on it
+        // being the correct
+        // distance
+        if (p[n] <= threshold) {
+            return p[n];
+        }
+        return -1;
+    }
+
+    /**
+     * <p>Find the Levenshtein distance between two Strings.</p>
+     *
+     * <p>A higher score indicates a greater distance.</p>
+     *
+     * <p>The previous implementation of the Levenshtein distance algorithm
+     * was from <a href="https://web.archive.org/web/20120526085419/http://www.merriampark.com/ldjava.htm">
+     * https://web.archive.org/web/20120526085419/http://www.merriampark.com/ldjava.htm</a></p>
+     *
+     * <p>This implementation only need one single-dimensional arrays of length s.length() + 1</p>
+     *
+     * <pre>
+     * unlimitedCompare(null, *)             = IllegalArgumentException
+     * unlimitedCompare(*, null)             = IllegalArgumentException
+     * unlimitedCompare("","")               = 0
+     * unlimitedCompare("","a")              = 1
+     * unlimitedCompare("aaapppp", "")       = 7
+     * unlimitedCompare("frog", "fog")       = 1
+     * unlimitedCompare("fly", "ant")        = 3
+     * unlimitedCompare("elephant", "hippo") = 7
+     * unlimitedCompare("hippo", "elephant") = 7
+     * unlimitedCompare("hippo", "zzzzzzzz") = 8
+     * unlimitedCompare("hello", "hallo")    = 1
+     * </pre>
+     *
+     * @param left the first String, must not be null
+     * @param right the second String, must not be null
+     * @return result distance, or -1
+     * @throws IllegalArgumentException if either String input {@code null}
+     */
+    private static int unlimitedCompare(CharSequence left, CharSequence right) {
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Strings must not be null");
+        }
+
+        /*
+           This implementation use two variable to record the previous cost counts,
+           So this implementation use less memory than previous impl.
+         */
+
+        int n = left.length(); // length of left
+        int m = right.length(); // length of right
+
+        if (n == 0) {
+            return m;
+        } else if (m == 0) {
+            return n;
+        }
+
+        if (n > m) {
+            // swap the input strings to consume less memory
+            final CharSequence tmp = left;
+            left = right;
+            right = tmp;
+            n = m;
+            m = right.length();
+        }
+
+        int[] p = new int[n + 1];
+
+        // indexes into strings left and right
+        int i; // iterates through left
+        int j; // iterates through right
+        int upperLeft;
+        int upper;
+
+        char rightJ; // jth character of right
+        int cost; // cost
+
+        for (i = 0; i <= n; i++) {
+            p[i] = i;
+        }
+
+        for (j = 1; j <= m; j++) {
+            upperLeft = p[0];
+            rightJ = right.charAt(j - 1);
+            p[0] = j;
+
+            for (i = 1; i <= n; i++) {
+                upper = p[i];
+                cost = left.charAt(i - 1) == rightJ ? 0 : 1;
+                // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
+                p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upperLeft + cost);
+                upperLeft = upper;
+            }
+        }
+
+        return p[n];
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/LevenshteinResults.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/LevenshteinResults.java b/src/main/java/org/apache/commons/text/similarity/LevenshteinResults.java
new file mode 100644
index 0000000..e6c666f
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/LevenshteinResults.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.Objects;
+
+/**
+ * Container class to store Levenshtein distance between two character sequences.
+ *
+ * <p>Stores the count of insert, deletion and substitute operations needed to
+ * change one character sequence into another.</p>
+ *
+ * <p>This class is immutable.</p>
+ *
+ * @since 1.0
+ */
+public class LevenshteinResults {
+    /**
+     * Edit distance.
+     */
+    private final Integer distance;
+    /**
+     * Insert character count.
+     */
+    private final Integer insertCount;
+    /**
+     * Delete character count.
+     */
+    private final Integer deleteCount;
+    /**
+     * Substitute character count.
+     */
+    private final Integer substituteCount;
+
+    /**
+     * Create the results for a detailed Levenshtein distance.
+     *
+     * @param distance distance between two character sequences.
+     * @param insertCount insert character count
+     * @param deleteCount delete character count
+     * @param substituteCount substitute character count
+     */
+    public LevenshteinResults(final Integer distance, final Integer insertCount, final Integer deleteCount,
+            final Integer substituteCount) {
+        this.distance = distance;
+        this.insertCount = insertCount;
+        this.deleteCount = deleteCount;
+        this.substituteCount = substituteCount;
+    }
+
+    /**
+     * Get the distance between two character sequences.
+     *
+     * @return distance between two character sequence
+     */
+    public Integer getDistance() {
+        return distance;
+    }
+
+    /**
+     * Get the number of insertion needed to change one character sequence into another.
+     *
+     * @return insert character count
+     */
+    public Integer getInsertCount() {
+        return insertCount;
+    }
+
+    /**
+     * Get the number of character deletion needed to change one character sequence to other.
+     *
+     * @return delete character count
+     */
+    public Integer getDeleteCount() {
+        return deleteCount;
+    }
+
+    /**
+     * Get the number of character substitution needed to change one character sequence into another.
+     *
+     * @return substitute character count
+     */
+    public Integer getSubstituteCount() {
+        return substituteCount;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final LevenshteinResults result = (LevenshteinResults) o;
+        return Objects.equals(distance, result.distance) && Objects.equals(insertCount, result.insertCount)
+                && Objects.equals(deleteCount, result.deleteCount)
+                && Objects.equals(substituteCount, result.substituteCount);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(distance, insertCount, deleteCount, substituteCount);
+    }
+
+    @Override
+    public String toString() {
+        return "Distance: " + distance + ", Insert: " + insertCount + ", Delete: " + deleteCount + ", Substitute: "
+                + substituteCount;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequence.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequence.java b/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequence.java
new file mode 100644
index 0000000..cc5bb45
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequence.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * A similarity algorithm indicating the length of the longest common subsequence between two strings.
+ *
+ * <p>
+ * The Longest common subsequence algorithm returns the length of the longest subsequence that two strings have in
+ * common. Two strings that are entirely different, return a value of 0, and two strings that return a value
+ * of the commonly shared length implies that the strings are completely the same in value and position.
+ * <i>Note.</i>  Generally this algorithm is fairly inefficient, as for length <i>m</i>, <i>n</i> of the input
+ * <code>CharSequence</code>'s <code>left</code> and <code>right</code> respectively, the runtime of the
+ * algorithm is <i>O(m*n)</i>.
+ * </p>
+ *
+ * <p>
+ * This implementation is based on the Longest Commons Substring algorithm
+ * from <a href="https://en.wikipedia.org/wiki/Longest_common_subsequence_problem">
+ * https://en.wikipedia.org/wiki/Longest_common_subsequence_problem</a>.
+ * </p>
+ *
+ * <p>For further reading see:</p>
+ *
+ * <p>Lothaire, M. <i>Applied combinatorics on words</i>. New York: Cambridge U Press, 2005. <b>12-13</b></p>
+ *
+ * @since 1.0
+ */
+public class LongestCommonSubsequence implements SimilarityScore<Integer> {
+
+    /**
+     * Calculates longestCommonSubsequence similarity score of two <code>CharSequence</code>'s passed as
+     * input.
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return longestCommonSubsequenceLength
+     * @throws IllegalArgumentException
+     *             if either String input {@code null}
+     */
+    @Override
+    public Integer apply(final CharSequence left, final CharSequence right) {
+        // Quick return for invalid inputs
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Inputs must not be null");
+        }
+        return logestCommonSubsequence(left, right).length();
+    }
+
+    /**
+     *
+     * Computes the longestCommonSubsequence between the two <code>CharSequence</code>'s passed as
+     * input.
+     *
+     * <p>
+     * Note, a substring and
+     * subsequence are not necessarily the same thing. Indeed, <code>abcxyzqrs</code> and
+     * <code>xyzghfm</code> have both the same common substring and subsequence, namely <code>xyz</code>. However,
+     * <code>axbyczqrs</code> and <code>abcxyzqtv</code> have the longest common subsequence <code>xyzq</code> because a
+     * subsequence need not have adjacent characters.
+     * </p>
+     *
+     * <p>
+     * For reference, we give the definition of a subsequence for the reader: a <i>subsequence</i> is a sequence that
+     * can be derived from another sequence by deleting some elements without changing the order of the remaining
+     * elements.
+     * </p>
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return lcsLengthArray
+     * @throws IllegalArgumentException
+     *             if either String input {@code null}
+     */
+    public CharSequence logestCommonSubsequence(final CharSequence left, final CharSequence right) {
+        // Quick return
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Inputs must not be null");
+        }
+        StringBuilder longestCommonSubstringArray = new StringBuilder(Math.max(left.length(), right.length()));
+        int[][] lcsLengthArray = longestCommonSubstringLengthArray(left, right);
+        int i = left.length() - 1;
+        int j = right.length() - 1;
+        int k = lcsLengthArray[left.length()][right.length()] - 1;
+        while (k >= 0) {
+            if (left.charAt(i) == right.charAt(j)) {
+                longestCommonSubstringArray.append(left.charAt(i));
+                i = i - 1;
+                j = j - 1;
+                k = k - 1;
+            } else if (lcsLengthArray[i + 1][j] < lcsLengthArray[i][j + 1]) {
+                i = i - 1;
+            } else {
+                j = j - 1;
+            }
+        }
+        return longestCommonSubstringArray.reverse().toString();
+    }
+
+    /**
+     *
+     * Computes the lcsLengthArray for the sake of doing the actual lcs calculation. This is the
+     * dynamic programming portion of the algorithm, and is the reason for the runtime complexity being
+     * O(m*n), where m=left.length() and n=right.length().
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return lcsLengthArray
+     */
+    public int[][] longestCommonSubstringLengthArray(final CharSequence left, final CharSequence right) {
+        int[][] lcsLengthArray = new int[left.length() + 1][right.length() + 1];
+        for (int i = 0; i < left.length(); i++) {
+            for (int j = 0; j < right.length(); j++) {
+                if (i == 0) {
+                    lcsLengthArray[i][j] = 0;
+                }
+                if (j == 0) {
+                    lcsLengthArray[i][j] = 0;
+                }
+                if (left.charAt(i) == right.charAt(j)) {
+                    lcsLengthArray[i + 1][j + 1] = lcsLengthArray[i][j] + 1;
+                } else {
+                    lcsLengthArray[i + 1][j + 1] = Math.max(lcsLengthArray[i + 1][j], lcsLengthArray[i][j + 1]);
+                }
+            }
+        }
+        return lcsLengthArray;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistance.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistance.java b/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistance.java
new file mode 100644
index 0000000..a33f8b3
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistance.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * An edit distance algorithm based on the length of the longest common subsequence between two strings.
+ *
+ * <p>
+ * This code is directly based upon the implementation in {@link LongestCommonSubsequence}.
+ * </p>
+ *
+ * <p>
+ * For reference see: <a href="https://en.wikipedia.org/wiki/Longest_common_subsequence_problem">
+ * https://en.wikipedia.org/wiki/Longest_common_subsequence_problem</a>.
+ * </p>
+ *
+ * <p>For further reading see:</p>
+ *
+ * <p>Lothaire, M. <i>Applied combinatorics on words</i>. New York: Cambridge U Press, 2005. <b>12-13</b></p>
+ *
+ * @since 1.0
+ */
+public class LongestCommonSubsequenceDistance implements EditDistance<Integer> {
+
+    /**
+     * Object for calculating the longest common subsequence that we can then normalize in apply.
+     */
+    private final LongestCommonSubsequence longestCommonSubsequence = new LongestCommonSubsequence();
+
+    /**
+     * Calculates an edit distance between two <code>CharSequence</code>'s <code>left</code> and
+     * <code>right</code> as: <code>left.length() + right.length() - 2 * LCS(left, right)</code>, where
+     * <code>LCS</code> is given in {@link LongestCommonSubsequence#apply(CharSequence, CharSequence)}.
+     *
+     * @param left first character sequence
+     * @param right second character sequence
+     * @return distance
+     * @throws IllegalArgumentException
+     *             if either String input {@code null}
+     */
+    @Override
+    public Integer apply(final CharSequence left, final CharSequence right) {
+        // Quick return for invalid inputs
+        if (left == null || right == null) {
+            throw new IllegalArgumentException("Inputs must not be null");
+        }
+        return left.length() + right.length() - 2 * longestCommonSubsequence.apply(left, right);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/RegexTokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/RegexTokenizer.java b/src/main/java/org/apache/commons/text/similarity/RegexTokenizer.java
new file mode 100644
index 0000000..1c9e268
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/RegexTokenizer.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A simple word tokenizer that utilizes regex to find words. It applies a regex
+ * {@code}(\w)+{@code} over the input text to extract words from a given character
+ * sequence.
+ *
+ * @since 1.0
+ */
+class RegexTokenizer implements Tokenizer<CharSequence> {
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IllegalArgumentException if the input text is blank
+     */
+    @Override
+    public CharSequence[] tokenize(final CharSequence text) {
+        if (text == null || text.toString().trim().equals("")) {
+            throw new IllegalArgumentException("Invalid text");
+        }
+        final Pattern pattern = Pattern.compile("(\\w)+");
+        final Matcher matcher = pattern.matcher(text.toString());
+        final List<String> tokens = new ArrayList<>();
+        while (matcher.find()) {
+            tokens.add(matcher.group(0));
+        }
+        return tokens.toArray(new String[0]);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/SimilarityScore.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/SimilarityScore.java b/src/main/java/org/apache/commons/text/similarity/SimilarityScore.java
new file mode 100644
index 0000000..bca8d05
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/SimilarityScore.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * Interface for the concept of a string similarity score.
+ *
+ * <p>
+ * A string similarity score is intended to have <i>some</i> of the properties of a metric, yet
+ * allowing for exceptions, namely the Jaro-Winkler similarity score.
+ * </p>
+ * <p>
+ * We Define a SimilarityScore to be a function <code>d: [X * X] -&gt; [0, INFINITY)</code> with the
+ * following properties:
+ * </p>
+ * <ul>
+ *     <li><code>d(x,y) &gt;= 0</code>, non-negativity or separation axiom</li>
+ *     <li><code>d(x,y) == d(y,x)</code>, symmetry.</li>
+ * </ul>
+ *
+ * <p>
+ * Notice, these are two of the properties that contribute to d being a metric.
+ * </p>
+ *
+ *
+ * <p>
+ * Further, this intended to be BiFunction&lt;CharSequence, CharSequence, R&gt;.
+ * The <code>apply</code> method
+ * accepts a pair of {@link CharSequence} parameters
+ * and returns an <code>R</code> type similarity score. We have ommitted the explicit
+ * statement of extending BiFunction due to it only being implemented in Java 1.8, and we
+ * wish to maintain Java 1.7 compatibility.
+ * </p>
+ *
+ * @param <R> The type of similarity score unit used by this EditDistance.
+ * @since 1.0
+ */
+public interface SimilarityScore<R> {
+
+    /**
+     * Compares two CharSequences.
+     *
+     * @param left the first CharSequence
+     * @param right the second CharSequence
+     * @return the similarity score between two CharSequences
+     */
+    R apply(CharSequence left, CharSequence right);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/SimilarityScoreFrom.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/SimilarityScoreFrom.java b/src/main/java/org/apache/commons/text/similarity/SimilarityScoreFrom.java
new file mode 100644
index 0000000..b58ea4a
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/SimilarityScoreFrom.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * <p>
+ * This stores a {@link SimilarityScore} implementation and a {@link CharSequence} "left" string.
+ * The {@link #apply(CharSequence right)} method accepts the "right" string and invokes the
+ * comparison function for the pair of strings.
+ * </p>
+ *
+ * <p>
+ * The following is an example which finds the most similar string:
+ * </p>
+ * <pre>
+ * SimilarityScore&lt;Integer&gt; similarityScore = new LevenshteinDistance();
+ * String target = "Apache";
+ * SimilarityScoreFrom&lt;Integer&gt; similarityScoreFrom =
+ *     new SimilarityScoreFrom&lt;Integer&gt;(similarityScore, target);
+ * String mostSimilar = null;
+ * Integer shortestDistance = null;
+ *
+ * for (String test : new String[] { "Appaloosa", "a patchy", "apple" }) {
+ *     Integer distance = similarityScoreFrom.apply(test);
+ *     if (shortestDistance == null || distance &lt; shortestDistance) {
+ *         shortestDistance = distance;
+ *         mostSimilar = test;
+ *     }
+ * }
+ *
+ * System.out.println("The string most similar to \"" + target + "\" "
+ *     + "is \"" + mostSimilar + "\" because "
+ *     + "its distance is only " + shortestDistance + ".");
+ * </pre>
+ *
+ * @param <R> This is the type of similarity score used by the SimilarityScore function.
+ * @since 1.0
+ */
+public class SimilarityScoreFrom<R> {
+
+    /**
+     * Similarity score.
+     */
+    private final SimilarityScore<R> similarityScore;
+    /**
+     * Left parameter used in distance function.
+     */
+    private final CharSequence left;
+
+    /**
+     * <p>This accepts the similarity score implementation and the "left" string.</p>
+     *
+     * @param similarityScore This may not be null.
+     * @param left This may be null here,
+     *             but the SimilarityScore#compare(CharSequence left, CharSequence right)
+     *             implementation may not accept nulls.
+     */
+    public SimilarityScoreFrom(final SimilarityScore<R> similarityScore, final CharSequence left) {
+        if (similarityScore == null) {
+            throw new IllegalArgumentException("The edit distance may not be null.");
+        }
+
+        this.similarityScore = similarityScore;
+        this.left = left;
+    }
+
+    /**
+     * <p>
+     * This compares "left" field against the "right" parameter
+     * using the "similarity score" implementation.
+     * </p>
+     *
+     * @param right the second CharSequence
+     * @return the similarity score between two CharSequences
+     */
+    public R apply(final CharSequence right) {
+        return similarityScore.apply(left, right);
+    }
+
+    /**
+     * Gets the left parameter.
+     *
+     * @return the left parameter
+     */
+    public CharSequence getLeft() {
+        return left;
+    }
+
+    /**
+     * Gets the edit distance.
+     *
+     * @return the edit distance
+     */
+    public SimilarityScore<R> getSimilarityScore() {
+        return similarityScore;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/Tokenizer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/Tokenizer.java b/src/main/java/org/apache/commons/text/similarity/Tokenizer.java
new file mode 100644
index 0000000..fa8fda4
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/Tokenizer.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+/**
+ * A tokenizer. Can produce arrays of tokens from a given type.
+ *
+ * @param <T> given type
+ * @since 1.0
+ */
+interface Tokenizer<T> {
+
+    /**
+     * Returns an array of tokens.
+     *
+     * @param text input text
+     * @return array of tokens
+     */
+    T[] tokenize(CharSequence text);
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/similarity/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/similarity/package-info.java b/src/main/java/org/apache/commons/text/similarity/package-info.java
new file mode 100644
index 0000000..703e427
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/similarity/package-info.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * <p>Provides algorithms for string similarity.</p>
+ *
+ * <p>The algorithms that implement the EditDistance interface follow the same
+ * simple principle: the more similar (closer) strings are, lower is the distance.
+ * For example, the words house and hose are closer than house and trousers.</p>
+ *
+ * <p>The following algorithms are available at the moment:</p>
+ *
+ * <ul>
+ * <li>{@link org.apache.commons.text.similarity.CosineDistance Cosine Distance}</li>
+ * <li>{@link org.apache.commons.text.similarity.CosineSimilarity Cosine Similarity}</li>
+ * <li>{@link org.apache.commons.text.similarity.FuzzyScore Fuzzy Score}</li>
+ * <li>{@link org.apache.commons.text.similarity.HammingDistance Hamming Distance}</li>
+ * <li>{@link org.apache.commons.text.similarity.JaroWinklerDistance Jaro-Winkler Distance}</li>
+ * <li>{@link org.apache.commons.text.similarity.LevenshteinDistance Levenshtein Distance}</li>
+ * <li>{@link org.apache.commons.text.similarity.LongestCommonSubsequenceDistance
+ * Longest Commons Subsequence Distance}</li>
+ * </ul>
+ *
+ * <p>The {@link org.apache.commons.text.similarity.CosineDistance Cosine Distance}
+ * utilises a {@link org.apache.commons.text.similarity.RegexTokenizer regular expression tokenizer (\w+)}.
+ * And the {@link org.apache.commons.text.similarity.LevenshteinDistance Levenshtein Distance}'s
+ * behaviour can be changed to take into consideration a maximum throughput.</p>
+ *
+ * @since 1.0
+ */
+package org.apache.commons.text.similarity;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java b/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
new file mode 100644
index 0000000..010ab2a
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/AggregateTranslator.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Executes a sequence of translators one after the other. Execution ends whenever 
+ * the first translator consumes codepoints from the input.
+ *
+ * @since 1.0
+ */
+public class AggregateTranslator extends CharSequenceTranslator {
+
+    private final List<CharSequenceTranslator> translators = new ArrayList<>();
+
+    /**
+     * Specify the translators to be used at creation time. 
+     *
+     * @param translators CharSequenceTranslator array to aggregate
+     */
+    public AggregateTranslator(final CharSequenceTranslator... translators) {
+        if (translators != null) {
+            for (CharSequenceTranslator translator : translators) {
+                if (translator != null) {
+                    this.translators.add(translator);
+                }
+            }
+        }
+    }
+
+    /**
+     * The first translator to consume codepoints from the input is the 'winner'. 
+     * Execution stops with the number of consumed codepoints being returned. 
+     * {@inheritDoc}
+     */
+    @Override
+    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        for (final CharSequenceTranslator translator : translators) {
+            final int consumed = translator.translate(input, index, out);
+            if(consumed != 0) {
+                return consumed;
+            }
+        }
+        return 0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java b/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
new file mode 100644
index 0000000..baec844
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/CharSequenceTranslator.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Locale;
+
+/**
+ * An API for translating text. 
+ * Its core use is to escape and unescape text. Because escaping and unescaping 
+ * is completely contextual, the API does not present two separate signatures.
+ *
+ * @since 1.0
+ */
+public abstract class CharSequenceTranslator {
+
+    static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+
+    /**
+     * Translate a set of codepoints, represented by an int index into a CharSequence, 
+     * into another set of codepoints. The number of codepoints consumed must be returned, 
+     * and the only IOExceptions thrown must be from interacting with the Writer so that 
+     * the top level API may reliably ignore StringWriter IOExceptions. 
+     *
+     * @param input CharSequence that is being translated
+     * @param index int representing the current point of translation
+     * @param out Writer to translate the text to
+     * @return int count of codepoints consumed
+     * @throws IOException if and only if the Writer produces an IOException
+     */
+    public abstract int translate(CharSequence input, int index, Writer out) throws IOException;
+
+    /**
+     * Helper for non-Writer usage. 
+     * @param input CharSequence to be translated
+     * @return String output of translation
+     */
+    public final String translate(final CharSequence input) {
+        if (input == null) {
+            return null;
+        }
+        try {
+            final StringWriter writer = new StringWriter(input.length() * 2);
+            translate(input, writer);
+            return writer.toString();
+        } catch (final IOException ioe) {
+            // this should never ever happen while writing to a StringWriter
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    /**
+     * Translate an input onto a Writer. This is intentionally final as its algorithm is 
+     * tightly coupled with the abstract method of this class. 
+     *
+     * @param input CharSequence that is being translated
+     * @param out Writer to translate the text to
+     * @throws IOException if and only if the Writer produces an IOException
+     */
+    public final void translate(final CharSequence input, final Writer out) throws IOException {
+        if (out == null) {
+            throw new IllegalArgumentException("The Writer must not be null");
+        }
+        if (input == null) {
+            return;
+        }
+        int pos = 0;
+        final int len = input.length();
+        while (pos < len) {
+            final int consumed = translate(input, pos, out);
+            if (consumed == 0) {
+                // inlined implementation of Character.toChars(Character.codePointAt(input, pos))
+                // avoids allocating temp char arrays and duplicate checks
+                final char c1 = input.charAt(pos);
+                out.write(c1);
+                pos++;
+                if (Character.isHighSurrogate(c1) && pos < len) {
+                    final char c2 = input.charAt(pos);
+                    if (Character.isLowSurrogate(c2)) {
+                      out.write(c2);
+                      pos++;
+                    }
+                }
+                continue;
+            }
+            // contract with translators is that they have to understand codepoints
+            // and they just took care of a surrogate pair
+            for (int pt = 0; pt < consumed; pt++) {
+                pos += Character.charCount(Character.codePointAt(input, pos));
+            }
+        }
+    }
+
+    /**
+     * Helper method to create a merger of this translator with another set of 
+     * translators. Useful in customizing the standard functionality.
+     *
+     * @param translators CharSequenceTranslator array of translators to merge with this one
+     * @return CharSequenceTranslator merging this translator with the others
+     */
+    public final CharSequenceTranslator with(final CharSequenceTranslator... translators) {
+        final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1];
+        newArray[0] = this;
+        System.arraycopy(translators, 0, newArray, 1, translators.length);
+        return new AggregateTranslator(newArray);
+    }
+
+    /**
+     * <p>Returns an upper case hexadecimal <code>String</code> for the given
+     * character.</p>
+     *
+     * @param codepoint The codepoint to convert.
+     * @return An upper case hexadecimal <code>String</code>
+     */
+    public static String hex(final int codepoint) {
+        return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java b/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
new file mode 100644
index 0000000..3318261
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Helper subclass to CharSequenceTranslator to allow for translations that 
+ * will replace up to one character at a time.
+ *
+ * @since 1.0
+ */
+public abstract class CodePointTranslator extends CharSequenceTranslator {
+
+    /**
+     * Implementation of translate that maps onto the abstract translate(int, Writer) method. 
+     * {@inheritDoc}
+     */
+    @Override
+    public final int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        final int codepoint = Character.codePointAt(input, index);
+        final boolean consumed = translate(codepoint, out);
+        return consumed ? 1 : 0; 
+    }
+
+    /**
+     * Translate the specified codepoint into another. 
+     * 
+     * @param codepoint int character input to translate
+     * @param out Writer to optionally push the translated output to
+     * @return boolean as to whether translation occurred or not
+     * @throws IOException if and only if the Writer produces an IOException
+     */
+    public abstract boolean translate(int codepoint, Writer out) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/CsvTranslators.java b/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
new file mode 100644
index 0000000..f11b9fe
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import org.apache.commons.lang3.CharUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * This class holds inner classes for escaping/unescaping Comma Separated Values.
+ */
+public class CsvTranslators {
+
+    private static final char CSV_DELIMITER = ',';
+    private static final char CSV_QUOTE = '"';
+    private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
+    private static final String CSV_ESCAPED_QUOTE_STR = CSV_QUOTE_STR + CSV_QUOTE_STR;
+    private static final char[] CSV_SEARCH_CHARS =
+            new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
+
+    private CsvTranslators() { }
+
+    /**
+     * Translator for escaping Comma Separated Values.
+     */
+    public static class CsvEscaper extends SinglePassTranslator {
+
+        @Override
+        void translateWhole(final CharSequence input, final Writer out) throws IOException {
+            final String inputSting = input.toString();
+            if (StringUtils.containsNone(inputSting, CSV_SEARCH_CHARS)) {
+                out.write(inputSting);
+            } else {
+                // input needs quoting
+                out.write(CSV_QUOTE);
+                out.write(StringUtils.replace(inputSting, CSV_QUOTE_STR, CSV_ESCAPED_QUOTE_STR));
+                out.write(CSV_QUOTE);
+            }
+        }
+    }
+
+    /**
+     * Translator for unescaping escaped Comma Separated Value entries.
+     */
+    public static class CsvUnescaper extends SinglePassTranslator {
+
+        @Override
+        void translateWhole(final CharSequence input, final Writer out) throws IOException {
+            // is input not quoted?
+            if (input.charAt(0) != CSV_QUOTE || input.charAt(input.length() - 1) != CSV_QUOTE) {
+                out.write(input.toString());
+                return;
+            }
+
+            // strip quotes
+            final String quoteless = input.subSequence(1, input.length() - 1).toString();
+
+            if (StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS)) {
+                // deal with escaped quotes; ie) ""
+                out.write(StringUtils.replace(quoteless, CSV_ESCAPED_QUOTE_STR, CSV_QUOTE_STR));
+            } else {
+                out.write(input.toString());
+            }
+        }
+    }
+}
\ No newline at end of file


[35/50] [abbrv] [text] site: release-history, point to 1.0-beta-1 RELEASE-NOTES.txt

Posted by ch...@apache.org.
site: release-history, point to 1.0-beta-1 RELEASE-NOTES.txt


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/931fc751
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/931fc751
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/931fc751

Branch: refs/heads/release
Commit: 931fc75197e69e310576b840b7b480aee75cec31
Parents: 01e630b
Author: Rob Tompkins <ch...@apache.org>
Authored: Tue Feb 14 21:07:30 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Tue Feb 14 21:07:30 2017 -0500

----------------------------------------------------------------------
 src/site/xdoc/release-history.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/931fc751/src/site/xdoc/release-history.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/release-history.xml b/src/site/xdoc/release-history.xml
index b91841b..9e94c77 100644
--- a/src/site/xdoc/release-history.xml
+++ b/src/site/xdoc/release-history.xml
@@ -29,7 +29,7 @@ limitations under the License.
 <table>
 <tr><th>Version</th><th>Release date</th><th>Required Java Version</th><th>Javadoc</th><th>Release notes</th></tr>
 <tr>
-  <td>1.0-beta-1</td><td>2-9-2017</td><td>7.0</td><td><a href="javadocs/api-1.0-beta-1/">api-1.0-beta-1</a></td><td><a href="/RELEASE-NOTES.txt">release notes for 1.0-beta-1</a></td>
+  <td>1.0-beta-1</td><td>2-9-2017</td><td>7.0</td><td><a href="javadocs/api-1.0-beta-1/">api-1.0-beta-1</a></td><td><a href="release-notes/RELEASE-NOTES-1.0-beta-1.txt">release notes for 1.0-beta-1</a></td>
 </tr>
 </table>
 


[27/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/StrLookup.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrLookup.java b/src/main/java/org/apache/commons/text/StrLookup.java
new file mode 100644
index 0000000..f9bffb5
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/StrLookup.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.Map;
+
+/**
+ * Lookup a String key to a String value.
+ * <p>
+ * This class represents the simplest form of a string to string map.
+ * It has a benefit over a map in that it can create the result on
+ * demand based on the key.
+ * <p>
+ * This class comes complete with various factory methods.
+ * If these do not suffice, you can subclass and implement your own matcher.
+ * <p>
+ * For example, it would be possible to implement a lookup that used the
+ * key as a primary key, and looked up the value on demand from the database
+ *
+ * @since 1.0
+ */
+public abstract class StrLookup<V> {
+
+    /**
+     * Lookup that always returns null.
+     */
+    private static final StrLookup<String> NONE_LOOKUP = new MapStrLookup<>(null);
+
+    /**
+     * Lookup based on system properties.
+     */
+    private static final StrLookup<String> SYSTEM_PROPERTIES_LOOKUP = new SystemPropertiesStrLookup();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a lookup which always returns null.
+     *
+     * @return a lookup that always returns null, not null
+     */
+    public static StrLookup<?> noneLookup() {
+        return NONE_LOOKUP;
+    }
+
+    /**
+     * Returns a new lookup which uses a copy of the current
+     * {@link System#getProperties() System properties}.
+     * <p>
+     * If a security manager blocked access to system properties, then null will
+     * be returned from every lookup.
+     * <p>
+     * If a null key is used, this lookup will throw a NullPointerException.
+     *
+     * @return a lookup using system properties, not null
+     */
+    public static StrLookup<String> systemPropertiesLookup() {
+        return SYSTEM_PROPERTIES_LOOKUP;
+    }
+
+    /**
+     * Returns a lookup which looks up values using a map.
+     * <p>
+     * If the map is null, then null will be returned from every lookup.
+     * The map result object is converted to a string using toString().
+     *
+     * @param <V> the type of the values supported by the lookup
+     * @param map  the map of keys to values, may be null
+     * @return a lookup using the map, not null
+     */
+    public static <V> StrLookup<V> mapLookup(final Map<String, V> map) {
+        return new MapStrLookup<>(map);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     */
+    protected StrLookup() {
+        super();
+    }
+
+    /**
+     * Looks up a String key to a String value.
+     * <p>
+     * The internal implementation may use any mechanism to return the value.
+     * The simplest implementation is to use a Map. However, virtually any
+     * implementation is possible.
+     * <p>
+     * For example, it would be possible to implement a lookup that used the
+     * key as a primary key, and looked up the value on demand from the database
+     * Or, a numeric based implementation could be created that treats the key
+     * as an integer, increments the value and return the result as a string -
+     * converting 1 to 2, 15 to 16 etc.
+     * <p>
+     * The {@link #lookup(String)} method always returns a String, regardless of
+     * the underlying data, by converting it as necessary. For example:
+     * <pre>
+     * Map&lt;String, Object&gt; map = new HashMap&lt;String, Object&gt;();
+     * map.put("number", Integer.valueOf(2));
+     * assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
+     * </pre>
+     * @param key  the key to be looked up, may be null
+     * @return the matching value, null if no match
+     */
+    public abstract String lookup(String key);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Lookup implementation that uses a Map.
+     */
+    static class MapStrLookup<V> extends StrLookup<V> {
+
+        /** Map keys are variable names and value. */
+        private final Map<String, V> map;
+
+        /**
+         * Creates a new instance backed by a Map.
+         *
+         * @param map  the map of keys to values, may be null
+         */
+        MapStrLookup(final Map<String, V> map) {
+            this.map = map;
+        }
+
+        /**
+         * Looks up a String key to a String value using the map.
+         * <p>
+         * If the map is null, then null is returned.
+         * The map result object is converted to a string using toString().
+         *
+         * @param key  the key to be looked up, may be null
+         * @return the matching value, null if no match
+         */
+        @Override
+        public String lookup(final String key) {
+            if (map == null) {
+                return null;
+            }
+            final Object obj = map.get(key);
+            if (obj == null) {
+                return null;
+            }
+            return obj.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Lookup implementation based on system properties.
+     */
+    private static class SystemPropertiesStrLookup extends StrLookup<String> {
+        /**
+         * {@inheritDoc} This implementation directly accesses system properties.
+         */
+        @Override
+        public String lookup(final String key) {
+            if (key.length() > 0) {
+                try {
+                    return System.getProperty(key);
+                } catch (final SecurityException scex) {
+                    // Squelched. All lookup(String) will return null.
+                }
+            }
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/StrMatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrMatcher.java b/src/main/java/org/apache/commons/text/StrMatcher.java
new file mode 100644
index 0000000..97d6673
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/StrMatcher.java
@@ -0,0 +1,438 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.Arrays;
+
+/**
+ * A matcher class that can be queried to determine if a character array
+ * portion matches.
+ * <p>
+ * This class comes complete with various factory methods.
+ * If these do not suffice, you can subclass and implement your own matcher.
+ *
+ * @since 1.0
+ */
+public abstract class StrMatcher {
+
+    /**
+     * Matches the comma character.
+     */
+    private static final StrMatcher COMMA_MATCHER = new CharMatcher(',');
+    /**
+     * Matches the tab character.
+     */
+    private static final StrMatcher TAB_MATCHER = new CharMatcher('\t');
+    /**
+     * Matches the space character.
+     */
+    private static final StrMatcher SPACE_MATCHER = new CharMatcher(' ');
+    /**
+     * Matches the same characters as StringTokenizer,
+     * namely space, tab, newline, formfeed.
+     */
+    private static final StrMatcher SPLIT_MATCHER = new CharSetMatcher(" \t\n\r\f".toCharArray());
+    /**
+     * Matches the String trim() whitespace characters.
+     */
+    private static final StrMatcher TRIM_MATCHER = new TrimMatcher();
+    /**
+     * Matches the double quote character.
+     */
+    private static final StrMatcher SINGLE_QUOTE_MATCHER = new CharMatcher('\'');
+    /**
+     * Matches the double quote character.
+     */
+    private static final StrMatcher DOUBLE_QUOTE_MATCHER = new CharMatcher('"');
+    /**
+     * Matches the single or double quote character.
+     */
+    private static final StrMatcher QUOTE_MATCHER = new CharSetMatcher("'\"".toCharArray());
+    /**
+     * Matches no characters.
+     */
+    private static final StrMatcher NONE_MATCHER = new NoMatcher();
+
+    // -----------------------------------------------------------------------
+
+    /**
+     * Returns a matcher which matches the comma character.
+     *
+     * @return a matcher for a comma
+     */
+    public static StrMatcher commaMatcher() {
+        return COMMA_MATCHER;
+    }
+
+    /**
+     * Returns a matcher which matches the tab character.
+     *
+     * @return a matcher for a tab
+     */
+    public static StrMatcher tabMatcher() {
+        return TAB_MATCHER;
+    }
+
+    /**
+     * Returns a matcher which matches the space character.
+     *
+     * @return a matcher for a space
+     */
+    public static StrMatcher spaceMatcher() {
+        return SPACE_MATCHER;
+    }
+
+    /**
+     * Matches the same characters as StringTokenizer,
+     * namely space, tab, newline and formfeed.
+     *
+     * @return the split matcher
+     */
+    public static StrMatcher splitMatcher() {
+        return SPLIT_MATCHER;
+    }
+
+    /**
+     * Matches the String trim() whitespace characters.
+     *
+     * @return the trim matcher
+     */
+    public static StrMatcher trimMatcher() {
+        return TRIM_MATCHER;
+    }
+
+    /**
+     * Returns a matcher which matches the single quote character.
+     *
+     * @return a matcher for a single quote
+     */
+    public static StrMatcher singleQuoteMatcher() {
+        return SINGLE_QUOTE_MATCHER;
+    }
+
+    /**
+     * Returns a matcher which matches the double quote character.
+     *
+     * @return a matcher for a double quote
+     */
+    public static StrMatcher doubleQuoteMatcher() {
+        return DOUBLE_QUOTE_MATCHER;
+    }
+
+    /**
+     * Returns a matcher which matches the single or double quote character.
+     *
+     * @return a matcher for a single or double quote
+     */
+    public static StrMatcher quoteMatcher() {
+        return QUOTE_MATCHER;
+    }
+
+    /**
+     * Matches no characters.
+     *
+     * @return a matcher that matches nothing
+     */
+    public static StrMatcher noneMatcher() {
+        return NONE_MATCHER;
+    }
+
+    /**
+     * Constructor that creates a matcher from a character.
+     *
+     * @param ch  the character to match, must not be null
+     * @return a new Matcher for the given char
+     */
+    public static StrMatcher charMatcher(final char ch) {
+        return new CharMatcher(ch);
+    }
+
+    /**
+     * Constructor that creates a matcher from a set of characters.
+     *
+     * @param chars  the characters to match, null or empty matches nothing
+     * @return a new matcher for the given char[]
+     */
+    public static StrMatcher charSetMatcher(final char... chars) {
+        if (chars == null || chars.length == 0) {
+            return NONE_MATCHER;
+        }
+        if (chars.length == 1) {
+            return new CharMatcher(chars[0]);
+        }
+        return new CharSetMatcher(chars);
+    }
+
+    /**
+     * Constructor that creates a matcher from a string representing a set of characters.
+     *
+     * @param chars  the characters to match, null or empty matches nothing
+     * @return a new Matcher for the given characters
+     */
+    public static StrMatcher charSetMatcher(final String chars) {
+        if (chars == null || chars.length() == 0) {
+            return NONE_MATCHER;
+        }
+        if (chars.length() == 1) {
+            return new CharMatcher(chars.charAt(0));
+        }
+        return new CharSetMatcher(chars.toCharArray());
+    }
+
+    /**
+     * Constructor that creates a matcher from a string.
+     *
+     * @param str  the string to match, null or empty matches nothing
+     * @return a new Matcher for the given String
+     */
+    public static StrMatcher stringMatcher(final String str) {
+        if (str == null || str.length() == 0) {
+            return NONE_MATCHER;
+        }
+        return new StringMatcher(str);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     */
+    protected StrMatcher() {
+        super();
+    }
+
+    /**
+     * Returns the number of matching characters, zero for no match.
+     * <p>
+     * This method is called to check for a match.
+     * The parameter <code>pos</code> represents the current position to be
+     * checked in the string <code>buffer</code> (a character array which must
+     * not be changed).
+     * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
+     * <p>
+     * The character array may be larger than the active area to be matched.
+     * Only values in the buffer between the specified indices may be accessed.
+     * <p>
+     * The matching code may check one character or many.
+     * It may check characters preceding <code>pos</code> as well as those
+     * after, so long as no checks exceed the bounds specified.
+     * <p>
+     * It must return zero for no match, or a positive number if a match was found.
+     * The number indicates the number of characters that matched.
+     *
+     * @param buffer  the text content to match against, do not change
+     * @param pos  the starting position for the match, valid for buffer
+     * @param bufferStart  the first active index in the buffer, valid for buffer
+     * @param bufferEnd  the end index (exclusive) of the active buffer, valid for buffer
+     * @return the number of matching characters, zero for no match
+     */
+    public abstract int isMatch(char[] buffer, int pos, int bufferStart, int bufferEnd);
+
+    /**
+     * Returns the number of matching characters, zero for no match.
+     * <p>
+     * This method is called to check for a match.
+     * The parameter <code>pos</code> represents the current position to be
+     * checked in the string <code>buffer</code> (a character array which must
+     * not be changed).
+     * The API guarantees that <code>pos</code> is a valid index for <code>buffer</code>.
+     * <p>
+     * The matching code may check one character or many.
+     * It may check characters preceding <code>pos</code> as well as those after.
+     * <p>
+     * It must return zero for no match, or a positive number if a match was found.
+     * The number indicates the number of characters that matched.
+     *
+     * @param buffer  the text content to match against, do not change
+     * @param pos  the starting position for the match, valid for buffer
+     * @return the number of matching characters, zero for no match
+     */
+    public int isMatch(final char[] buffer, final int pos) {
+        return isMatch(buffer, pos, 0, buffer.length);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Class used to define a set of characters for matching purposes.
+     */
+    static final class CharSetMatcher extends StrMatcher {
+        /** The set of characters to match. */
+        private final char[] chars;
+
+        /**
+         * Constructor that creates a matcher from a character array.
+         *
+         * @param chars  the characters to match, must not be null
+         */
+        CharSetMatcher(final char chars[]) {
+            super();
+            this.chars = chars.clone();
+            Arrays.sort(this.chars);
+        }
+
+        /**
+         * Returns whether or not the given character matches.
+         *
+         * @param buffer  the text content to match against, do not change
+         * @param pos  the starting position for the match, valid for buffer
+         * @param bufferStart  the first active index in the buffer, valid for buffer
+         * @param bufferEnd  the end index of the active buffer, valid for buffer
+         * @return the number of matching characters, zero for no match
+         */
+        @Override
+        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
+            return Arrays.binarySearch(chars, buffer[pos]) >= 0 ? 1 : 0;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Class used to define a character for matching purposes.
+     */
+    static final class CharMatcher extends StrMatcher {
+        /** The character to match. */
+        private final char ch;
+
+        /**
+         * Constructor that creates a matcher that matches a single character.
+         *
+         * @param ch  the character to match
+         */
+        CharMatcher(final char ch) {
+            super();
+            this.ch = ch;
+        }
+
+        /**
+         * Returns whether or not the given character matches.
+         *
+         * @param buffer  the text content to match against, do not change
+         * @param pos  the starting position for the match, valid for buffer
+         * @param bufferStart  the first active index in the buffer, valid for buffer
+         * @param bufferEnd  the end index of the active buffer, valid for buffer
+         * @return the number of matching characters, zero for no match
+         */
+        @Override
+        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
+            return ch == buffer[pos] ? 1 : 0;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Class used to define a set of characters for matching purposes.
+     */
+    static final class StringMatcher extends StrMatcher {
+        /** The string to match, as a character array. */
+        private final char[] chars;
+
+        /**
+         * Constructor that creates a matcher from a String.
+         *
+         * @param str  the string to match, must not be null
+         */
+        StringMatcher(final String str) {
+            super();
+            chars = str.toCharArray();
+        }
+
+        /**
+         * Returns whether or not the given text matches the stored string.
+         *
+         * @param buffer  the text content to match against, do not change
+         * @param pos  the starting position for the match, valid for buffer
+         * @param bufferStart  the first active index in the buffer, valid for buffer
+         * @param bufferEnd  the end index of the active buffer, valid for buffer
+         * @return the number of matching characters, zero for no match
+         */
+        @Override
+        public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
+            final int len = chars.length;
+            if (pos + len > bufferEnd) {
+                return 0;
+            }
+            for (int i = 0; i < chars.length; i++, pos++) {
+                if (chars[i] != buffer[pos]) {
+                    return 0;
+                }
+            }
+            return len;
+        }
+        
+        @Override
+        public String toString() {
+            return super.toString() + ' ' + Arrays.toString(chars);
+        }
+
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Class used to match no characters.
+     */
+    static final class NoMatcher extends StrMatcher {
+
+        /**
+         * Constructs a new instance of <code>NoMatcher</code>.
+         */
+        NoMatcher() {
+            super();
+        }
+
+        /**
+         * Always returns <code>false</code>.
+         *
+         * @param buffer  the text content to match against, do not change
+         * @param pos  the starting position for the match, valid for buffer
+         * @param bufferStart  the first active index in the buffer, valid for buffer
+         * @param bufferEnd  the end index of the active buffer, valid for buffer
+         * @return the number of matching characters, zero for no match
+         */
+        @Override
+        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
+            return 0;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Class used to match whitespace as per trim().
+     */
+    static final class TrimMatcher extends StrMatcher {
+
+        /**
+         * Constructs a new instance of <code>TrimMatcher</code>.
+         */
+        TrimMatcher() {
+            super();
+        }
+
+        /**
+         * Returns whether or not the given character matches.
+         *
+         * @param buffer  the text content to match against, do not change
+         * @param pos  the starting position for the match, valid for buffer
+         * @param bufferStart  the first active index in the buffer, valid for buffer
+         * @param bufferEnd  the end index of the active buffer, valid for buffer
+         * @return the number of matching characters, zero for no match
+         */
+        @Override
+        public int isMatch(final char[] buffer, final int pos, final int bufferStart, final int bufferEnd) {
+            return buffer[pos] <= 32 ? 1 : 0;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/StrSubstitutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrSubstitutor.java b/src/main/java/org/apache/commons/text/StrSubstitutor.java
new file mode 100644
index 0000000..00d05f7
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/StrSubstitutor.java
@@ -0,0 +1,1213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * Substitutes variables within a string by values.
+ * <p>
+ * This class takes a piece of text and substitutes all the variables within it.
+ * The default definition of a variable is <code>${variableName}</code>.
+ * The prefix and suffix can be changed via constructors and set methods.
+ * <p>
+ * Variable values are typically resolved from a map, but could also be resolved
+ * from system properties, or by supplying a custom variable resolver.
+ * <p>
+ * The simplest example is to use this class to replace Java System properties. For example:
+ * <pre>
+ * StrSubstitutor.replaceSystemProperties(
+ *      "You are running with java.version = ${java.version} and os.name = ${os.name}.");
+ * </pre>
+ * <p>
+ * Typical usage of this class follows the following pattern: First an instance is created
+ * and initialized with the map that contains the values for the available variables.
+ * If a prefix and/or suffix for variables should be used other than the default ones,
+ * the appropriate settings can be performed. After that the <code>replace()</code>
+ * method can be called passing in the source text for interpolation. In the returned
+ * text all variable references (as long as their values are known) will be resolved.
+ * The following example demonstrates this:
+ * <pre>
+ * Map valuesMap = HashMap();
+ * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
+ * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
+ * String templateString = &quot;The ${animal} jumped over the ${target}.&quot;;
+ * StrSubstitutor sub = new StrSubstitutor(valuesMap);
+ * String resolvedString = sub.replace(templateString);
+ * </pre>
+ * yielding:
+ * <pre>
+ *      The quick brown fox jumped over the lazy dog.
+ * </pre>
+ * <p>
+ * Also, this class allows to set a default value for unresolved variables.
+ * The default value for a variable can be appended to the variable name after the variable
+ * default value delimiter. The default value of the variable default value delimiter is ':-',
+ * as in bash and other *nix shells, as those are arguably where the default ${} delimiter set originated.
+ * The variable default value delimiter can be manually set by calling {@link #setValueDelimiterMatcher(StrMatcher)},
+ * {@link #setValueDelimiter(char)} or {@link #setValueDelimiter(String)}.
+ * The following shows an example with variable default value settings:
+ * <pre>
+ * Map valuesMap = HashMap();
+ * valuesMap.put(&quot;animal&quot;, &quot;quick brown fox&quot;);
+ * valuesMap.put(&quot;target&quot;, &quot;lazy dog&quot;);
+ * String templateString = &quot;The ${animal} jumped over the ${target}. ${undefined.number:-1234567890}.&quot;;
+ * StrSubstitutor sub = new StrSubstitutor(valuesMap);
+ * String resolvedString = sub.replace(templateString);
+ * </pre>
+ * yielding:
+ * <pre>
+ *      The quick brown fox jumped over the lazy dog. 1234567890.
+ * </pre>
+ * <p>
+ * In addition to this usage pattern there are some static convenience methods that
+ * cover the most common use cases. These methods can be used without the need of
+ * manually creating an instance. However if multiple replace operations are to be
+ * performed, creating and reusing an instance of this class will be more efficient.
+ * <p>
+ * Variable replacement works in a recursive way. Thus, if a variable value contains
+ * a variable then that variable will also be replaced. Cyclic replacements are
+ * detected and will cause an exception to be thrown.
+ * <p>
+ * Sometimes the interpolation's result must contain a variable prefix. As an example
+ * take the following source text:
+ * <pre>
+ *   The variable ${${name}} must be used.
+ * </pre>
+ * Here only the variable's name referred to in the text should be replaced resulting
+ * in the text (assuming that the value of the <code>name</code> variable is <code>x</code>):
+ * <pre>
+ *   The variable ${x} must be used.
+ * </pre>
+ * To achieve this effect there are two possibilities: Either set a different prefix
+ * and suffix for variables which do not conflict with the result text you want to
+ * produce. The other possibility is to use the escape character, by default '$'.
+ * If this character is placed before a variable reference, this reference is ignored
+ * and won't be replaced. For example:
+ * <pre>
+ *   The variable $${${name}} must be used.
+ * </pre>
+ * <p>
+ * In some complex scenarios you might even want to perform substitution in the
+ * names of variables, for instance
+ * <pre>
+ * ${jre-${java.specification.version}}
+ * </pre>
+ * <code>StrSubstitutor</code> supports this recursive substitution in variable
+ * names, but it has to be enabled explicitly by setting the
+ * {@link #setEnableSubstitutionInVariables(boolean) enableSubstitutionInVariables}
+ * property to <b>true</b>.
+ * <p>This class is <b>not</b> thread safe.</p>
+ *
+ * @since 1.0
+ */
+public class StrSubstitutor {
+
+    /**
+     * Constant for the default escape character.
+     */
+    public static final char DEFAULT_ESCAPE = '$';
+    /**
+     * Constant for the default variable prefix.
+     */
+    public static final StrMatcher DEFAULT_PREFIX = StrMatcher.stringMatcher("${");
+    /**
+     * Constant for the default variable suffix.
+     */
+    public static final StrMatcher DEFAULT_SUFFIX = StrMatcher.stringMatcher("}");
+    /**
+     * Constant for the default value delimiter of a variable.
+     */
+    public static final StrMatcher DEFAULT_VALUE_DELIMITER = StrMatcher.stringMatcher(":-");
+
+    /**
+     * Stores the escape character.
+     */
+    private char escapeChar;
+    /**
+     * Stores the variable prefix.
+     */
+    private StrMatcher prefixMatcher;
+    /**
+     * Stores the variable suffix.
+     */
+    private StrMatcher suffixMatcher;
+    /**
+     * Stores the default variable value delimiter
+     */
+    private StrMatcher valueDelimiterMatcher;
+    /**
+     * Variable resolution is delegated to an implementor of VariableResolver.
+     */
+    private StrLookup<?> variableResolver;
+    /**
+     * The flag whether substitution in variable names is enabled.
+     */
+    private boolean enableSubstitutionInVariables;
+    /**
+     * Whether escapes should be preserved.  Default is false;
+     */
+    private boolean preserveEscapes = false;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables in the given source object with
+     * their matching values from the map.
+     *
+     * @param <V> the type of the values in the map
+     * @param source  the source text containing the variables to substitute, null returns null
+     * @param valueMap  the map with the values, may be null
+     * @return the result of the replace operation
+     */
+    public static <V> String replace(final Object source, final Map<String, V> valueMap) {
+        return new StrSubstitutor(valueMap).replace(source);
+    }
+
+    /**
+     * Replaces all the occurrences of variables in the given source object with
+     * their matching values from the map. This method allows to specifiy a
+     * custom variable prefix and suffix
+     *
+     * @param <V> the type of the values in the map
+     * @param source  the source text containing the variables to substitute, null returns null
+     * @param valueMap  the map with the values, may be null
+     * @param prefix  the prefix of variables, not null
+     * @param suffix  the suffix of variables, not null
+     * @return the result of the replace operation
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public static <V> String replace(final Object source, final Map<String, V> valueMap, final String prefix, final String suffix) {
+        return new StrSubstitutor(valueMap, prefix, suffix).replace(source);
+    }
+
+    /**
+     * Replaces all the occurrences of variables in the given source object with their matching
+     * values from the properties.
+     *
+     * @param source the source text containing the variables to substitute, null returns null
+     * @param valueProperties the properties with values, may be null
+     * @return the result of the replace operation
+     */
+    public static String replace(final Object source, final Properties valueProperties) {
+        if (valueProperties == null) {
+            return source.toString();
+        }
+        final Map<String,String> valueMap = new HashMap<>();
+        final Enumeration<?> propNames = valueProperties.propertyNames();
+        while (propNames.hasMoreElements()) {
+            final String propName = (String)propNames.nextElement();
+            final String propValue = valueProperties.getProperty(propName);
+            valueMap.put(propName, propValue);
+        }
+        return StrSubstitutor.replace(source, valueMap);
+    }
+
+    /**
+     * Replaces all the occurrences of variables in the given source object with
+     * their matching values from the system properties.
+     *
+     * @param source  the source text containing the variables to substitute, null returns null
+     * @return the result of the replace operation
+     */
+    public static String replaceSystemProperties(final Object source) {
+        return new StrSubstitutor(StrLookup.systemPropertiesLookup()).replace(source);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a new instance with defaults for variable prefix and suffix
+     * and the escaping character.
+     */
+    public StrSubstitutor() {
+        this((StrLookup<?>) null, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
+    }
+
+    /**
+     * Creates a new instance and initializes it. Uses defaults for variable
+     * prefix and suffix and the escaping character.
+     *
+     * @param <V> the type of the values in the map
+     * @param valueMap  the map with the variables' values, may be null
+     */
+    public <V> StrSubstitutor(final Map<String, V> valueMap) {
+        this(StrLookup.mapLookup(valueMap), DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
+    }
+
+    /**
+     * Creates a new instance and initializes it. Uses a default escaping character.
+     *
+     * @param <V> the type of the values in the map
+     * @param valueMap  the map with the variables' values, may be null
+     * @param prefix  the prefix for variables, not null
+     * @param suffix  the suffix for variables, not null
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public <V> StrSubstitutor(final Map<String, V> valueMap, final String prefix, final String suffix) {
+        this(StrLookup.mapLookup(valueMap), prefix, suffix, DEFAULT_ESCAPE);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param <V> the type of the values in the map
+     * @param valueMap  the map with the variables' values, may be null
+     * @param prefix  the prefix for variables, not null
+     * @param suffix  the suffix for variables, not null
+     * @param escape  the escape character
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public <V> StrSubstitutor(final Map<String, V> valueMap, final String prefix, final String suffix,
+                              final char escape) {
+        this(StrLookup.mapLookup(valueMap), prefix, suffix, escape);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param <V> the type of the values in the map
+     * @param valueMap  the map with the variables' values, may be null
+     * @param prefix  the prefix for variables, not null
+     * @param suffix  the suffix for variables, not null
+     * @param escape  the escape character
+     * @param valueDelimiter  the variable default value delimiter, may be null
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public <V> StrSubstitutor(final Map<String, V> valueMap, final String prefix, final String suffix,
+                              final char escape, final String valueDelimiter) {
+        this(StrLookup.mapLookup(valueMap), prefix, suffix, escape, valueDelimiter);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param variableResolver  the variable resolver, may be null
+     */
+    public StrSubstitutor(final StrLookup<?> variableResolver) {
+        this(variableResolver, DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_ESCAPE);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param variableResolver  the variable resolver, may be null
+     * @param prefix  the prefix for variables, not null
+     * @param suffix  the suffix for variables, not null
+     * @param escape  the escape character
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public StrSubstitutor(final StrLookup<?> variableResolver, final String prefix, final String suffix,
+                          final char escape) {
+        this.setVariableResolver(variableResolver);
+        this.setVariablePrefix(prefix);
+        this.setVariableSuffix(suffix);
+        this.setEscapeChar(escape);
+        this.setValueDelimiterMatcher(DEFAULT_VALUE_DELIMITER);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param variableResolver  the variable resolver, may be null
+     * @param prefix  the prefix for variables, not null
+     * @param suffix  the suffix for variables, not null
+     * @param escape  the escape character
+     * @param valueDelimiter  the variable default value delimiter string, may be null
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public StrSubstitutor(final StrLookup<?> variableResolver, final String prefix, final String suffix,
+                          final char escape, final String valueDelimiter) {
+        this.setVariableResolver(variableResolver);
+        this.setVariablePrefix(prefix);
+        this.setVariableSuffix(suffix);
+        this.setEscapeChar(escape);
+        this.setValueDelimiter(valueDelimiter);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param variableResolver  the variable resolver, may be null
+     * @param prefixMatcher  the prefix for variables, not null
+     * @param suffixMatcher  the suffix for variables, not null
+     * @param escape  the escape character
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public StrSubstitutor(
+            final StrLookup<?> variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher,
+            final char escape) {
+        this(variableResolver, prefixMatcher, suffixMatcher, escape, DEFAULT_VALUE_DELIMITER);
+    }
+
+    /**
+     * Creates a new instance and initializes it.
+     *
+     * @param variableResolver  the variable resolver, may be null
+     * @param prefixMatcher  the prefix for variables, not null
+     * @param suffixMatcher  the suffix for variables, not null
+     * @param escape  the escape character
+     * @param valueDelimiterMatcher  the variable default value delimiter matcher, may be null
+     * @throws IllegalArgumentException if the prefix or suffix is null
+     */
+    public StrSubstitutor(
+            final StrLookup<?> variableResolver, final StrMatcher prefixMatcher, final StrMatcher suffixMatcher,
+            final char escape, final StrMatcher valueDelimiterMatcher) {
+        this.setVariableResolver(variableResolver);
+        this.setVariablePrefixMatcher(prefixMatcher);
+        this.setVariableSuffixMatcher(suffixMatcher);
+        this.setEscapeChar(escape);
+        this.setValueDelimiterMatcher(valueDelimiterMatcher);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source string as a template.
+     *
+     * @param source  the string to replace in, null returns null
+     * @return the result of the replace operation
+     */
+    public String replace(final String source) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(source);
+        if (substitute(buf, 0, source.length()) == false) {
+            return source;
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source string as a template.
+     * <p>
+     * Only the specified portion of the string will be processed.
+     * The rest of the string is not processed, and is not returned.
+     *
+     * @param source  the string to replace in, null returns null
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the array to be processed, must be valid
+     * @return the result of the replace operation
+     */
+    public String replace(final String source, final int offset, final int length) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        if (substitute(buf, 0, length) == false) {
+            return source.substring(offset, offset + length);
+        }
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source array as a template.
+     * The array is not altered by this method.
+     *
+     * @param source  the character array to replace in, not altered, null returns null
+     * @return the result of the replace operation
+     */
+    public String replace(final char[] source) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(source.length).append(source);
+        substitute(buf, 0, source.length);
+        return buf.toString();
+    }
+
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source array as a template.
+     * The array is not altered by this method.
+     * <p>
+     * Only the specified portion of the array will be processed.
+     * The rest of the array is not processed, and is not returned.
+     *
+     * @param source  the character array to replace in, not altered, null returns null
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the array to be processed, must be valid
+     * @return the result of the replace operation
+     */
+    public String replace(final char[] source, final int offset, final int length) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        substitute(buf, 0, length);
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source buffer as a template.
+     * The buffer is not altered by this method.
+     *
+     * @param source  the buffer to use as a template, not changed, null returns null
+     * @return the result of the replace operation
+     */
+    public String replace(final StringBuffer source) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(source.length()).append(source);
+        substitute(buf, 0, buf.length());
+        return buf.toString();
+    }
+
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source buffer as a template.
+     * The buffer is not altered by this method.
+     * <p>
+     * Only the specified portion of the buffer will be processed.
+     * The rest of the buffer is not processed, and is not returned.
+     *
+     * @param source  the buffer to use as a template, not changed, null returns null
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the array to be processed, must be valid
+     * @return the result of the replace operation
+     */
+    public String replace(final StringBuffer source, final int offset, final int length) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        substitute(buf, 0, length);
+        return buf.toString();
+    }
+
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source as a template.
+     * The source is not altered by this method.
+     *
+     * @param source  the buffer to use as a template, not changed, null returns null
+     * @return the result of the replace operation
+     */
+    public String replace(final CharSequence source) {
+        if (source == null) {
+            return null;
+        }
+        return replace(source, 0, source.length());
+    }
+
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source as a template.
+     * The source is not altered by this method.
+     * <p>
+     * Only the specified portion of the buffer will be processed.
+     * The rest of the buffer is not processed, and is not returned.
+     *
+     * @param source  the buffer to use as a template, not changed, null returns null
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the array to be processed, must be valid
+     * @return the result of the replace operation
+     */
+    public String replace(final CharSequence source, final int offset, final int length) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        substitute(buf, 0, length);
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source builder as a template.
+     * The builder is not altered by this method.
+     *
+     * @param source  the builder to use as a template, not changed, null returns null
+     * @return the result of the replace operation
+     */
+    public String replace(final StrBuilder source) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(source.length()).append(source);
+        substitute(buf, 0, buf.length());
+        return buf.toString();
+    }
+
+    /**
+     * Replaces all the occurrences of variables with their matching values
+     * from the resolver using the given source builder as a template.
+     * The builder is not altered by this method.
+     * <p>
+     * Only the specified portion of the builder will be processed.
+     * The rest of the builder is not processed, and is not returned.
+     *
+     * @param source  the builder to use as a template, not changed, null returns null
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the array to be processed, must be valid
+     * @return the result of the replace operation
+     */
+    public String replace(final StrBuilder source, final int offset, final int length) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        substitute(buf, 0, length);
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables in the given source object with
+     * their matching values from the resolver. The input source object is
+     * converted to a string using <code>toString</code> and is not altered.
+     *
+     * @param source  the source to replace in, null returns null
+     * @return the result of the replace operation
+     */
+    public String replace(final Object source) {
+        if (source == null) {
+            return null;
+        }
+        final StrBuilder buf = new StrBuilder().append(source);
+        substitute(buf, 0, buf.length());
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables within the given source buffer
+     * with their matching values from the resolver.
+     * The buffer is updated with the result.
+     *
+     * @param source  the buffer to replace in, updated, null returns zero
+     * @return true if altered
+     */
+    public boolean replaceIn(final StringBuffer source) {
+        if (source == null) {
+            return false;
+        }
+        return replaceIn(source, 0, source.length());
+    }
+
+    /**
+     * Replaces all the occurrences of variables within the given source buffer
+     * with their matching values from the resolver.
+     * The buffer is updated with the result.
+     * <p>
+     * Only the specified portion of the buffer will be processed.
+     * The rest of the buffer is not processed, but it is not deleted.
+     *
+     * @param source  the buffer to replace in, updated, null returns zero
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the buffer to be processed, must be valid
+     * @return true if altered
+     */
+    public boolean replaceIn(final StringBuffer source, final int offset, final int length) {
+        if (source == null) {
+            return false;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        if (substitute(buf, 0, length) == false) {
+            return false;
+        }
+        source.replace(offset, offset + length, buf.toString());
+        return true;
+    }
+
+  //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables within the given source buffer
+     * with their matching values from the resolver.
+     * The buffer is updated with the result.
+     *
+     * @param source  the buffer to replace in, updated, null returns zero
+     * @return true if altered
+     */
+    public boolean replaceIn(final StringBuilder source) {
+        if (source == null) {
+            return false;
+        }
+        return replaceIn(source, 0, source.length());
+    }
+
+    /**
+     * Replaces all the occurrences of variables within the given source builder
+     * with their matching values from the resolver.
+     * The builder is updated with the result.
+     * <p>
+     * Only the specified portion of the buffer will be processed.
+     * The rest of the buffer is not processed, but it is not deleted.
+     *
+     * @param source  the buffer to replace in, updated, null returns zero
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the buffer to be processed, must be valid
+     * @return true if altered
+     */
+    public boolean replaceIn(final StringBuilder source, final int offset, final int length) {
+        if (source == null) {
+            return false;
+        }
+        final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
+        if (substitute(buf, 0, length) == false) {
+            return false;
+        }
+        source.replace(offset, offset + length, buf.toString());
+        return true;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Replaces all the occurrences of variables within the given source
+     * builder with their matching values from the resolver.
+     *
+     * @param source  the builder to replace in, updated, null returns zero
+     * @return true if altered
+     */
+    public boolean replaceIn(final StrBuilder source) {
+        if (source == null) {
+            return false;
+        }
+        return substitute(source, 0, source.length());
+    }
+
+    /**
+     * Replaces all the occurrences of variables within the given source
+     * builder with their matching values from the resolver.
+     * <p>
+     * Only the specified portion of the builder will be processed.
+     * The rest of the builder is not processed, but it is not deleted.
+     *
+     * @param source  the builder to replace in, null returns zero
+     * @param offset  the start offset within the array, must be valid
+     * @param length  the length within the builder to be processed, must be valid
+     * @return true if altered
+     */
+    public boolean replaceIn(final StrBuilder source, final int offset, final int length) {
+        if (source == null) {
+            return false;
+        }
+        return substitute(source, offset, length);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Internal method that substitutes the variables.
+     * <p>
+     * Most users of this class do not need to call this method. This method will
+     * be called automatically by another (public) method.
+     * <p>
+     * Writers of subclasses can override this method if they need access to
+     * the substitution process at the start or end.
+     *
+     * @param buf  the string builder to substitute into, not null
+     * @param offset  the start offset within the builder, must be valid
+     * @param length  the length within the builder to be processed, must be valid
+     * @return true if altered
+     */
+    protected boolean substitute(final StrBuilder buf, final int offset, final int length) {
+        return substitute(buf, offset, length, null) > 0;
+    }
+
+    /**
+     * Recursive handler for multiple levels of interpolation. This is the main
+     * interpolation method, which resolves the values of all variable references
+     * contained in the passed in text.
+     *
+     * @param buf  the string builder to substitute into, not null
+     * @param offset  the start offset within the builder, must be valid
+     * @param length  the length within the builder to be processed, must be valid
+     * @param priorVariables  the stack keeping track of the replaced variables, may be null
+     * @return the length change that occurs, unless priorVariables is null when the int
+     *  represents a boolean flag as to whether any change occurred.
+     */
+    private int substitute(final StrBuilder buf, final int offset, final int length, List<String> priorVariables) {
+        final StrMatcher pfxMatcher = getVariablePrefixMatcher();
+        final StrMatcher suffMatcher = getVariableSuffixMatcher();
+        final char escape = getEscapeChar();
+        final StrMatcher valueDelimMatcher = getValueDelimiterMatcher();
+        final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables();
+
+        final boolean top = priorVariables == null;
+        boolean altered = false;
+        int lengthChange = 0;
+        char[] chars = buf.buffer;
+        int bufEnd = offset + length;
+        int pos = offset;
+        while (pos < bufEnd) {
+            final int startMatchLen = pfxMatcher.isMatch(chars, pos, offset,
+                    bufEnd);
+            if (startMatchLen == 0) {
+                pos++;
+            } else {
+                // found variable start marker
+                if (pos > offset && chars[pos - 1] == escape) {
+                    // escaped
+                    if (preserveEscapes) {
+                        pos++;
+                        continue;
+                    }
+                    buf.deleteCharAt(pos - 1);
+                    chars = buf.buffer; // in case buffer was altered
+                    lengthChange--;
+                    altered = true;
+                    bufEnd--;
+                } else {
+                    // find suffix
+                    final int startPos = pos;
+                    pos += startMatchLen;
+                    int endMatchLen = 0;
+                    int nestedVarCount = 0;
+                    while (pos < bufEnd) {
+                        if (substitutionInVariablesEnabled
+                                && (endMatchLen = pfxMatcher.isMatch(chars,
+                                        pos, offset, bufEnd)) != 0) {
+                            // found a nested variable start
+                            nestedVarCount++;
+                            pos += endMatchLen;
+                            continue;
+                        }
+
+                        endMatchLen = suffMatcher.isMatch(chars, pos, offset,
+                                bufEnd);
+                        if (endMatchLen == 0) {
+                            pos++;
+                        } else {
+                            // found variable end marker
+                            if (nestedVarCount == 0) {
+                                String varNameExpr = new String(chars, startPos
+                                        + startMatchLen, pos - startPos
+                                        - startMatchLen);
+                                if (substitutionInVariablesEnabled) {
+                                    final StrBuilder bufName = new StrBuilder(varNameExpr);
+                                    substitute(bufName, 0, bufName.length());
+                                    varNameExpr = bufName.toString();
+                                }
+                                pos += endMatchLen;
+                                final int endPos = pos;
+
+                                String varName = varNameExpr;
+                                String varDefaultValue = null;
+
+                                if (valueDelimMatcher != null) {
+                                    final char [] varNameExprChars = varNameExpr.toCharArray();
+                                    int valueDelimiterMatchLen = 0;
+                                    for (int i = 0; i < varNameExprChars.length; i++) {
+                                        // if there's any nested variable when nested variable substitution disabled, then stop resolving name and default value.
+                                        if (!substitutionInVariablesEnabled
+                                                && pfxMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) {
+                                            break;
+                                        }
+                                        if ((valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, i)) != 0) {
+                                            varName = varNameExpr.substring(0, i);
+                                            varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
+                                            break;
+                                        }
+                                    }
+                                }
+
+                                // on the first call initialize priorVariables
+                                if (priorVariables == null) {
+                                    priorVariables = new ArrayList<>();
+                                    priorVariables.add(new String(chars,
+                                            offset, length));
+                                }
+
+                                // handle cyclic substitution
+                                checkCyclicSubstitution(varName, priorVariables);
+                                priorVariables.add(varName);
+
+                                // resolve the variable
+                                String varValue = resolveVariable(varName, buf,
+                                        startPos, endPos);
+                                if (varValue == null) {
+                                    varValue = varDefaultValue;
+                                }
+                                if (varValue != null) {
+                                    // recursive replace
+                                    final int varLen = varValue.length();
+                                    buf.replace(startPos, endPos, varValue);
+                                    altered = true;
+                                    int change = substitute(buf, startPos,
+                                            varLen, priorVariables);
+                                    change = change
+                                            + varLen - (endPos - startPos);
+                                    pos += change;
+                                    bufEnd += change;
+                                    lengthChange += change;
+                                    chars = buf.buffer; // in case buffer was
+                                                        // altered
+                                }
+
+                                // remove variable from the cyclic stack
+                                priorVariables
+                                        .remove(priorVariables.size() - 1);
+                                break;
+                            }
+                            nestedVarCount--;
+                            pos += endMatchLen;
+                        }
+                    }
+                }
+            }
+        }
+        if (top) {
+            return altered ? 1 : 0;
+        }
+        return lengthChange;
+    }
+
+    /**
+     * Checks if the specified variable is already in the stack (list) of variables.
+     *
+     * @param varName  the variable name to check
+     * @param priorVariables  the list of prior variables
+     */
+    private void checkCyclicSubstitution(final String varName, final List<String> priorVariables) {
+        if (priorVariables.contains(varName) == false) {
+            return;
+        }
+        final StrBuilder buf = new StrBuilder(256);
+        buf.append("Infinite loop in property interpolation of ");
+        buf.append(priorVariables.remove(0));
+        buf.append(": ");
+        buf.appendWithSeparators(priorVariables, "->");
+        throw new IllegalStateException(buf.toString());
+    }
+
+    /**
+     * Internal method that resolves the value of a variable.
+     * <p>
+     * Most users of this class do not need to call this method. This method is
+     * called automatically by the substitution process.
+     * <p>
+     * Writers of subclasses can override this method if they need to alter
+     * how each substitution occurs. The method is passed the variable's name
+     * and must return the corresponding value. This implementation uses the
+     * {@link #getVariableResolver()} with the variable's name as the key.
+     *
+     * @param variableName  the name of the variable, not null
+     * @param buf  the buffer where the substitution is occurring, not null
+     * @param startPos  the start position of the variable including the prefix, valid
+     * @param endPos  the end position of the variable including the suffix, valid
+     * @return the variable's value or <b>null</b> if the variable is unknown
+     */
+    protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) {
+        final StrLookup<?> resolver = getVariableResolver();
+        if (resolver == null) {
+            return null;
+        }
+        return resolver.lookup(variableName);
+    }
+
+    // Escape
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the escape character.
+     *
+     * @return the character used for escaping variable references
+     */
+    public char getEscapeChar() {
+        return this.escapeChar;
+    }
+
+    /**
+     * Sets the escape character.
+     * If this character is placed before a variable reference in the source
+     * text, this variable will be ignored.
+     *
+     * @param escapeCharacter  the escape character (0 for disabling escaping)
+     */
+    public void setEscapeChar(final char escapeCharacter) {
+        this.escapeChar = escapeCharacter;
+    }
+
+    // Prefix
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the variable prefix matcher currently in use.
+     * <p>
+     * The variable prefix is the characer or characters that identify the
+     * start of a variable. This prefix is expressed in terms of a matcher
+     * allowing advanced prefix matches.
+     *
+     * @return the prefix matcher in use
+     */
+    public StrMatcher getVariablePrefixMatcher() {
+        return prefixMatcher;
+    }
+
+    /**
+     * Sets the variable prefix matcher currently in use.
+     * <p>
+     * The variable prefix is the characer or characters that identify the
+     * start of a variable. This prefix is expressed in terms of a matcher
+     * allowing advanced prefix matches.
+     *
+     * @param prefixMatcher  the prefix matcher to use, null ignored
+     * @return this, to enable chaining
+     * @throws IllegalArgumentException if the prefix matcher is null
+     */
+    public StrSubstitutor setVariablePrefixMatcher(final StrMatcher prefixMatcher) {
+        if (prefixMatcher == null) {
+            throw new IllegalArgumentException("Variable prefix matcher must not be null!");
+        }
+        this.prefixMatcher = prefixMatcher;
+        return this;
+    }
+
+    /**
+     * Sets the variable prefix to use.
+     * <p>
+     * The variable prefix is the character or characters that identify the
+     * start of a variable. This method allows a single character prefix to
+     * be easily set.
+     *
+     * @param prefix  the prefix character to use
+     * @return this, to enable chaining
+     */
+    public StrSubstitutor setVariablePrefix(final char prefix) {
+        return setVariablePrefixMatcher(StrMatcher.charMatcher(prefix));
+    }
+
+    /**
+     * Sets the variable prefix to use.
+     * <p>
+     * The variable prefix is the characer or characters that identify the
+     * start of a variable. This method allows a string prefix to be easily set.
+     *
+     * @param prefix  the prefix for variables, not null
+     * @return this, to enable chaining
+     * @throws IllegalArgumentException if the prefix is null
+     */
+    public StrSubstitutor setVariablePrefix(final String prefix) {
+       if (prefix == null) {
+            throw new IllegalArgumentException("Variable prefix must not be null!");
+        }
+        return setVariablePrefixMatcher(StrMatcher.stringMatcher(prefix));
+    }
+
+    // Suffix
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the variable suffix matcher currently in use.
+     * <p>
+     * The variable suffix is the characer or characters that identify the
+     * end of a variable. This suffix is expressed in terms of a matcher
+     * allowing advanced suffix matches.
+     *
+     * @return the suffix matcher in use
+     */
+    public StrMatcher getVariableSuffixMatcher() {
+        return suffixMatcher;
+    }
+
+    /**
+     * Sets the variable suffix matcher currently in use.
+     * <p>
+     * The variable suffix is the characer or characters that identify the
+     * end of a variable. This suffix is expressed in terms of a matcher
+     * allowing advanced suffix matches.
+     *
+     * @param suffixMatcher  the suffix matcher to use, null ignored
+     * @return this, to enable chaining
+     * @throws IllegalArgumentException if the suffix matcher is null
+     */
+    public StrSubstitutor setVariableSuffixMatcher(final StrMatcher suffixMatcher) {
+        if (suffixMatcher == null) {
+            throw new IllegalArgumentException("Variable suffix matcher must not be null!");
+        }
+        this.suffixMatcher = suffixMatcher;
+        return this;
+    }
+
+    /**
+     * Sets the variable suffix to use.
+     * <p>
+     * The variable suffix is the characer or characters that identify the
+     * end of a variable. This method allows a single character suffix to
+     * be easily set.
+     *
+     * @param suffix  the suffix character to use
+     * @return this, to enable chaining
+     */
+    public StrSubstitutor setVariableSuffix(final char suffix) {
+        return setVariableSuffixMatcher(StrMatcher.charMatcher(suffix));
+    }
+
+    /**
+     * Sets the variable suffix to use.
+     * <p>
+     * The variable suffix is the character or characters that identify the
+     * end of a variable. This method allows a string suffix to be easily set.
+     *
+     * @param suffix  the suffix for variables, not null
+     * @return this, to enable chaining
+     * @throws IllegalArgumentException if the suffix is null
+     */
+    public StrSubstitutor setVariableSuffix(final String suffix) {
+       if (suffix == null) {
+            throw new IllegalArgumentException("Variable suffix must not be null!");
+        }
+        return setVariableSuffixMatcher(StrMatcher.stringMatcher(suffix));
+    }
+
+    // Variable Default Value Delimiter
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the variable default value delimiter matcher currently in use.
+     * <p>
+     * The variable default value delimiter is the characer or characters that delimite the
+     * variable name and the variable default value. This delimiter is expressed in terms of a matcher
+     * allowing advanced variable default value delimiter matches.
+     * <p>
+     * If it returns null, then the variable default value resolution is disabled.
+     *
+     * @return the variable default value delimiter matcher in use, may be null
+     */
+    public StrMatcher getValueDelimiterMatcher() {
+        return valueDelimiterMatcher;
+    }
+
+    /**
+     * Sets the variable default value delimiter matcher to use.
+     * <p>
+     * The variable default value delimiter is the characer or characters that delimite the
+     * variable name and the variable default value. This delimiter is expressed in terms of a matcher
+     * allowing advanced variable default value delimiter matches.
+     * <p>
+     * If the <code>valueDelimiterMatcher</code> is null, then the variable default value resolution
+     * becomes disabled.
+     *
+     * @param valueDelimiterMatcher  variable default value delimiter matcher to use, may be null
+     * @return this, to enable chaining
+     */
+    public StrSubstitutor setValueDelimiterMatcher(final StrMatcher valueDelimiterMatcher) {
+        this.valueDelimiterMatcher = valueDelimiterMatcher;
+        return this;
+    }
+
+    /**
+     * Sets the variable default value delimiter to use.
+     * <p>
+     * The variable default value delimiter is the characer or characters that delimite the
+     * variable name and the variable default value. This method allows a single character
+     * variable default value delimiter to be easily set.
+     *
+     * @param valueDelimiter  the variable default value delimiter character to use
+     * @return this, to enable chaining
+     */
+    public StrSubstitutor setValueDelimiter(final char valueDelimiter) {
+        return setValueDelimiterMatcher(StrMatcher.charMatcher(valueDelimiter));
+    }
+
+    /**
+     * Sets the variable default value delimiter to use.
+     * <p>
+     * The variable default value delimiter is the characer or characters that delimite the
+     * variable name and the variable default value. This method allows a string
+     * variable default value delimiter to be easily set.
+     * <p>
+     * If the <code>valueDelimiter</code> is null or empty string, then the variable default
+     * value resolution becomes disabled.
+     *
+     * @param valueDelimiter  the variable default value delimiter string to use, may be null or empty
+     * @return this, to enable chaining
+     */
+    public StrSubstitutor setValueDelimiter(final String valueDelimiter) {
+        if (valueDelimiter == null || valueDelimiter.length() == 0) {
+            setValueDelimiterMatcher(null);
+            return this;
+        }
+        return setValueDelimiterMatcher(StrMatcher.stringMatcher(valueDelimiter));
+    }
+
+    // Resolver
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the VariableResolver that is used to lookup variables.
+     *
+     * @return the VariableResolver
+     */
+    public StrLookup<?> getVariableResolver() {
+        return this.variableResolver;
+    }
+
+    /**
+     * Sets the VariableResolver that is used to lookup variables.
+     *
+     * @param variableResolver  the VariableResolver
+     */
+    public void setVariableResolver(final StrLookup<?> variableResolver) {
+        this.variableResolver = variableResolver;
+    }
+
+    // Substitution support in variable names
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a flag whether substitution is done in variable names.
+     *
+     * @return the substitution in variable names flag
+     */
+    public boolean isEnableSubstitutionInVariables() {
+        return enableSubstitutionInVariables;
+    }
+
+    /**
+     * Sets a flag whether substitution is done in variable names. If set to
+     * <b>true</b>, the names of variables can contain other variables which are
+     * processed first before the original variable is evaluated, e.g.
+     * <code>${jre-${java.version}}</code>. The default value is <b>false</b>.
+     *
+     * @param enableSubstitutionInVariables the new value of the flag
+     */
+    public void setEnableSubstitutionInVariables(
+            final boolean enableSubstitutionInVariables) {
+        this.enableSubstitutionInVariables = enableSubstitutionInVariables;
+    }
+
+    /**
+     * Returns the flag controlling whether escapes are preserved during
+     * substitution.
+     * 
+     * @return the preserve escape flag
+     */
+    public boolean isPreserveEscapes() {
+        return preserveEscapes;
+    }
+
+    /**
+     * Sets a flag controlling whether escapes are preserved during
+     * substitution.  If set to <b>true</b>, the escape character is retained
+     * during substitution (e.g. <code>$${this-is-escaped}</code> remains
+     * <code>$${this-is-escaped}</code>).  If set to <b>false</b>, the escape
+     * character is removed during substitution (e.g.
+     * <code>$${this-is-escaped}</code> becomes
+     * <code>${this-is-escaped}</code>).  The default value is <b>false</b>
+     * 
+     * @param preserveEscapes true if escapes are to be preserved
+     */
+    public void setPreserveEscapes(final boolean preserveEscapes) {
+        this.preserveEscapes = preserveEscapes;
+    }
+}


[43/50] [abbrv] [text] TEXT-69: Upgrade to maven-pmd-plugin:3.7 from 3.2

Posted by ch...@apache.org.
TEXT-69: Upgrade to maven-pmd-plugin:3.7 from 3.2


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/0ccf70e3
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/0ccf70e3
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/0ccf70e3

Branch: refs/heads/release
Commit: 0ccf70e36d339240bcd4cdd83db176d59d6cdf94
Parents: a0077dd
Author: Rob Tompkins <ch...@apache.org>
Authored: Wed Feb 22 12:55:35 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Wed Feb 22 12:55:35 2017 -0500

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/0ccf70e3/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index dc2bc80..4b08b4b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -235,7 +235,7 @@
       </plugin>
       <plugin>
         <artifactId>maven-pmd-plugin</artifactId>
-        <version>3.2</version>
+        <version>3.7</version>
         <configuration>
           <targetJdk>${maven.compiler.target}</targetJdk>
         </configuration>


[32/50] [abbrv] [text] TEXT-65: 25 checkstyle errors

Posted by ch...@apache.org.
TEXT-65: 25 checkstyle errors


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/3e075846
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/3e075846
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/3e075846

Branch: refs/heads/release
Commit: 3e07584624c170cc703a673b2ec6ee49c57fba08
Parents: df0658f
Author: Rob Tompkins <ch...@apache.org>
Authored: Mon Feb 13 08:37:30 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Mon Feb 13 08:37:30 2017 -0500

----------------------------------------------------------------------
 checkstyle-suppressions.xml                     | 17 +++++++
 .../text/translate/CodePointTranslator.java     | 14 +++---
 .../commons/text/translate/CsvTranslators.java  | 10 +++-
 .../commons/text/translate/EntityArrays.java    |  4 +-
 .../text/translate/JavaUnicodeEscaper.java      | 14 +++---
 .../text/translate/LookupTranslator.java        |  8 +++-
 .../text/translate/NumericEntityEscaper.java    |  5 +-
 .../text/translate/NumericEntityUnescaper.java  | 50 ++++++++++----------
 .../commons/text/translate/OctalUnescaper.java  | 14 +++---
 .../text/translate/SingleLookupTranslator.java  |  8 +++-
 .../text/translate/SinglePassTranslator.java    | 10 ++--
 11 files changed, 98 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/checkstyle-suppressions.xml
----------------------------------------------------------------------
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
index d6634e3..cc03b22 100644
--- a/checkstyle-suppressions.xml
+++ b/checkstyle-suppressions.xml
@@ -25,15 +25,32 @@
   <suppress checks="DesignForExtension" files=".+\.java" lines="0-99999" />
   <suppress checks="HideUtilityClassConstructor" files=".+\.java" lines="0-99999" />
   <suppress checks="VisibilityModifier" files=".+\.java" lines="0-99999" />
+
   <suppress checks="EmptyBlock" files="ExtendedMessageFormat.java" lines="0-99999" />
+
   <suppress checks="LocalFinalVariableName" files="FormattableUtils.java" lines="0-99999" />
+
   <suppress checks="MagicNumber" files="JaccardDistance.java" lines="0-99999" />
+
   <suppress checks="MagicNumber" files="JaccardSimilarity.java" lines="0-99999" />
+
   <suppress checks="MagicNumber" files="JaroWinklerDistance.java" lines="0-99999" />
   <suppress checks="NoWhitespaceAfter" files="JaroWinklerDistance.java" lines="0-99999" />
+
   <suppress checks="FileLength" files="StrBuilder.java" lines="0-99999" />
   <suppress checks="MagicNumber" files="StrBuilder.java" lines="0-99999" />
+
   <suppress checks="MagicNumber" files="StringEscapeUtils.java" lines="0-99999" />
+
   <suppress checks="EmptyBlock" files="StrLookup.java" lines="0-99999" />
+
   <suppress checks="MagicNumber" files="StrMatcher.java" lines="0-99999" />
+
+  <suppress checks="LocalVariableName" files="LookupTranslator.java" lines="0-99999" />
+
+  <suppress checks="MagicNumber" files="NumericEntityEscaper.java" lines="0-99999" />
+
+  <suppress checks="MagicNumber" files="NumericEntityUnescaper.java" lines="0-99999" />
+
+  <suppress checks="MagicNumber" files="OctalUnescaper.java" lines="0-99999" />
 </suppressions>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java b/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
index 3318261..71828be 100644
--- a/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/CodePointTranslator.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,7 +20,7 @@ import java.io.IOException;
 import java.io.Writer;
 
 /**
- * Helper subclass to CharSequenceTranslator to allow for translations that 
+ * Helper subclass to CharSequenceTranslator to allow for translations that
  * will replace up to one character at a time.
  *
  * @since 1.0
@@ -28,19 +28,19 @@ import java.io.Writer;
 public abstract class CodePointTranslator extends CharSequenceTranslator {
 
     /**
-     * Implementation of translate that maps onto the abstract translate(int, Writer) method. 
+     * Implementation of translate that maps onto the abstract translate(int, Writer) method.
      * {@inheritDoc}
      */
     @Override
     public final int translate(final CharSequence input, final int index, final Writer out) throws IOException {
         final int codepoint = Character.codePointAt(input, index);
         final boolean consumed = translate(codepoint, out);
-        return consumed ? 1 : 0; 
+        return consumed ? 1 : 0;
     }
 
     /**
-     * Translate the specified codepoint into another. 
-     * 
+     * Translate the specified codepoint into another.
+     *
      * @param codepoint int character input to translate
      * @param out Writer to optionally push the translated output to
      * @return boolean as to whether translation occurred or not

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/CsvTranslators.java b/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
index f11b9fe..a7a98e4 100644
--- a/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
+++ b/src/main/java/org/apache/commons/text/translate/CsvTranslators.java
@@ -25,15 +25,21 @@ import java.io.Writer;
 /**
  * This class holds inner classes for escaping/unescaping Comma Separated Values.
  */
-public class CsvTranslators {
+public final class CsvTranslators {
 
+    /** Comma character. */
     private static final char CSV_DELIMITER = ',';
+    /** Quote character. */
     private static final char CSV_QUOTE = '"';
+    /** Quote character converted to string. */
     private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE);
+    /** Escaped quote string. */
     private static final String CSV_ESCAPED_QUOTE_STR = CSV_QUOTE_STR + CSV_QUOTE_STR;
+    /** CSV key characters in an array. */
     private static final char[] CSV_SEARCH_CHARS =
             new char[] {CSV_DELIMITER, CSV_QUOTE, CharUtils.CR, CharUtils.LF};
 
+    /** Hidden constructor. */
     private CsvTranslators() { }
 
     /**
@@ -79,4 +85,4 @@ public class CsvTranslators {
             }
         }
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/EntityArrays.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/EntityArrays.java b/src/main/java/org/apache/commons/text/translate/EntityArrays.java
index f5876f2..f314386 100644
--- a/src/main/java/org/apache/commons/text/translate/EntityArrays.java
+++ b/src/main/java/org/apache/commons/text/translate/EntityArrays.java
@@ -390,7 +390,7 @@ public class EntityArrays {
     public static final Map<CharSequence, CharSequence> APOS_ESCAPE;
     static {
         Map<CharSequence, CharSequence> initialMap = new HashMap<>();
-        initialMap.put("'","&apos;"); // XML apostrophe
+        initialMap.put("'", "&apos;"); // XML apostrophe
         APOS_ESCAPE = Collections.unmodifiableMap(initialMap);
     }
 
@@ -428,7 +428,7 @@ public class EntityArrays {
     }
 
     /**
-     * Used to invert an escape Map into an unescape Map
+     * Used to invert an escape Map into an unescape Map.
      * @param map Map&lt;String, String&gt; to be inverted
      * @return Map&lt;String, String&gt; inverted array
      */

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java b/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
index 22549fa..b4b3aac 100644
--- a/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
+++ b/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
@@ -27,7 +27,7 @@ public class JavaUnicodeEscaper extends UnicodeEscaper {
      * <p>
      * Constructs a <code>JavaUnicodeEscaper</code> above the specified value (exclusive).
      * </p>
-     * 
+     *
      * @param codepoint
      *            above which to escape
      * @return the newly created {@code UnicodeEscaper} instance
@@ -40,7 +40,7 @@ public class JavaUnicodeEscaper extends UnicodeEscaper {
      * <p>
      * Constructs a <code>JavaUnicodeEscaper</code> below the specified value (exclusive).
      * </p>
-     * 
+     *
      * @param codepoint
      *            below which to escape
      * @return the newly created {@code UnicodeEscaper} instance
@@ -53,7 +53,7 @@ public class JavaUnicodeEscaper extends UnicodeEscaper {
      * <p>
      * Constructs a <code>JavaUnicodeEscaper</code> between the specified values (inclusive).
      * </p>
-     * 
+     *
      * @param codepointLow
      *            above which to escape
      * @param codepointHigh
@@ -68,7 +68,7 @@ public class JavaUnicodeEscaper extends UnicodeEscaper {
      * <p>
      * Constructs a <code>JavaUnicodeEscaper</code> outside of the specified values (exclusive).
      * </p>
-     * 
+     *
      * @param codepointLow
      *            below which to escape
      * @param codepointHigh
@@ -85,7 +85,7 @@ public class JavaUnicodeEscaper extends UnicodeEscaper {
      * other constructors/builders. The <code>below</code> and <code>above</code> boundaries are inclusive when
      * <code>between</code> is <code>true</code> and exclusive when it is <code>false</code>.
      * </p>
-     * 
+     *
      * @param below
      *            int value representing the lowest codepoint boundary
      * @param above
@@ -98,8 +98,8 @@ public class JavaUnicodeEscaper extends UnicodeEscaper {
     }
 
     /**
-     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX\\uXXXX"}
-     * 
+     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX\\uXXXX"}.
+     *
      * @param codepoint
      *            a Unicode code point
      * @return the hex string for the given codepoint

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/LookupTranslator.java b/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
index ab3a7f6..51cafd9 100644
--- a/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -31,9 +31,13 @@ import java.util.Map;
  */
 public class LookupTranslator extends CharSequenceTranslator {
 
+    /** The mapping to be used in translation. */
     private final Map<String, String> lookupMap;
+    /** The first character of each key in the lookupMap. */
     private final HashSet<Character> prefixSet;
+    /** The length of the shortest key in the lookupMap. */
     private final int shortest;
+    /** The length of the longest key in the lookupMap. */
     private final int longest;
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
index a852964..0cdb808 100644
--- a/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
@@ -26,8 +26,11 @@ import java.io.Writer;
  */
 public class NumericEntityEscaper extends CodePointTranslator {
 
+    /** int value representing the lowest codepoint boundary. */
     private final int below;
+    /** int value representing the highest codepoint boundary. */
     private final int above;
+    /** whether to escape between the boundaries or outside them. */
     private final boolean between;
 
     /**
@@ -100,7 +103,7 @@ public class NumericEntityEscaper extends CodePointTranslator {
      */
     @Override
     public boolean translate(final int codepoint, final Writer out) throws IOException {
-        if(between) {
+        if (between) {
             if (codepoint < below || codepoint > above) {
                 return false;
             }

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
index 8b3d7c7..42b38ef 100644
--- a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ import java.util.Arrays;
 import java.util.EnumSet;
 
 /**
- * Translate XML numeric entities of the form &amp;#[xX]?\d+;? to 
+ * Translate XML numeric entities of the form &amp;#[xX]?\d+;? to
  * the specific codepoint.
  *
  * Note that the semi-colon is optional.
@@ -31,16 +31,18 @@ import java.util.EnumSet;
  */
 public class NumericEntityUnescaper extends CharSequenceTranslator {
 
+    /** NumericEntityUnescaper option enum. */
     public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
 
+    /** EnumSet of OPTIONS, given from the constructor. */
     // TODO?: Create an OptionsSet class to hide some of the conditional logic below
     private final EnumSet<OPTION> options;
 
     /**
      * Create a UnicodeUnescaper.
      *
-     * The constructor takes a list of options, only one type of which is currently 
-     * available (whether to allow, error or ignore the semi-colon on the end of a 
+     * The constructor takes a list of options, only one type of which is currently
+     * available (whether to allow, error or ignore the semi-colon on the end of a
      * numeric entity to being missing).
      *
      * For example, to support numeric entities without a ';':
@@ -48,15 +50,15 @@ public class NumericEntityUnescaper extends CharSequenceTranslator {
      * and to throw an IllegalArgumentException when they're missing:
      *    new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon)
      *
-     * Note that the default behaviour is to ignore them. 
+     * Note that the default behaviour is to ignore them.
      *
      * @param options to apply to this unescaper
      */
     public NumericEntityUnescaper(final OPTION... options) {
-        if(options.length > 0) {
+        if (options.length > 0) {
             this.options = EnumSet.copyOf(Arrays.asList(options));
         } else {
-            this.options = EnumSet.copyOf(Arrays.asList(new OPTION[] { OPTION.semiColonRequired }));
+            this.options = EnumSet.copyOf(Arrays.asList(new OPTION[] {OPTION.semiColonRequired}));
         }
     }
 
@@ -66,7 +68,7 @@ public class NumericEntityUnescaper extends CharSequenceTranslator {
      * @param option to check state of
      * @return whether the option is set
      */
-    public boolean isSet(final OPTION option) { 
+    public boolean isSet(final OPTION option) {
         return options == null ? false : options.contains(option);
     }
 
@@ -77,53 +79,53 @@ public class NumericEntityUnescaper extends CharSequenceTranslator {
     public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
         final int seqEnd = input.length();
         // Uses -2 to ensure there is something after the &#
-        if(input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
+        if (input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
             int start = index + 2;
             boolean isHex = false;
 
             final char firstChar = input.charAt(start);
-            if(firstChar == 'x' || firstChar == 'X') {
+            if (firstChar == 'x' || firstChar == 'X') {
                 start++;
                 isHex = true;
 
                 // Check there's more than just an x after the &#
-                if(start == seqEnd) {
+                if (start == seqEnd) {
                     return 0;
                 }
             }
 
             int end = start;
             // Note that this supports character codes without a ; on the end
-            while(end < seqEnd && ( input.charAt(end) >= '0' && input.charAt(end) <= '9' ||
-                                    input.charAt(end) >= 'a' && input.charAt(end) <= 'f' ||
-                                    input.charAt(end) >= 'A' && input.charAt(end) <= 'F' ) )
-            {
+            while (end < seqEnd && (input.charAt(end) >= '0' && input.charAt(end) <= '9'
+                                    || input.charAt(end) >= 'a' && input.charAt(end) <= 'f'
+                                    || input.charAt(end) >= 'A' && input.charAt(end) <= 'F')) {
                 end++;
             }
 
             final boolean semiNext = end != seqEnd && input.charAt(end) == ';';
 
-            if(!semiNext) {
-                if(isSet(OPTION.semiColonRequired)) {
+            if (!semiNext) {
+                if (isSet(OPTION.semiColonRequired)) {
                     return 0;
-                } else
-                if(isSet(OPTION.errorIfNoSemiColon)) {
-                    throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
+                } else {
+                    if (isSet(OPTION.errorIfNoSemiColon)) {
+                        throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
+                    }
                 }
             }
 
             int entityValue;
             try {
-                if(isHex) {
+                if (isHex) {
                     entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 16);
                 } else {
                     entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 10);
                 }
-            } catch(final NumberFormatException nfe) {
+            } catch (final NumberFormatException nfe) {
                 return 0;
             }
 
-            if(entityValue > 0xFFFF) {
+            if (entityValue > 0xFFFF) {
                 final char[] chrs = Character.toChars(entityValue);
                 out.write(chrs[0]);
                 out.write(chrs[1]);

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java b/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
index e49cdd5..0443128 100644
--- a/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
+++ b/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,7 +24,7 @@ import java.io.Writer;
  *
  * For example, "\45" should go back to being the specific value (a %).
  *
- * Note that this currently only supports the viable range of octal for Java; namely 
+ * Note that this currently only supports the viable range of octal for Java; namely
  * 1 to 377. This is because parsing Java is the main use case.
  *
  * @since 1.0
@@ -38,7 +38,7 @@ public class OctalUnescaper extends CharSequenceTranslator {
     public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
         final int remaining = input.length() - index - 1; // how many characters left, ignoring the first \
         final StringBuilder builder = new StringBuilder();
-        if(input.charAt(index) == '\\' && remaining > 0 && isOctalDigit(input.charAt(index + 1)) ) {
+        if (input.charAt(index) == '\\' && remaining > 0 && isOctalDigit(input.charAt(index + 1))) {
             final int next = index + 1;
             final int next2 = index + 2;
             final int next3 = index + 3;
@@ -46,14 +46,14 @@ public class OctalUnescaper extends CharSequenceTranslator {
             // we know this is good as we checked it in the if block above
             builder.append(input.charAt(next));
 
-            if(remaining > 1 && isOctalDigit(input.charAt(next2))) {
+            if (remaining > 1 && isOctalDigit(input.charAt(next2))) {
                 builder.append(input.charAt(next2));
-                if(remaining > 2 && isZeroToThree(input.charAt(next)) && isOctalDigit(input.charAt(next3))) {
+                if (remaining > 2 && isZeroToThree(input.charAt(next)) && isOctalDigit(input.charAt(next3))) {
                     builder.append(input.charAt(next3));
                 }
             }
 
-            out.write( Integer.parseInt(builder.toString(), 8) );
+            out.write(Integer.parseInt(builder.toString(), 8));
             return 1 + builder.length();
         }
         return 0;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java b/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
index 7af0579..8fafab8 100644
--- a/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
@@ -31,11 +31,17 @@ import java.util.Map;
  */
 public class SingleLookupTranslator extends CharSequenceTranslator {
 
+    /** The lookupMap to be used for translation. */
     private final Map<String, String> lookupMap;
+    /** The first character of each key in the lookupMap. */
     private final HashSet<Character> prefixSet;
+    /** The length of the shortest key in the lookupMap. */
     private final int shortest;
+    /** The length of the longest key in the lookupMap. */
     private final int longest;
+    /** The length of the shortest value in the lookupMap. */
     private final int shortestValue;
+    /** The length of the longest value in the lookupMap. */
     private final int longestValue;
 
     /**
@@ -51,7 +57,7 @@ public class SingleLookupTranslator extends CharSequenceTranslator {
      * lookup table passed to this instance while deciding whether a value is
      * already translated or not.
      *
-     * @param inputMaps, an array of Map&lt;CharSequence, CharSequence&gt;.
+     * @param inputMaps an array of Map&lt;CharSequence, CharSequence&gt;.
      */
     public SingleLookupTranslator(Map<CharSequence, CharSequence>... inputMaps) {
         Map<CharSequence, CharSequence> lookup = new HashMap<>();

http://git-wip-us.apache.org/repos/asf/commons-text/blob/3e075846/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java b/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
index 721e727..63bdde1 100644
--- a/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
+++ b/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
@@ -28,8 +28,8 @@ abstract class SinglePassTranslator extends CharSequenceTranslator {
     @Override
     public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
         if (index != 0) {
-            throw new IllegalArgumentException(getClassName() + ".translate(final CharSequence input, final int " +
-                    "index, final Writer out) can not handle a non-zero index.");
+            throw new IllegalArgumentException(getClassName() + ".translate(final CharSequence input, final int "
+                    + "index, final Writer out) can not handle a non-zero index.");
         }
 
         translateWhole(input, out);
@@ -37,6 +37,11 @@ abstract class SinglePassTranslator extends CharSequenceTranslator {
         return Character.codePointCount(input, index, input.length());
     }
 
+    /**
+     * A utility method to be used in the {@link #translate(CharSequence, int, Writer)} method.
+     *
+     * @return the name of this or the extending class.
+     */
     private String getClassName() {
         final Class<? extends SinglePassTranslator> clazz = this.getClass();
         return clazz.isAnonymousClass() ?  clazz.getName() : clazz.getSimpleName();
@@ -47,7 +52,6 @@ abstract class SinglePassTranslator extends CharSequenceTranslator {
      *
      * @param input CharSequence that is being translated
      * @param out Writer to translate the text to
-     * @return total count of codepoints in input
      * @throws IOException if and only if the Writer produces an IOException
      */
     abstract void translateWhole(final CharSequence input, final Writer out) throws IOException;


[07/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/diff/ReplacementsFinderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/diff/ReplacementsFinderTest.java b/src/test/java/org/apache/commons/text/beta/diff/ReplacementsFinderTest.java
deleted file mode 100644
index f5a8277..0000000
--- a/src/test/java/org/apache/commons/text/beta/diff/ReplacementsFinderTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-/**
- * Tests for the ReplacementsFinder.
- */
-@RunWith(Parameterized.class)
-public class ReplacementsFinderTest {
-    private SimpleHandler handler = null;
-    private final String left;
-    private final String right;
-    private final int skipped;
-    private final Character[] from;
-    private final Character[] to;
-    @Before
-    public void setUp() {
-        handler = new SimpleHandler();
-    }
-    @Parameters
-    public static Collection<Object[]> data() {
-        return Arrays.asList(new Object[][] {
-            {
-                "branco",
-                "blanco",
-                1,
-                new Character[] {'r'},
-                new Character[] {'l'}},
-            {
-                "test the blocks before you use it",
-                "try the blocks before you put it",
-                25,
-                new Character[] {'e', 's', 't', 's', 'e'},
-                new Character[] {'r', 'y', 'p', 't'}
-            }
-        });
-    }
-    public ReplacementsFinderTest(final String left, final String right, final int skipped,
-            final Character[] from, final Character[] to) {
-        this.left = left;
-        this.right = right;
-        this.skipped = skipped;
-        this.from = from;
-        this.to = to;
-    }
-    @Test
-    public void testReplacementsHandler() {
-        final StringsComparator sc = new StringsComparator(left, right);
-        final ReplacementsFinder<Character> replacementFinder = new ReplacementsFinder<>(handler);
-        sc.getScript().visit(replacementFinder);
-        assertEquals("Skipped characters do not match", skipped, handler.getSkipped());
-        assertArrayEquals("From characters do not match", from,
-                handler.getFrom().toArray(new Character[0]));
-        assertArrayEquals("To characters do not match", to,
-                handler.getTo().toArray(new Character[0]));
-    }
-    // Helper RecplacementsHandler implementation for testing
-    private class SimpleHandler implements ReplacementsHandler<Character> {
-        private int skipped;
-        private final List<Character> from;
-        private final List<Character> to;
-        public SimpleHandler() {
-            skipped = 0;
-            from = new ArrayList<>();
-            to = new ArrayList<>();
-        }
-        public int getSkipped() {
-            return skipped;
-        }
-        public List<Character> getFrom() {
-            return from;
-        }
-        public List<Character> getTo() {
-            return to;
-        }
-        @Override
-        public void handleReplacement(final int skipped, final List<Character> from, final List<Character> to) {
-            this.skipped += skipped;
-            this.from.addAll(from);
-            this.to.addAll(to);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/diff/StringsComparatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/diff/StringsComparatorTest.java b/src/test/java/org/apache/commons/text/beta/diff/StringsComparatorTest.java
deleted file mode 100644
index cb0fd3f..0000000
--- a/src/test/java/org/apache/commons/text/beta/diff/StringsComparatorTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.diff;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-/**
- * Tests for the StringsComparator.
- */
-public class StringsComparatorTest {
-    private List<String> before;
-    private List<String> after;
-    private int[]        length;
-    private int[]        lcs;
-    @Test
-    public void testLength() {
-        for (int i = 0; i < before.size(); ++i) {
-            final StringsComparator comparator =  new StringsComparator(before.get(i), after.get(i));
-            Assert.assertEquals(length[i], comparator.getScript().getModifications());
-        }
-    }
-    @Test
-    public void testLongestCommonSubsequence() {
-        for (int i = 0; i < before.size(); ++i) {
-            final StringsComparator comparator =  new StringsComparator(before.get(i), after.get(i));
-            Assert.assertEquals(lcs[i], comparator.getScript().getLCSLength());
-        }
-    }
-    @Test
-    public void testExecution() {
-        for (int i = 0; i < before.size(); ++i) {
-            final ExecutionVisitor<Character> ev = new ExecutionVisitor<>();
-            new StringsComparator(before.get(i), after.get(i)).getScript().visit(ev);
-            Assert.assertEquals(after.get(i), ev.getString());
-        }
-    }
-    private class ExecutionVisitor<T> implements CommandVisitor<T> {
-        private final StringBuilder v;
-        public ExecutionVisitor() {
-            v = new StringBuilder();
-        }
-        @Override
-        public void visitInsertCommand(final T object) {
-            v.append(object);
-        }
-        @Override
-        public void visitKeepCommand(final T object) {
-            v.append(object);
-        }
-        @Override
-        public void visitDeleteCommand(final T object) {
-        }
-        public String getString() {
-            return v.toString();
-        }
-    }
-    @Before
-    public void setUp() {
-        before = Arrays.asList(
-            "bottle",
-            "nematode knowledge",
-            "",
-            "aa",
-            "prefixed string",
-            "ABCABBA",
-            "glop glop",
-            "coq",
-            "spider-man");
-        after = Arrays.asList(
-            "noodle",
-            "empty bottle",
-            "",
-            "C",
-            "prefix",
-            "CBABAC",
-            "pas glop pas glop",
-            "ane",
-            "klingon");
-        length = new int[] {
-            6,
-            16,
-            0,
-            3,
-            9,
-            5,
-            8,
-            6,
-            13
-        };
-        lcs = new int[] {
-            3,
-            7,
-            0,
-            0,
-            6,
-            4,
-            9,
-            0,
-            2
-        };
-    }
-    @After
-    public void tearDown() {
-        before = null;
-        after  = null;
-        length = null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/CosineDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/CosineDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/CosineDistanceTest.java
deleted file mode 100644
index 65cb51a..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/CosineDistanceTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Unit tests for {@link CosineSimilarity}.
- */
-public class CosineDistanceTest {
-
-    /**
-     * Cosine distance under test.
-     */
-    private static CosineDistance cosineDistance;
-
-    /**
-     * Creates the cosine distance object used throughout the tests.
-     */
-    @BeforeClass
-    public static void setUp() {
-        cosineDistance = new CosineDistance();
-    }
-
-    /**
-     * Tests the cosine distance with several inputs.
-     */
-    @Test
-    public void testCosineDistance() {
-        assertEquals(Double.valueOf(0.5d), roundValue(cosineDistance.apply("the house", "da house")));
-        assertEquals(Double.valueOf(0.0d), roundValue(cosineDistance.apply("AB", "AB")));
-        assertEquals(Double.valueOf(1.0d), roundValue(cosineDistance.apply("AB", "BA")));
-        assertEquals(Double.valueOf(0.08d), roundValue(cosineDistance.apply(
-                "the boy was from tamana shi, kumamoto ken, and the girl was from rio de janeiro, rio",
-                "the boy was from tamana shi, kumamoto, and the boy was from rio de janeiro, rio de janeiro")));
-    }
-
-    // --- Utility methods
-
-    /**
-     * Rounds up a value.
-     *
-     * @param value a value
-     * @return rounded up value
-     */
-    private Double roundValue(final Double value) {
-        return (Double) new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/FuzzyScoreTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/FuzzyScoreTest.java b/src/test/java/org/apache/commons/text/beta/similarity/FuzzyScoreTest.java
deleted file mode 100644
index e1401ca..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/FuzzyScoreTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.Locale;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link FuzzyScore}.
- */
-public class FuzzyScoreTest {
-
-    private static final FuzzyScore ENGLISH_SCORE = new FuzzyScore(Locale.ENGLISH);
-
-    @Test
-    public void testGetFuzzyScore() throws Exception {
-        assertEquals(0, (int) ENGLISH_SCORE.fuzzyScore("", ""));
-        assertEquals(0, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "b"));
-        assertEquals(1, (int) ENGLISH_SCORE.fuzzyScore("Room", "o"));
-        assertEquals(1, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "w"));
-        assertEquals(2, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "ws"));
-        assertEquals(4, (int) ENGLISH_SCORE.fuzzyScore("Workshop", "wo"));
-        assertEquals(3, (int) ENGLISH_SCORE.fuzzyScore(
-            "Apache Software Foundation", "asf"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetFuzzyScore_StringNullLocale() throws Exception {
-        ENGLISH_SCORE.fuzzyScore("not null", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetFuzzyScore_NullStringLocale() throws Exception {
-        ENGLISH_SCORE.fuzzyScore(null, "not null");
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetFuzzyScore_NullNullLocale() throws Exception {
-        ENGLISH_SCORE.fuzzyScore(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testMissingLocale() throws Exception {
-        new FuzzyScore((Locale) null);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/HammingDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/HammingDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/HammingDistanceTest.java
deleted file mode 100644
index d38981f..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/HammingDistanceTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Unit tests for {@link HammingDistance}.
- */
-public class HammingDistanceTest {
-
-    private static HammingDistance distance;
-
-    @BeforeClass
-    public static void setUp() {
-        distance = new HammingDistance();
-    }
-
-    @Test
-    public void testHammingDistance() {
-        assertEquals(Integer.valueOf(0), distance.apply("", ""));
-        assertEquals(Integer.valueOf(0), distance.apply("pappa", "pappa"));
-        assertEquals(Integer.valueOf(1), distance.apply("papaa", "pappa"));
-        assertEquals(Integer.valueOf(3), distance.apply("karolin", "kathrin"));
-        assertEquals(Integer.valueOf(3), distance.apply("karolin", "kerstin"));
-        assertEquals(Integer.valueOf(2), distance.apply("1011101", "1001001"));
-        assertEquals(Integer.valueOf(3), distance.apply("2173896", "2233796"));
-        assertEquals(Integer.valueOf(2), distance.apply("ATCG", "ACCC"));
-    }
-
-    @Test(expected=IllegalArgumentException.class)
-    public void testHammingDistance_nullLeftValue() {
-        distance.apply(null, "");
-    }
-
-    @Test(expected=IllegalArgumentException.class)
-    public void testHammingDistance_nullRightValue() {
-        distance.apply("", null);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/JaccardDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/JaccardDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/JaccardDistanceTest.java
deleted file mode 100644
index 6e74dc3..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/JaccardDistanceTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Unit tests for {@link JaccardDistance}.
- */
-public class JaccardDistanceTest {
-
-    private static JaccardDistance classBeingTested;
-    
-    @BeforeClass
-    public static void setUp() {
-        classBeingTested = new JaccardDistance();
-    }
-
-    @Test
-    public void testGettingJaccardDistance() {
-        assertEquals(1.00d, classBeingTested.apply("", ""), 0.0d);
-        assertEquals(1.00d, classBeingTested.apply("left", ""), 0.0d);
-        assertEquals(1.00d, classBeingTested.apply("", "right"), 0.0d);
-        assertEquals(0.25d, classBeingTested.apply("frog", "fog"), 0.0d);
-        assertEquals(1.00d, classBeingTested.apply("fly", "ant"), 0.0d);
-        assertEquals(0.78d, classBeingTested.apply("elephant", "hippo"), 0.0d);
-        assertEquals(0.36d, classBeingTested.apply("ABC Corporation", "ABC Corp"), 0.0d);
-        assertEquals(0.24d, classBeingTested.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.0d);
-        assertEquals(0.11d, classBeingTested.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.0d);
-        assertEquals(0.10d, classBeingTested.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.0d);
-        assertEquals(0.87d, classBeingTested.apply("left", "right"), 0.0d);
-        assertEquals(0.87d, classBeingTested.apply("leettteft", "ritttght"), 0.0d);
-        assertEquals(0.0d, classBeingTested.apply("the same string", "the same string"), 0.0d);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingJaccardDistanceNullNull() throws Exception {
-        classBeingTested.apply(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingJaccardDistanceStringNull() throws Exception {
-        classBeingTested.apply(" ", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingJaccardDistanceNullString() throws Exception {
-        classBeingTested.apply(null, "right");
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/JaccardSimilarityTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/JaccardSimilarityTest.java b/src/test/java/org/apache/commons/text/beta/similarity/JaccardSimilarityTest.java
deleted file mode 100644
index 8841cfe..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/JaccardSimilarityTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Unit tests for {@link JaccardSimilarity}.
- */
-public class JaccardSimilarityTest {
-
-    private static JaccardSimilarity classBeingTested;
-    
-    @BeforeClass
-    public static void setUp() {
-        classBeingTested = new JaccardSimilarity();
-    }
-
-    @Test
-    public void testGettingJaccardSimilarity() {
-        assertEquals(0.00d, classBeingTested.apply("", ""), 0.0d);
-        assertEquals(0.00d, classBeingTested.apply("left", ""), 0.0d);
-        assertEquals(0.00d, classBeingTested.apply("", "right"), 0.0d);
-        assertEquals(0.75d, classBeingTested.apply("frog", "fog"), 0.0d);
-        assertEquals(0.00d, classBeingTested.apply("fly", "ant"), 0.0d);
-        assertEquals(0.22d, classBeingTested.apply("elephant", "hippo"), 0.0d);
-        assertEquals(0.64d, classBeingTested.apply("ABC Corporation", "ABC Corp"), 0.0d);
-        assertEquals(0.76d, classBeingTested.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.0d);
-        assertEquals(0.89d, classBeingTested.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.0d);
-        assertEquals(0.9d, classBeingTested.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.0d);
-        assertEquals(0.13d, classBeingTested.apply("left", "right"), 0.0d);
-        assertEquals(0.13d, classBeingTested.apply("leettteft", "ritttght"), 0.0d);
-        assertEquals(1.0d, classBeingTested.apply("the same string", "the same string"), 0.0d);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingJaccardSimilarityNullNull() throws Exception {
-        classBeingTested.apply(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingJaccardSimilarityStringNull() throws Exception {
-        classBeingTested.apply(" ", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingJaccardSimilarityNullString() throws Exception {
-        classBeingTested.apply(null, "right");
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/JaroWinklerDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/JaroWinklerDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/JaroWinklerDistanceTest.java
deleted file mode 100644
index 2210426..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/JaroWinklerDistanceTest.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Unit tests for {@link JaroWinklerDistance}.
- */
-public class JaroWinklerDistanceTest {
-
-    private static JaroWinklerDistance distance;
-    
-    @BeforeClass
-    public static void setUp() {
-        distance = new JaroWinklerDistance();
-    }
-    
-    @Test
-    public void testGetJaroWinklerDistance_StringString() {
-        assertEquals(0.93d, (double) distance.apply("frog", "fog"), 0.0d);
-        assertEquals(0.0d, (double) distance.apply("fly", "ant"), 0.0d);
-        assertEquals(0.44d, (double) distance.apply("elephant", "hippo"), 0.0d);
-        assertEquals(0.93d, (double) distance.apply("ABC Corporation", "ABC Corp"), 0.0d);
-        assertEquals(0.95d, (double) distance.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."), 0.0d);
-        assertEquals(0.92d, (double) distance.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"), 0.0d);
-        assertEquals(0.88d, (double) distance.apply("PENNSYLVANIA", "PENNCISYLVNIA"), 0.0d);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetJaroWinklerDistance_NullNull() throws Exception {
-        distance.apply(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetJaroWinklerDistance_StringNull() throws Exception {
-        distance.apply(" ", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetJaroWinklerDistance_NullString() throws Exception {
-        distance.apply(null, "clear");
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistanceTest.java
deleted file mode 100644
index dc814bb..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDetailedDistanceTest.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-public class LevenshteinDetailedDistanceTest {
-
-    private static final LevenshteinDetailedDistance UNLIMITED_DISTANCE = new LevenshteinDetailedDistance();
-
-    @Test
-    public void testGetLevenshteinDetailedDistance_StringString() {
-        LevenshteinResults result = UNLIMITED_DISTANCE.apply("", "");
-        assertEquals(0, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("", "a");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(1, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("aaapppp", "");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(7, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("frog", "fog");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(1, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("fly", "ant");
-        assertEquals(3, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(3, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("elephant", "hippo");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(3, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("hippo", "elephant");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("hippo", "zzzzzzzz");
-        assertEquals(8, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(5, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("zzzzzzzz", "hippo");
-        assertEquals(8, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(3, (int) result.getDeleteCount());
-        assertEquals(5, (int) result.getSubstituteCount());
-
-        result = UNLIMITED_DISTANCE.apply("hello", "hallo");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-    }
-    
-    @Test
-    public void testEquals() {
-     final LevenshteinDetailedDistance classBeingTested = new LevenshteinDetailedDistance();
-     LevenshteinResults actualResult = classBeingTested.apply("hello", "hallo");
-     LevenshteinResults expectedResult = new LevenshteinResults(1, 0, 0, 1);
-     assertEquals(actualResult, expectedResult);
-     
-     actualResult = classBeingTested.apply("zzzzzzzz", "hippo");
-     expectedResult = new LevenshteinResults(8, 0, 3, 5);
-     assertEquals(actualResult, expectedResult);
-     assertEquals(actualResult, actualResult); //intentionally added
-
-     actualResult = classBeingTested.apply("", "");
-     expectedResult = new LevenshteinResults(0, 0, 0, 0);
-     assertEquals(actualResult, expectedResult);
-    }
-
-    @Test
-    public void testHashCode() {
-     final LevenshteinDetailedDistance classBeingTested = new LevenshteinDetailedDistance();
-     LevenshteinResults actualResult = classBeingTested.apply("aaapppp", "");
-     LevenshteinResults expectedResult = new LevenshteinResults(7, 0, 7, 0);
-     assertEquals(actualResult.hashCode(), expectedResult.hashCode());
-     
-     actualResult = classBeingTested.apply("frog", "fog");
-     expectedResult = new LevenshteinResults(1, 0, 1, 0);
-     assertEquals(actualResult.hashCode(), expectedResult.hashCode());
-
-     actualResult = classBeingTested.apply("elephant", "hippo");
-     expectedResult = new LevenshteinResults(7, 0, 3, 4);
-     assertEquals(actualResult.hashCode(), expectedResult.hashCode());
-    }
-
-    @Test
-    public void testToString() {
-     final LevenshteinDetailedDistance classBeingTested = new LevenshteinDetailedDistance();
-     LevenshteinResults actualResult = classBeingTested.apply("fly", "ant");
-     LevenshteinResults expectedResult = new LevenshteinResults(3, 0, 0, 3);
-     assertEquals(actualResult.toString(), expectedResult.toString());
-     
-     actualResult = classBeingTested.apply("hippo", "elephant");
-     expectedResult = new LevenshteinResults(7, 3, 0, 4);
-     assertEquals(actualResult.toString(), expectedResult.toString());
-
-     actualResult = classBeingTested.apply("", "a");
-     expectedResult = new LevenshteinResults(1, 1, 0, 0);
-     assertEquals(actualResult.toString(), expectedResult.toString());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDetailedDistance_NullString() throws Exception {
-        UNLIMITED_DISTANCE.apply("a", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDetailedDistance_StringNull() throws Exception {
-        UNLIMITED_DISTANCE.apply(null, "a");
-    }
-
-    @Test
-    public void testGetLevenshteinDetailedDistance_StringStringInt() {
-
-        LevenshteinResults result = new LevenshteinDetailedDistance(0).apply("", "");
-
-        assertEquals(0, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(8).apply("aaapppp", "");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(7, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(7).apply("aaapppp", "");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(7, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(6).apply("aaapppp", "");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(0).apply("b", "a");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(0).apply("a", "b");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(0).apply("aa", "aa");
-        assertEquals(0, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(2).apply("aa", "aa");
-        assertEquals(0, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(2).apply("aaa", "bbb");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(3).apply("aaa", "bbb");
-        assertEquals(3, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(3, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(10).apply("aaaaaa", "b");
-        assertEquals(6, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(5, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(8).apply("aaapppp", "b");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(6, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(4).apply("a", "bbb");
-        assertEquals(3, (int) result.getDistance());
-        assertEquals(2, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(7).apply("aaapppp", "b");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(6, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(3).apply("a", "bbb");
-        assertEquals(3, (int) result.getDistance());
-        assertEquals(2, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(2).apply("a", "bbb");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(2).apply("bbb", "a");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(6).apply("aaapppp", "b");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(1).apply("a", "bbb");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(1).apply("bbb", "a");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(1).apply("12345", "1234567");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(1).apply("1234567", "12345");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(1).apply("frog", "fog");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(1, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(3).apply("fly", "ant");
-        assertEquals(3, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(3, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(7).apply("elephant", "hippo");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(3, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(6).apply("elephant", "hippo");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(7).apply("hippo", "elephant");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(7).apply("hippo", "elephant");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(6).apply("hippo", "elephant");
-        assertEquals(-1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(8).apply("hippo", "zzzzzzzz");
-        assertEquals(8, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(5, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(8).apply("zzzzzzzz", "hippo");
-        assertEquals(8, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(3, (int) result.getDeleteCount());
-        assertEquals(5, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(1).apply("hello", "hallo");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("frog", "fog");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(1, (int) result.getDeleteCount());
-        assertEquals(0, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("fly", "ant");
-        assertEquals(3, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(3, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("elephant", "hippo");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(3, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hippo", "elephant");
-        assertEquals(7, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(4, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hippo", "zzzzzzzz");
-        assertEquals(8, (int) result.getDistance());
-        assertEquals(3, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(5, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("zzzzzzzz", "hippo");
-        assertEquals(8, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(3, (int) result.getDeleteCount());
-        assertEquals(5, (int) result.getSubstituteCount());
-
-        result = new LevenshteinDetailedDistance(Integer.MAX_VALUE).apply("hello", "hallo");
-        assertEquals(1, (int) result.getDistance());
-        assertEquals(0, (int) result.getInsertCount());
-        assertEquals(0, (int) result.getDeleteCount());
-        assertEquals(1, (int) result.getSubstituteCount());
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDetailedDistance_NullStringInt() throws Exception {
-        UNLIMITED_DISTANCE.apply(null, "a");
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDetailedDistance_StringNullInt() throws Exception {
-        UNLIMITED_DISTANCE.apply("a", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testConstructorWithNegativeThreshold() throws Exception {
-        new LevenshteinDetailedDistance(-1);
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDistanceTest.java
deleted file mode 100644
index cc69195..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/LevenshteinDistanceTest.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link LevenshteinDistance}.
- */
-public class LevenshteinDistanceTest {
-
-    private static final LevenshteinDistance UNLIMITED_DISTANCE = new LevenshteinDistance();
-
-    @Test
-    public void testGetLevenshteinDistance_StringString() {
-        assertEquals(0, (int) UNLIMITED_DISTANCE.apply("", ""));
-        assertEquals(1, (int) UNLIMITED_DISTANCE.apply("", "a"));
-        assertEquals(7, (int) UNLIMITED_DISTANCE.apply("aaapppp", ""));
-        assertEquals(1, (int) UNLIMITED_DISTANCE.apply("frog", "fog"));
-        assertEquals(3, (int) UNLIMITED_DISTANCE.apply("fly", "ant"));
-        assertEquals(7, (int) UNLIMITED_DISTANCE.apply("elephant", "hippo"));
-        assertEquals(7, (int) UNLIMITED_DISTANCE.apply("hippo", "elephant"));
-        assertEquals(8, (int) UNLIMITED_DISTANCE.apply("hippo", "zzzzzzzz"));
-        assertEquals(8, (int) UNLIMITED_DISTANCE.apply("zzzzzzzz", "hippo"));
-        assertEquals(1, (int) UNLIMITED_DISTANCE.apply("hello", "hallo"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDistance_NullString() throws Exception {
-        UNLIMITED_DISTANCE.apply("a", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDistance_StringNull() throws Exception {
-        UNLIMITED_DISTANCE.apply(null, "a");
-    }
-
-    @Test
-    public void testGetLevenshteinDistance_StringStringInt() {
-        // empty strings
-        assertEquals(0, (int) new LevenshteinDistance(0).apply("", ""));
-        assertEquals(7, (int) new LevenshteinDistance(8).apply("aaapppp", ""));
-        assertEquals(7, (int) new LevenshteinDistance(7).apply("aaapppp", ""));
-        assertEquals(-1, (int) new LevenshteinDistance(6).apply("aaapppp", ""));
-
-        // unequal strings, zero threshold
-        assertEquals(-1, (int) new LevenshteinDistance(0).apply("b", "a"));
-        assertEquals(-1, (int) new LevenshteinDistance(0).apply("a", "b"));
-
-        // equal strings
-        assertEquals(0, (int) new LevenshteinDistance(0).apply("aa", "aa"));
-        assertEquals(0, (int) new LevenshteinDistance(2).apply("aa", "aa"));
-
-        // same length
-        assertEquals(-1, (int) new LevenshteinDistance(2).apply("aaa", "bbb"));
-        assertEquals(3, (int) new LevenshteinDistance(3).apply("aaa", "bbb"));
-
-        // big stripe
-        assertEquals(6, (int) new LevenshteinDistance(10).apply("aaaaaa", "b"));
-
-        // distance less than threshold
-        assertEquals(7, (int) new LevenshteinDistance(8).apply("aaapppp", "b"));
-        assertEquals(3, (int) new LevenshteinDistance(4).apply("a", "bbb"));
-
-        // distance equal to threshold
-        assertEquals(7, (int) new LevenshteinDistance(7).apply("aaapppp", "b"));
-        assertEquals(3, (int) new LevenshteinDistance(3).apply("a", "bbb"));
-
-        // distance greater than threshold
-        assertEquals(-1, (int) new LevenshteinDistance(2).apply("a", "bbb"));
-        assertEquals(-1, (int) new LevenshteinDistance(2).apply("bbb", "a"));
-        assertEquals(-1, (int) new LevenshteinDistance(6).apply("aaapppp", "b"));
-
-        // stripe runs off array, strings not similar
-        assertEquals(-1, (int) new LevenshteinDistance(1).apply("a", "bbb"));
-        assertEquals(-1, (int) new LevenshteinDistance(1).apply("bbb", "a"));
-
-        // stripe runs off array, strings are similar
-        assertEquals(-1, (int) new LevenshteinDistance(1).apply("12345", "1234567"));
-        assertEquals(-1, (int) new LevenshteinDistance(1).apply("1234567", "12345"));
-
-        // old getLevenshteinDistance test cases
-        assertEquals(1, (int) new LevenshteinDistance(1).apply("frog", "fog"));
-        assertEquals(3, (int) new LevenshteinDistance(3).apply("fly", "ant"));
-        assertEquals(7, (int) new LevenshteinDistance(7).apply("elephant", "hippo"));
-        assertEquals(-1, (int) new LevenshteinDistance(6).apply("elephant", "hippo"));
-        assertEquals(7, (int) new LevenshteinDistance(7).apply("hippo", "elephant"));
-        assertEquals(-1, (int) new LevenshteinDistance(6).apply("hippo", "elephant"));
-        assertEquals(8, (int) new LevenshteinDistance(8).apply("hippo", "zzzzzzzz"));
-        assertEquals(8, (int) new LevenshteinDistance(8).apply("zzzzzzzz", "hippo"));
-        assertEquals(1, (int) new LevenshteinDistance(1).apply("hello", "hallo"));
-
-        assertEquals(1,
-                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("frog", "fog"));
-        assertEquals(3, (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("fly", "ant"));
-        assertEquals(7,
-                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("elephant", "hippo"));
-        assertEquals(7,
-                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("hippo", "elephant"));
-        assertEquals(8,
-                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("hippo", "zzzzzzzz"));
-        assertEquals(8,
-                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("zzzzzzzz", "hippo"));
-        assertEquals(1,
-                (int) new LevenshteinDistance(Integer.MAX_VALUE).apply("hello", "hallo"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDistance_NullStringInt() throws Exception {
-        UNLIMITED_DISTANCE.apply(null, "a");
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGetLevenshteinDistance_StringNullInt() throws Exception {
-        UNLIMITED_DISTANCE.apply("a", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testConstructorWithNegativeThreshold() throws Exception {
-        new LevenshteinDistance(-1);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistanceTest.java
deleted file mode 100644
index 4de31bd..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceDistanceTest.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link LongestCommonSubsequenceDistance}.
- */
-public class LongestCommonSubsequenceDistanceTest {
-
-    private static LongestCommonSubsequenceDistance subject;
-    
-    @BeforeClass
-    public static void setup() {
-        subject = new LongestCommonSubsequenceDistance();
-    }
-
-    @Test
-    public void testGettingLogestCommonSubsequenceDistacne() {
-        assertEquals(Integer.valueOf(0), subject.apply("", ""));
-        assertEquals(Integer.valueOf(4), subject.apply("left", ""));
-        assertEquals(Integer.valueOf(5), subject.apply("", "right"));
-        assertEquals(Integer.valueOf(1), subject.apply("frog", "fog"));
-        assertEquals(Integer.valueOf(6), subject.apply("fly", "ant"));
-        assertEquals(Integer.valueOf(11), subject.apply("elephant", "hippo"));
-        assertEquals(Integer.valueOf(7), subject.apply("ABC Corporation", "ABC Corp"));
-        assertEquals(Integer.valueOf(4), subject.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."));
-        assertEquals(Integer.valueOf(9), subject.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"));
-        assertEquals(Integer.valueOf(3), subject.apply("PENNSYLVANIA", "PENNCISYLVNIA"));
-        assertEquals(Integer.valueOf(7), subject.apply("left", "right"));
-        assertEquals(Integer.valueOf(9), subject.apply("leettteft", "ritttght"));
-        assertEquals(Integer.valueOf(0), subject.apply("the same string", "the same string"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceDistanceNullNull() throws Exception {
-        subject.apply(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceDistanceStringNull() throws Exception {
-        subject.apply(" ", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceDistanceNullString() throws Exception {
-        subject.apply(null, "right");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceTest.java
deleted file mode 100644
index 95c2d09..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/LongestCommonSubsequenceTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link LongestCommonSubsequence}.
- */
-public class LongestCommonSubsequenceTest {
-
-    private static LongestCommonSubsequence subject;
-
-    @BeforeClass
-    public static void setup() {
-        subject = new LongestCommonSubsequence();
-    }
-
-    @Test
-    public void testLongestCommonSubsequenceApply() {
-        assertEquals(Integer.valueOf(0), subject.apply("", ""));
-        assertEquals(Integer.valueOf(0), subject.apply("left", ""));
-        assertEquals(Integer.valueOf(0), subject.apply("", "right"));
-        assertEquals(Integer.valueOf(3), subject.apply("frog", "fog"));
-        assertEquals(Integer.valueOf(0), subject.apply("fly", "ant"));
-        assertEquals(Integer.valueOf(1), subject.apply("elephant", "hippo"));
-        assertEquals(Integer.valueOf(8), subject.apply("ABC Corporation", "ABC Corp"));
-        assertEquals(Integer.valueOf(20), subject.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."));
-        assertEquals(Integer.valueOf(24), subject.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"));
-        assertEquals(Integer.valueOf(11), subject.apply("PENNSYLVANIA", "PENNCISYLVNIA"));
-        assertEquals(Integer.valueOf(1), subject.apply("left", "right"));
-        assertEquals(Integer.valueOf(4), subject.apply("leettteft", "ritttght"));
-        assertEquals(Integer.valueOf(15), subject.apply("the same string", "the same string"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceApplyNullNull() throws Exception {
-        subject.apply(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceApplyStringNull() throws Exception {
-        subject.apply(" ", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceApplyNullString() throws Exception {
-        subject.apply(null, "right");
-    }
-
-    @Test
-    public void testLongestCommonSubsequence() {
-        assertEquals("", subject.logestCommonSubsequence("", ""));
-        assertEquals("", subject.logestCommonSubsequence("left", ""));
-        assertEquals("", subject.logestCommonSubsequence("", "right"));
-        assertEquals("fog", subject.logestCommonSubsequence("frog", "fog"));
-        assertEquals("", subject.logestCommonSubsequence("fly", "ant"));
-        assertEquals("h", subject.logestCommonSubsequence("elephant", "hippo"));
-        assertEquals("ABC Corp", subject.logestCommonSubsequence("ABC Corporation", "ABC Corp"));
-        assertEquals("D  H Enterprises Inc", subject.logestCommonSubsequence("D N H Enterprises Inc", "D & H Enterprises, Inc."));
-        assertEquals("My Gym Childrens Fitness", subject.logestCommonSubsequence("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"));
-        assertEquals("PENNSYLVNIA", subject.logestCommonSubsequence("PENNSYLVANIA", "PENNCISYLVNIA"));
-        assertEquals("t", subject.logestCommonSubsequence("left", "right"));
-        assertEquals("tttt", subject.logestCommonSubsequence("leettteft", "ritttght"));
-        assertEquals("the same string", subject.logestCommonSubsequence("the same string", "the same string"));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceNullNull() throws Exception {
-        subject.logestCommonSubsequence(null, null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceStringNull() throws Exception {
-        subject.logestCommonSubsequence(" ", null);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testGettingLongestCommonSubsequenceNullString() throws Exception {
-        subject.logestCommonSubsequence(null, "right");
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedEditDistanceFromTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedEditDistanceFromTest.java b/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedEditDistanceFromTest.java
deleted file mode 100644
index 0d080ba..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedEditDistanceFromTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import java.util.Arrays;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Unit tests for {@link EditDistanceFrom}.
- *
- * @param <R> The {@link EditDistance} return type.
- */
-@RunWith(Parameterized.class)
-public class ParameterizedEditDistanceFromTest<R> {
-
-    private final EditDistance<R> editDistance;
-    private final CharSequence left;
-    private final CharSequence right;
-    private final R distance;
-
-    public ParameterizedEditDistanceFromTest(
-        final EditDistance<R> editDistance,
-        final CharSequence left, final CharSequence right,
-        final R distance) {
-
-        this.editDistance = editDistance;
-        this.left = left;
-        this.right = right;
-        this.distance = distance;
-    }
-
-    @Parameters
-    public static Iterable<Object[]> parameters() {
-        return Arrays.asList( new Object[][] {
-
-            { new HammingDistance(), "Sam I am.", "Ham I am.", 1 },
-            { new HammingDistance(), "Japtheth, Ham, Shem", "Japtheth, HAM, Shem", 2 },
-            { new HammingDistance(), "Hamming", "Hamming", 0 },
-
-            { new LevenshteinDistance(), "Apache", "a patchy", 4 },
-            { new LevenshteinDistance(), "go", "no go", 3 },
-            { new LevenshteinDistance(), "go", "go", 0 },
-
-            { new LevenshteinDistance(4), "Apache", "a patchy", 4 },
-            { new LevenshteinDistance(4), "go", "no go", 3 },
-            { new LevenshteinDistance(0), "go", "go", 0 },
-
-            {
-                new EditDistance<Boolean>() {
-                    @Override
-                    public Boolean apply(final CharSequence left, final CharSequence right) {
-                        return left == right || (left != null && left.equals(right));
-                    }
-                },
-                "Bob's your uncle.",
-                "Every good boy does fine.",
-                false
-            }
-
-        } );
-    }
-
-    @Test
-    public void test() {
-        final EditDistanceFrom<R> editDistanceFrom = new EditDistanceFrom<>(editDistance, left);
-        assertThat(editDistanceFrom.apply(right), equalTo(distance));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedLevenshteinDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedLevenshteinDistanceTest.java b/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedLevenshteinDistanceTest.java
deleted file mode 100644
index 69a062a..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedLevenshteinDistanceTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import java.util.Arrays;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-/**
- * Unit tests for {@link LevenshteinDistance}.
- */
-@RunWith(Parameterized.class)
-public class ParameterizedLevenshteinDistanceTest {
-
-    private final Integer distance;
-    private final CharSequence left;
-    private final CharSequence right;
-    private final Integer threshold;
-
-    public ParameterizedLevenshteinDistanceTest(
-        final Integer threshold,
-        final CharSequence left, final CharSequence right,
-        final Integer distance) {
-
-        this.threshold = threshold;
-        this.left = left;
-        this.right = right;
-        this.distance = distance;
-    }
-
-    @Parameters
-    public static Iterable<Object[]> parameters() {
-        return Arrays.asList( new Object[][] {
-
-            /* empty strings */
-            { 0, "", "", 0 },
-            { 8, "aaapppp", "", 7 },
-            { 7, "aaapppp", "", 7 },
-            { 6, "aaapppp", "", -1 },
-
-            /* unequal strings, zero threshold */
-            { 0, "b", "a", -1 },
-            { 0, "a", "b", -1 },
-
-            /* equal strings */
-            { 0, "aa", "aa", 0 },
-            { 2, "aa", "aa", 0 },
-
-            /* same length */
-            { 2, "aaa", "bbb", -1 },
-            { 3, "aaa", "bbb", 3 },
-
-            /* big stripe */
-            { 10, "aaaaaa", "b", 6 },
-
-            /* distance less than threshold */
-            { 8, "aaapppp", "b", 7 },
-            { 4, "a", "bbb", 3 },
-
-            /* distance equal to threshold */
-            { 7, "aaapppp", "b", 7 },
-            { 3, "a", "bbb", 3 },
-
-            /* distance greater than threshold */
-            { 2, "a", "bbb", -1 },
-            { 2, "bbb", "a", -1 },
-            { 6, "aaapppp", "b", -1 },
-
-            /* stripe runs off array, strings not similar */
-            { 1, "a", "bbb", -1 },
-            { 1, "bbb", "a", -1 },
-
-            /* stripe runs off array, strings are similar */
-            { 1, "12345", "1234567", -1 },
-            { 1, "1234567", "12345", -1 },
-
-           /* old getLevenshteinDistance test cases */
-            { 1, "frog", "fog", 1 },
-            { 3, "fly", "ant", 3 },
-            { 7, "elephant", "hippo", 7 },
-            { 6, "elephant", "hippo", -1 },
-            { 7, "hippo", "elephant", 7 },
-            { 6, "hippo", "elephant", -1 },
-            { 8, "hippo", "zzzzzzzz", 8 },
-            { 8, "zzzzzzzz", "hippo", 8 },
-            { 1, "hello", "hallo", 1 },
-
-            { Integer.MAX_VALUE, "frog", "fog", 1 },
-            { Integer.MAX_VALUE, "fly", "ant", 3 },
-            { Integer.MAX_VALUE, "elephant", "hippo", 7 },
-            { Integer.MAX_VALUE, "hippo", "elephant", 7 },
-            { Integer.MAX_VALUE, "hippo", "zzzzzzzz", 8 },
-            { Integer.MAX_VALUE, "zzzzzzzz", "hippo", 8 },
-            { Integer.MAX_VALUE, "hello", "hallo", 1 }
-
-        } );
-    }
-
-    @Test
-    public void test() {
-        final LevenshteinDistance metric = new LevenshteinDistance(threshold);
-        assertThat(metric.apply(left, right), equalTo(distance));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedSimilarityScoreFromTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedSimilarityScoreFromTest.java b/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedSimilarityScoreFromTest.java
deleted file mode 100644
index 810f1ee..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/ParameterizedSimilarityScoreFromTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-import java.util.Arrays;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-/**
- * Unit tests for {@link SimilarityScoreFrom}.
- *
- * @param <R> The {@link SimilarityScore} return type.
- */
-@RunWith(Parameterized.class)
-public class ParameterizedSimilarityScoreFromTest<R> {
-
-    private final SimilarityScore<R> similarityScore;
-    private final CharSequence left;
-    private final CharSequence right;
-    private final R distance;
-
-    public ParameterizedSimilarityScoreFromTest(
-            final SimilarityScore<R> similarityScore,
-            final CharSequence left, final CharSequence right,
-            final R distance) {
-
-        this.similarityScore = similarityScore;
-        this.left = left;
-        this.right = right;
-        this.distance = distance;
-    }
-
-    @Parameters
-    public static Iterable<Object[]> parameters() {
-        return Arrays.asList( new Object[][] {
-
-                { new JaroWinklerDistance(), "elephant", "hippo", 0.44 },
-                { new JaroWinklerDistance(), "hippo", "elephant",  0.44 },
-                { new JaroWinklerDistance(), "hippo", "zzzzzzzz", 0.0 },
-
-                {
-                        new SimilarityScore<Boolean>() {
-                            @Override
-                            public Boolean apply(final CharSequence left, final CharSequence right) {
-                                return left == right || (left != null && left.equals(right));
-                            }
-                        },
-                        "Bob's your uncle.",
-                        "Every good boy does fine.",
-                        false
-                }
-
-        } );
-    }
-
-    @Test
-    public void test() {
-        final SimilarityScoreFrom<R> similarityScoreFrom = new SimilarityScoreFrom<>(similarityScore, left);
-        assertThat(similarityScoreFrom.apply(right), equalTo(distance));
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/similarity/StringMetricFromTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/similarity/StringMetricFromTest.java b/src/test/java/org/apache/commons/text/beta/similarity/StringMetricFromTest.java
deleted file mode 100644
index f8f67da..0000000
--- a/src/test/java/org/apache/commons/text/beta/similarity/StringMetricFromTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.similarity;
-
-import static org.hamcrest.core.IsEqual.equalTo;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link EditDistanceFrom}.
- */
-public class StringMetricFromTest {
-
-    @Test
-    public void testEquivalence() {
-        final EditDistance<Integer> metric = new LevenshteinDistance();
-        final String left = "Apache";
-        final String right = "a patchy";
-        final Integer distance = 4;
-        final EditDistanceFrom<Integer> metricFrom = new EditDistanceFrom<>(metric, left);
-
-        assertThat(metricFrom.apply(right), equalTo(distance));
-        assertThat(metricFrom.apply(right), equalTo(metric.apply(left, right)));
-    }
-
-    @Test
-    public void testJavadocExample() {
-        final EditDistance<Integer> metric = new LevenshteinDistance();
-        final String target = "Apache";
-        final EditDistanceFrom<Integer> metricFrom =
-            new EditDistanceFrom<>(metric, target);
-        String mostSimilar = null;
-        Integer shortestDistance = null;
-        
-        for (final String test : new String[] { "Appaloosa", "a patchy", "apple" }) {
-            final Integer distance = metricFrom.apply(test);
-            if (shortestDistance == null || distance < shortestDistance) {
-                shortestDistance = distance;
-                mostSimilar = test;
-            }
-        }
-        assertThat(mostSimilar, equalTo("a patchy"));
-        assertThat(shortestDistance, equalTo(4));
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testMissingMetric() {
-        new EditDistanceFrom<Number>(null, "no go");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/AggregateTranslatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/AggregateTranslatorTest.java b/src/test/java/org/apache/commons/text/beta/translate/AggregateTranslatorTest.java
deleted file mode 100644
index cc63f5a..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/AggregateTranslatorTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.HashMap;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link AggregateTranslator}.
- */
-public class AggregateTranslatorTest {
-
-    @Test
-    public void testNullConstructor() throws Exception {
-        final String testString = "foo";
-        final AggregateTranslator subject = new AggregateTranslator((CharSequenceTranslator[]) null);
-        assertEquals(testString, subject.translate(testString));
-    }
-    
-    @Test
-    public void testNullVarargConstructor() throws Exception {
-        final String testString = "foo";
-        final AggregateTranslator subject = new AggregateTranslator((CharSequenceTranslator) null);
-        assertEquals(testString, subject.translate(testString));
-    }
-
-    @Test
-    public void testNonNull() throws IOException{
-        final Map<CharSequence, CharSequence> oneTwoMap = new HashMap<>();
-        oneTwoMap.put("one", "two");
-        final Map<CharSequence, CharSequence> threeFourMap = new HashMap<>();
-        threeFourMap.put("three", "four");
-        final CharSequenceTranslator translator1 = new LookupTranslator(oneTwoMap);
-        final CharSequenceTranslator translator2 = new LookupTranslator(threeFourMap);
-        final AggregateTranslator subject = new AggregateTranslator(translator1, translator2);
-        final StringWriter out1 = new StringWriter();
-        final int result1 = subject.translate(new StringBuffer("one"), 0, out1);
-        assertEquals("Incorrect codepoint consumption", 3, result1);
-        assertEquals("Incorrect value", "two", out1.toString());
-        final StringWriter out2 = new StringWriter();
-        final int result2 = subject.translate(new StringBuffer("three"), 0, out2);
-        assertEquals("Incorrect codepoint consumption", 5, result2);
-        assertEquals("Incorrect value", "four", out2.toString());
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/translate/EntityArraysTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/translate/EntityArraysTest.java b/src/test/java/org/apache/commons/text/beta/translate/EntityArraysTest.java
deleted file mode 100644
index 38b796e..0000000
--- a/src/test/java/org/apache/commons/text/beta/translate/EntityArraysTest.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta.translate;
-
-import org.junit.Test;
-
-import java.io.BufferedReader;
-import java.io.FileReader;
-import java.util.Map;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Unit tests for {@link EntityArrays}.
- */
-public class EntityArraysTest  {
-
-    @Test
-    public void testConstructorExists() {
-        new EntityArrays();
-    }
-
-    // LANG-659, LANG-658 - avoid duplicate entries
-    @Test
-    public void testForDuplicatedDeclaredMapKeys() throws Exception {
-        String packageDirectory = EntityArraysTest.class.getPackage().getName().replace(".", "/");
-        try (BufferedReader br = new BufferedReader(new FileReader("src/main/java/" + packageDirectory + "/EntityArrays.java"))) {
-            String line;
-            int mapDeclarationCounter = 0;
-            while ((line = br.readLine()) != null) {
-                //Start with map declaration and count put lines
-                if (line.contains("new HashMap<>();")) {
-                    mapDeclarationCounter = 0;
-                } else if (line.contains(".put(")) {
-                    mapDeclarationCounter++;
-                } else if (line.contains("Collections.unmodifiableMap(initialMap);")) {
-                    String mapVariableName = line.split("=")[0].trim();
-                    @SuppressWarnings("unchecked") // This is test code
-                    Map<String,String> mapValue = (Map<String, String>)EntityArrays.class.getDeclaredField(mapVariableName).get(EntityArrays.class);
-                    // Validate that we are not inserting into the same key twice in the map declaration. If this,
-                    // indeed was the case the keySet().size() would be smaller than the number of put() statements
-                    assertEquals(mapDeclarationCounter, mapValue.keySet().size());
-                }
-            }
-        }
-    }
-
-    @Test
-    public void testForDuplicateDeclaredMapValuesISO8859Map() {
-        assertEquals(EntityArrays.ISO8859_1_ESCAPE.keySet().size(),
-                EntityArrays.ISO8859_1_UNESCAPE.keySet().size());
-    }
-
-    @Test
-    public void testISO8859Map() {
-        testEscapeVsUnescapeMaps(EntityArrays.ISO8859_1_ESCAPE, EntityArrays.ISO8859_1_UNESCAPE);
-    }
-
-    @Test
-    public void testForDuplicateDeclaredMapValuesHtml40ExtendedMap() {
-        assertEquals(EntityArrays.HTML40_EXTENDED_ESCAPE.keySet().size(),
-                EntityArrays.HTML40_EXTENDED_UNESCAPE.keySet().size());
-    }
-
-    @Test
-    public void testHtml40ExtendedMap() {
-        testEscapeVsUnescapeMaps(EntityArrays.HTML40_EXTENDED_ESCAPE, EntityArrays.HTML40_EXTENDED_UNESCAPE);
-    }
-
-    @Test
-    public void testForDuplicateDeclaredMapValuesAposMap() {
-        assertEquals(EntityArrays.APOS_ESCAPE.keySet().size(),
-                EntityArrays.APOS_UNESCAPE.keySet().size());
-    }
-
-    @Test
-    public void testAposMap() {
-        testEscapeVsUnescapeMaps(EntityArrays.APOS_ESCAPE, EntityArrays.APOS_UNESCAPE);
-    }
-
-    @Test
-    public void testForDuplicateDeclaredMapValuesBasicMap() {
-        assertEquals(EntityArrays.BASIC_ESCAPE.keySet().size(),
-                EntityArrays.BASIC_UNESCAPE.keySet().size());
-    }
-
-    @Test
-    public void testBasicMap() {
-        testEscapeVsUnescapeMaps(EntityArrays.BASIC_ESCAPE, EntityArrays.BASIC_UNESCAPE);
-    }
-
-    @Test
-    public void testForDuplicateDeclaredMapValuesJavaCtrlCharsMap() {
-        assertEquals(EntityArrays.JAVA_CTRL_CHARS_ESCAPE.keySet().size(),
-                EntityArrays.JAVA_CTRL_CHARS_UNESCAPE.keySet().size());
-    }
-
-    @Test
-    public void testJavaCntrlCharsMap() {
-        testEscapeVsUnescapeMaps(EntityArrays.JAVA_CTRL_CHARS_ESCAPE, EntityArrays.JAVA_CTRL_CHARS_UNESCAPE);
-    }
-
-    private void testEscapeVsUnescapeMaps(final Map<CharSequence, CharSequence> escapeMap,
-                                          final Map<CharSequence, CharSequence> unescapeMap) {
-        for (final CharSequence escapeKey : escapeMap.keySet()) {
-            for (final CharSequence unescapeKey : unescapeMap.keySet()) {
-                if (escapeKey == unescapeMap.get(unescapeKey)) {
-                    assertEquals(escapeMap.get(escapeKey), unescapeKey);
-                }
-            }
-        }
-    }
-    
-}


[12/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrSubstitutorTest.java b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
new file mode 100644
index 0000000..e382691
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
@@ -0,0 +1,740 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.lang3.mutable.MutableObject;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@link StrSubstitutor}.
+ */
+public class StrSubstitutorTest {
+
+    private Map<String, String> values;
+
+    @Before
+    public void setUp() throws Exception {
+        values = new HashMap<>();
+        values.put("animal", "quick brown fox");
+        values.put("target", "lazy dog");
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        values = null;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests simple key replace.
+     */
+    @Test
+    public void testReplaceSimple() {
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests simple key replace.
+     */
+    @Test
+    public void testReplaceSolo() {
+        doTestReplace("quick brown fox", "${animal}", false);
+    }
+
+    /**
+     * Tests replace with no variables.
+     */
+    @Test
+    public void testReplaceNoVariables() {
+        doTestNoReplace("The balloon arrived.");
+    }
+
+    /**
+     * Tests replace with null.
+     */
+    @Test
+    public void testReplaceNull() {
+        doTestNoReplace(null);
+    }
+
+    /**
+     * Tests replace with null.
+     */
+    @Test
+    public void testReplaceEmpty() {
+        doTestNoReplace("");
+    }
+
+    /**
+     * Tests key replace changing map after initialization (not recommended).
+     */
+    @Test
+    public void testReplaceChangedMap() {
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        values.put("target", "moon");
+        assertEquals("The quick brown fox jumps over the moon.", sub.replace("The ${animal} jumps over the ${target}."));
+    }
+
+    /**
+     * Tests unknown key replace.
+     */
+    @Test
+    public void testReplaceUnknownKey() {
+        doTestReplace("The ${person} jumps over the lazy dog.", "The ${person} jumps over the ${target}.", true);
+        doTestReplace("The ${person} jumps over the lazy dog. 1234567890.", "The ${person} jumps over the ${target}. ${undefined.number:-1234567890}.", true);
+    }
+
+    /**
+     * Tests adjacent keys.
+     */
+    @Test
+    public void testReplaceAdjacentAtStart() {
+        values.put("code", "GBP");
+        values.put("amount", "12.50");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        assertEquals("GBP12.50 charged", sub.replace("${code}${amount} charged"));
+    }
+
+    /**
+     * Tests adjacent keys.
+     */
+    @Test
+    public void testReplaceAdjacentAtEnd() {
+        values.put("code", "GBP");
+        values.put("amount", "12.50");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        assertEquals("Amount is GBP12.50", sub.replace("Amount is ${code}${amount}"));
+    }
+
+    /**
+     * Tests simple recursive replace.
+     */
+    @Test
+    public void testReplaceRecursive() {
+        values.put("animal", "${critter}");
+        values.put("target", "${pet}");
+        values.put("pet", "${petCharacteristic} dog");
+        values.put("petCharacteristic", "lazy");
+        values.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+        values.put("critterSpeed", "quick");
+        values.put("critterColor", "brown");
+        values.put("critterType", "fox");
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+
+        values.put("pet", "${petCharacteristicUnknown:-lazy} dog");
+        doTestReplace("The quick brown fox jumps over the lazy dog.", "The ${animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests escaping.
+     */
+    @Test
+    public void testReplaceEscaping() {
+        doTestReplace("The ${animal} jumps over the lazy dog.", "The $${animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests escaping.
+     */
+    @Test
+    public void testReplaceSoloEscaping() {
+        doTestReplace("${animal}", "$${animal}", false);
+    }
+
+    /**
+     * Tests complex escaping.
+     */
+    @Test
+    public void testReplaceComplexEscaping() {
+        doTestReplace("The ${quick brown fox} jumps over the lazy dog.", "The $${${animal}} jumps over the ${target}.", true);
+        doTestReplace("The ${quick brown fox} jumps over the lazy dog. ${1234567890}.", "The $${${animal}} jumps over the ${target}. $${${undefined.number:-1234567890}}.", true);
+    }
+
+    /**
+     * Tests when no prefix or suffix.
+     */
+    @Test
+    public void testReplaceNoPrefixNoSuffix() {
+        doTestReplace("The animal jumps over the lazy dog.", "The animal jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests when no incomplete prefix.
+     */
+    @Test
+    public void testReplaceIncompletePrefix() {
+        doTestReplace("The {animal} jumps over the lazy dog.", "The {animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests when prefix but no suffix.
+     */
+    @Test
+    public void testReplacePrefixNoSuffix() {
+        doTestReplace("The ${animal jumps over the ${target} lazy dog.", "The ${animal jumps over the ${target} ${target}.", true);
+    }
+
+    /**
+     * Tests when suffix but no prefix.
+     */
+    @Test
+    public void testReplaceNoPrefixSuffix() {
+        doTestReplace("The animal} jumps over the lazy dog.", "The animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests when no variable name.
+     */
+    @Test
+    public void testReplaceEmptyKeys() {
+        doTestReplace("The ${} jumps over the lazy dog.", "The ${} jumps over the ${target}.", true);
+        doTestReplace("The animal jumps over the lazy dog.", "The ${:-animal} jumps over the ${target}.", true);
+    }
+
+    /**
+     * Tests replace creates output same as input.
+     */
+    @Test
+    public void testReplaceToIdentical() {
+        values.put("animal", "$${${thing}}");
+        values.put("thing", "animal");
+        doTestReplace("The ${animal} jumps.", "The ${animal} jumps.", true);
+    }
+
+    /**
+     * Tests a cyclic replace operation.
+     * The cycle should be detected and cause an exception to be thrown.
+     */
+    @Test
+    public void testCyclicReplacement() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("animal", "${critter}");
+        map.put("target", "${pet}");
+        map.put("pet", "${petCharacteristic} dog");
+        map.put("petCharacteristic", "lazy");
+        map.put("critter", "${critterSpeed} ${critterColor} ${critterType}");
+        map.put("critterSpeed", "quick");
+        map.put("critterColor", "brown");
+        map.put("critterType", "${animal}");
+        StrSubstitutor sub = new StrSubstitutor(map);
+        try {
+            sub.replace("The ${animal} jumps over the ${target}.");
+            fail("Cyclic replacement was not detected!");
+        } catch (final IllegalStateException ex) {
+            // expected
+        }
+
+        // also check even when default value is set.
+        map.put("critterType", "${animal:-fox}");
+        sub = new StrSubstitutor(map);
+        try {
+            sub.replace("The ${animal} jumps over the ${target}.");
+            fail("Cyclic replacement was not detected!");
+        } catch (final IllegalStateException ex) {
+            // expected
+        }
+    }
+
+    /**
+     * Tests interpolation with weird boundary patterns.
+     */
+    @Test
+    public void testReplaceWeirdPattens() {
+        doTestNoReplace("");
+        doTestNoReplace("${}");
+        doTestNoReplace("${ }");
+        doTestNoReplace("${\t}");
+        doTestNoReplace("${\n}");
+        doTestNoReplace("${\b}");
+        doTestNoReplace("${");
+        doTestNoReplace("$}");
+        doTestNoReplace("}");
+        doTestNoReplace("${}$");
+        doTestNoReplace("${${");
+        doTestNoReplace("${${}}");
+        doTestNoReplace("${$${}}");
+        doTestNoReplace("${$$${}}");
+        doTestNoReplace("${$$${$}}");
+        doTestNoReplace("${${}}");
+        doTestNoReplace("${${ }}");
+    }
+
+    /**
+     * Tests simple key replace.
+     */
+    @Test
+    public void testReplacePartialString_noReplace() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals("${animal} jumps", sub.replace("The ${animal} jumps over the ${target}.", 4, 15));
+    }
+
+    /**
+     * Tests whether a variable can be replaced in a variable name.
+     */
+    @Test
+    public void testReplaceInVariable() {
+        values.put("animal.1", "fox");
+        values.put("animal.2", "mouse");
+        values.put("species", "2");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        sub.setEnableSubstitutionInVariables(true);
+        assertEquals(
+                "Wrong result (1)",
+                "The mouse jumps over the lazy dog.",
+                sub.replace("The ${animal.${species}} jumps over the ${target}."));
+        values.put("species", "1");
+        assertEquals(
+                "Wrong result (2)",
+                "The fox jumps over the lazy dog.",
+                sub.replace("The ${animal.${species}} jumps over the ${target}."));
+        assertEquals(
+                "Wrong result (3)",
+                "The fox jumps over the lazy dog.",
+                sub.replace("The ${unknown.animal.${unknown.species:-1}:-fox} jumps over the ${unknow.target:-lazy dog}."));
+    }
+
+    /**
+     * Tests whether substitution in variable names is disabled per default.
+     */
+    @Test
+    public void testReplaceInVariableDisabled() {
+        values.put("animal.1", "fox");
+        values.put("animal.2", "mouse");
+        values.put("species", "2");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        assertEquals(
+                "Wrong result (1)",
+                "The ${animal.${species}} jumps over the lazy dog.",
+                sub.replace("The ${animal.${species}} jumps over the ${target}."));
+        assertEquals(
+                "Wrong result (2)",
+                "The ${animal.${species:-1}} jumps over the lazy dog.",
+                sub.replace("The ${animal.${species:-1}} jumps over the ${target}."));
+    }
+
+    /**
+     * Tests complex and recursive substitution in variable names.
+     */
+    @Test
+    public void testReplaceInVariableRecursive() {
+        values.put("animal.2", "brown fox");
+        values.put("animal.1", "white mouse");
+        values.put("color", "white");
+        values.put("species.white", "1");
+        values.put("species.brown", "2");
+        final StrSubstitutor sub = new StrSubstitutor(values);
+        sub.setEnableSubstitutionInVariables(true);
+        assertEquals(
+                "Wrong result (1)",
+                "The white mouse jumps over the lazy dog.",
+                sub.replace("The ${animal.${species.${color}}} jumps over the ${target}."));
+        assertEquals(
+                "Wrong result (2)",
+                "The brown fox jumps over the lazy dog.",
+                sub.replace("The ${animal.${species.${unknownColor:-brown}}} jumps over the ${target}."));
+    }
+
+    @Test
+    public void testDefaultValueDelimiters() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("animal", "fox");
+        map.put("target", "dog");
+
+        StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number:-1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "?:");
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number?:1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "||");
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number||1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "!");
+        assertEquals("The fox jumps over the lazy dog. 1234567890.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$', "");
+        sub.setValueDelimiterMatcher(null);
+        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+
+        sub = new StrSubstitutor(map, "${", "}", '$');
+        sub.setValueDelimiterMatcher(null);
+        assertEquals("The fox jumps over the lazy dog. ${undefined.number!1234567890}.",
+                sub.replace("The ${animal} jumps over the lazy ${target}. ${undefined.number!1234567890}."));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests protected.
+     */
+    @Test
+    public void testResolveVariable() {
+        final StrBuilder builder = new StrBuilder("Hi ${name}!");
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        final StrSubstitutor sub = new StrSubstitutor(map) {
+            @Override
+            protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) {
+                assertEquals("name", variableName);
+                assertSame(builder, buf);
+                assertEquals(3, startPos);
+                assertEquals(10, endPos);
+                return "jakarta";
+            }
+        };
+        sub.replaceIn(builder);
+        assertEquals("Hi jakarta!", builder.toString());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests constructor.
+     */
+    @Test
+    public void testConstructorNoArgs() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals("Hi ${name}", sub.replace("Hi ${name}"));
+    }
+
+    /**
+     * Tests constructor.
+     */
+    @Test
+    public void testConstructorMapPrefixSuffix() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        final StrSubstitutor sub = new StrSubstitutor(map, "<", ">");
+        assertEquals("Hi < commons", sub.replace("Hi $< <name>"));
+    }
+
+    /**
+     * Tests constructor.
+     */
+    @Test
+    public void testConstructorMapFull() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        StrSubstitutor sub = new StrSubstitutor(map, "<", ">", '!');
+        assertEquals("Hi < commons", sub.replace("Hi !< <name>"));
+        sub = new StrSubstitutor(map, "<", ">", '!', "||");
+        assertEquals("Hi < commons", sub.replace("Hi !< <name2||commons>"));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests get set.
+     */
+    @Test
+    public void testGetSetEscape() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertEquals('$', sub.getEscapeChar());
+        sub.setEscapeChar('<');
+        assertEquals('<', sub.getEscapeChar());
+    }
+
+    /**
+     * Tests get set.
+     */
+    @Test
+    public void testGetSetPrefix() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setVariablePrefix('<');
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.CharMatcher);
+
+        sub.setVariablePrefix("<<");
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+        try {
+            sub.setVariablePrefix((String) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertTrue(sub.getVariablePrefixMatcher() instanceof StrMatcher.StringMatcher);
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setVariablePrefixMatcher(matcher);
+        assertSame(matcher, sub.getVariablePrefixMatcher());
+        try {
+            sub.setVariablePrefixMatcher((StrMatcher) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertSame(matcher, sub.getVariablePrefixMatcher());
+    }
+
+    /**
+     * Tests get set.
+     */
+    @Test
+    public void testGetSetSuffix() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setVariableSuffix('<');
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.CharMatcher);
+
+        sub.setVariableSuffix("<<");
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
+        try {
+            sub.setVariableSuffix((String) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertTrue(sub.getVariableSuffixMatcher() instanceof StrMatcher.StringMatcher);
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setVariableSuffixMatcher(matcher);
+        assertSame(matcher, sub.getVariableSuffixMatcher());
+        try {
+            sub.setVariableSuffixMatcher((StrMatcher) null);
+            fail();
+        } catch (final IllegalArgumentException ex) {
+            // expected
+        }
+        assertSame(matcher, sub.getVariableSuffixMatcher());
+    }
+
+    /**
+     * Tests get set.
+     */
+    @Test
+    public void testGetSetValueDelimiter() {
+        final StrSubstitutor sub = new StrSubstitutor();
+        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setValueDelimiter(':');
+        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.CharMatcher);
+
+        sub.setValueDelimiter("||");
+        assertTrue(sub.getValueDelimiterMatcher() instanceof StrMatcher.StringMatcher);
+        sub.setValueDelimiter((String) null);
+        assertNull(sub.getValueDelimiterMatcher());
+
+        final StrMatcher matcher = StrMatcher.commaMatcher();
+        sub.setValueDelimiterMatcher(matcher);
+        assertSame(matcher, sub.getValueDelimiterMatcher());
+        sub.setValueDelimiterMatcher((StrMatcher) null);
+        assertNull(sub.getValueDelimiterMatcher());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Tests static.
+     */
+    @Test
+    public void testStaticReplace() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        assertEquals("Hi commons!", StrSubstitutor.replace("Hi ${name}!", map));
+    }
+
+    /**
+     * Tests static.
+     */
+    @Test
+    public void testStaticReplacePrefixSuffix() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("name", "commons");
+        assertEquals("Hi commons!", StrSubstitutor.replace("Hi <name>!", map, "<", ">"));
+    }
+
+    /**
+     * Tests interpolation with system properties.
+     */
+    @Test
+    public void testStaticReplaceSystemProperties() {
+        final StrBuilder buf = new StrBuilder();
+        buf.append("Hi ").append(System.getProperty("user.name"));
+        buf.append(", you are working with ");
+        buf.append(System.getProperty("os.name"));
+        buf.append(", your home directory is ");
+        buf.append(System.getProperty("user.home")).append('.');
+        assertEquals(buf.toString(), StrSubstitutor.replaceSystemProperties("Hi ${user.name}, you are "
+            + "working with ${os.name}, your home "
+            + "directory is ${user.home}."));
+    }
+
+    /**
+     * Test for LANG-1055: StrSubstitutor.replaceSystemProperties does not work consistently
+     */
+    @Test
+    public void testLANG1055() {
+        System.setProperty("test_key",  "test_value");
+
+        final String expected = StrSubstitutor.replace("test_key=${test_key}", System.getProperties());
+        final String actual = StrSubstitutor.replaceSystemProperties("test_key=${test_key}");
+        assertEquals(expected, actual);
+    }
+
+    /**
+     * Test the replace of a properties object
+     */
+    @Test
+    public void testSubstituteDefaultProperties(){
+        final String org = "${doesnotwork}";
+        System.setProperty("doesnotwork", "It works!");
+
+        // create a new Properties object with the System.getProperties as default
+        final Properties props = new Properties(System.getProperties());
+
+        assertEquals("It works!", StrSubstitutor.replace(org, props));
+    }
+
+    @Test
+    public void testSamePrefixAndSuffix() {
+        final Map<String, String> map = new HashMap<>();
+        map.put("greeting", "Hello");
+        map.put(" there ", "XXX");
+        map.put("name", "commons");
+        assertEquals("Hi commons!", StrSubstitutor.replace("Hi @name@!", map, "@", "@"));
+        assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@"));
+    }
+
+    @Test
+    public void testSubstitutePreserveEscape() {
+        final String org = "${not-escaped} $${escaped}";
+        final Map<String, String> map = new HashMap<>();
+        map.put("not-escaped", "value");
+
+        final StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
+        assertFalse(sub.isPreserveEscapes());
+        assertEquals("value ${escaped}", sub.replace(org));
+
+        sub.setPreserveEscapes(true);
+        assertTrue(sub.isPreserveEscapes());
+        assertEquals("value $${escaped}", sub.replace(org));
+    }
+
+    //-----------------------------------------------------------------------
+    private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) {
+        final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);
+        final StrSubstitutor sub = new StrSubstitutor(values);
+
+        // replace using String
+        assertEquals(expectedResult, sub.replace(replaceTemplate));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(replaceTemplate, 1, replaceTemplate.length() - 2));
+        }
+
+        // replace using char[]
+        final char[] chars = replaceTemplate.toCharArray();
+        assertEquals(expectedResult, sub.replace(chars));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(chars, 1, chars.length - 2));
+        }
+
+        // replace using StringBuffer
+        StringBuffer buf = new StringBuffer(replaceTemplate);
+        assertEquals(expectedResult, sub.replace(buf));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(buf, 1, buf.length() - 2));
+        }
+
+        // replace using StringBuilder
+        StringBuilder builder = new StringBuilder(replaceTemplate);
+        assertEquals(expectedResult, sub.replace(builder));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(builder, 1, builder.length() - 2));
+        }
+
+        // replace using StrBuilder
+        StrBuilder bld = new StrBuilder(replaceTemplate);
+        assertEquals(expectedResult, sub.replace(bld));
+        if (substring) {
+            assertEquals(expectedShortResult, sub.replace(bld, 1, bld.length() - 2));
+        }
+
+        // replace using object
+        final MutableObject<String> obj = new MutableObject<>(replaceTemplate);  // toString returns template
+        assertEquals(expectedResult, sub.replace(obj));
+
+        // replace in StringBuffer
+        buf = new StringBuffer(replaceTemplate);
+        assertTrue(sub.replaceIn(buf));
+        assertEquals(expectedResult, buf.toString());
+        if (substring) {
+            buf = new StringBuffer(replaceTemplate);
+            assertTrue(sub.replaceIn(buf, 1, buf.length() - 2));
+            assertEquals(expectedResult, buf.toString());  // expect full result as remainder is untouched
+        }
+
+        // replace in StringBuilder
+        builder = new StringBuilder(replaceTemplate);
+        assertTrue(sub.replaceIn(builder));
+        assertEquals(expectedResult, builder.toString());
+        if (substring) {
+            builder = new StringBuilder(replaceTemplate);
+            assertTrue(sub.replaceIn(builder, 1, builder.length() - 2));
+            assertEquals(expectedResult, builder.toString());  // expect full result as remainder is untouched
+        }
+
+        // replace in StrBuilder
+        bld = new StrBuilder(replaceTemplate);
+        assertTrue(sub.replaceIn(bld));
+        assertEquals(expectedResult, bld.toString());
+        if (substring) {
+            bld = new StrBuilder(replaceTemplate);
+            assertTrue(sub.replaceIn(bld, 1, bld.length() - 2));
+            assertEquals(expectedResult, bld.toString());  // expect full result as remainder is untouched
+        }
+    }
+
+    private void doTestNoReplace(final String replaceTemplate) {
+        final StrSubstitutor sub = new StrSubstitutor(values);
+
+        if (replaceTemplate == null) {
+            assertEquals(null, sub.replace((String) null));
+            assertEquals(null, sub.replace((String) null, 0, 100));
+            assertEquals(null, sub.replace((char[]) null));
+            assertEquals(null, sub.replace((char[]) null, 0, 100));
+            assertEquals(null, sub.replace((StringBuffer) null));
+            assertEquals(null, sub.replace((StringBuffer) null, 0, 100));
+            assertEquals(null, sub.replace((StrBuilder) null));
+            assertEquals(null, sub.replace((StrBuilder) null, 0, 100));
+            assertEquals(null, sub.replace((Object) null));
+            assertFalse(sub.replaceIn((StringBuffer) null));
+            assertFalse(sub.replaceIn((StringBuffer) null, 0, 100));
+            assertFalse(sub.replaceIn((StrBuilder) null));
+            assertFalse(sub.replaceIn((StrBuilder) null, 0, 100));
+        } else {
+            assertEquals(replaceTemplate, sub.replace(replaceTemplate));
+            final StrBuilder bld = new StrBuilder(replaceTemplate);
+            assertFalse(sub.replaceIn(bld));
+            assertEquals(replaceTemplate, bld.toString());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StrTokenizerTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StrTokenizerTest.java b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
new file mode 100644
index 0000000..7e86084
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
@@ -0,0 +1,913 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * Unit test for {@link StrTokenizer}.
+ */
+public class StrTokenizerTest {
+
+    private static final String CSV_SIMPLE_FIXTURE = "A,b,c";
+
+    private static final String TSV_SIMPLE_FIXTURE = "A\tb\tc";
+
+    private void checkClone(final StrTokenizer tokenizer) {
+        assertFalse(StrTokenizer.getCSVInstance() == tokenizer);
+        assertFalse(StrTokenizer.getTSVInstance() == tokenizer);
+    }
+
+    // -----------------------------------------------------------------------
+    @Test
+    public void test1() {
+
+        final String input = "a;b;c;\"d;\"\"e\";f; ; ;  ";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", "", "", "",};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test2() {
+
+        final String input = "a;b;c ;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c ", "d;\"e", "f", " ", " ", "",};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test3() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", " ", " ", "",};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test4() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f",};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test5() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d;\"e", "f", null, null, null,};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test6() {
+
+        final String input = "a;b; c;\"d;\"\"e\";f; ; ;";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterChar(';');
+        tok.setQuoteChar('"');
+        tok.setIgnoredMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        // tok.setTreatingEmptyAsNull(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", " c", "d;\"e", "f", null, null, null,};
+
+        int nextCount = 0;
+        while (tok.hasNext()) {
+            tok.next();
+            nextCount++;
+        }
+
+        int prevCount = 0;
+        while (tok.hasPrevious()) {
+            tok.previous();
+            prevCount++;
+        }
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+
+        assertTrue("could not cycle through entire token list" + " using the 'hasNext' and 'next' methods",
+                nextCount == expected.length);
+
+        assertTrue("could not cycle through entire token list" + " using the 'hasPrevious' and 'previous' methods",
+                prevCount == expected.length);
+
+    }
+
+    @Test
+    public void test7() {
+
+        final String input = "a   b c \"d e\" f ";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
+        tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "", "", "b", "c", "d e", "f", "",};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void test8() {
+
+        final String input = "a   b c \"d e\" f ";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setDelimiterMatcher(StrMatcher.spaceMatcher());
+        tok.setQuoteMatcher(StrMatcher.doubleQuoteMatcher());
+        tok.setIgnoredMatcher(StrMatcher.noneMatcher());
+        tok.setIgnoreEmptyTokens(true);
+        final String tokens[] = tok.getTokenArray();
+
+        final String expected[] = new String[]{"a", "b", "c", "d e", "f",};
+
+        assertEquals(Arrays.toString(tokens), expected.length, tokens.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals("token[" + i + "] was '" + tokens[i] + "' but was expected to be '" + expected[i] + "'",
+                    expected[i], tokens[i]);
+        }
+
+    }
+
+    @Test
+    public void testBasic1() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic2() {
+        final String input = "a \nb\fc";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic3() {
+        final String input = "a \nb\u0001\fc";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("b\u0001", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic4() {
+        final String input = "a \"b\" c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        assertEquals("a", tok.next());
+        assertEquals("\"b\"", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasic5() {
+        final String input = "a:b':c";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        assertEquals("a", tok.next());
+        assertEquals("b'", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicDelim1() {
+        final String input = "a:b:c";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicDelim2() {
+        final String input = "a:b:c";
+        final StrTokenizer tok = new StrTokenizer(input, ',');
+        assertEquals("a:b:c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testDelimString() {
+        final String input = "a##b##c";
+        final StrTokenizer tok = new StrTokenizer(input, "##");
+
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testDelimMatcher() {
+        final String input = "a/b\\c";
+        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[]{'/', '\\'});
+
+        final StrTokenizer tok = new StrTokenizer(input, delimMatcher);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testDelimMatcherQuoteMatcher() {
+        final String input = "`a`;`b`;`c`";
+        final StrMatcher delimMatcher = new StrMatcher.CharSetMatcher(new char[]{';'});
+        final StrMatcher quoteMatcher = new StrMatcher.CharSetMatcher(new char[]{'`'});
+
+        final StrTokenizer tok = new StrTokenizer(input, delimMatcher, quoteMatcher);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicEmpty1() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
+        assertEquals("a", tok.next());
+        assertEquals("", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicEmpty2() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals(null, tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted1() {
+        final String input = "a 'b' c";
+        final StrTokenizer tok = new StrTokenizer(input, ' ', '\'');
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted2() {
+        final String input = "a:'b':";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted3() {
+        final String input = "a:'b''c'";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b'c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted4() {
+        final String input = "a: 'b' 'c' :d";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b c", tok.next());
+        assertEquals("d", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted5() {
+        final String input = "a: 'b'x'c' :d";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bxc", tok.next());
+        assertEquals("d", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted6() {
+        final String input = "a:'b'\"c':d";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setQuoteMatcher(StrMatcher.quoteMatcher());
+        assertEquals("a", tok.next());
+        assertEquals("b\"c:d", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuoted7() {
+        final String input = "a:\"There's a reason here\":b";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setQuoteMatcher(StrMatcher.quoteMatcher());
+        assertEquals("a", tok.next());
+        assertEquals("There's a reason here", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicQuotedTrimmed1() {
+        final String input = "a: 'b' :";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicTrimmed1() {
+        final String input = "a: b :  ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicTrimmed2() {
+        final String input = "a:  b  :";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setTrimmerMatcher(StrMatcher.stringMatcher("  "));
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicIgnoreTrimmed1() {
+        final String input = "a: bIGNOREc : ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bc", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicIgnoreTrimmed2() {
+        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bc", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicIgnoreTrimmed3() {
+        final String input = "IGNOREaIGNORE: IGNORE bIGNOREc IGNORE : IGNORE ";
+        final StrTokenizer tok = new StrTokenizer(input, ':');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("  bc  ", tok.next());
+        assertEquals("  ", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    @Test
+    public void testBasicIgnoreTrimmed4() {
+        final String input = "IGNOREaIGNORE: IGNORE 'bIGNOREc'IGNORE'd' IGNORE : IGNORE ";
+        final StrTokenizer tok = new StrTokenizer(input, ':', '\'');
+        tok.setIgnoredMatcher(StrMatcher.stringMatcher("IGNORE"));
+        tok.setTrimmerMatcher(StrMatcher.trimMatcher());
+        tok.setIgnoreEmptyTokens(false);
+        tok.setEmptyTokenAsNull(true);
+        assertEquals("a", tok.next());
+        assertEquals("bIGNOREcd", tok.next());
+        assertEquals(null, tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testListArray() {
+        final String input = "a  b c";
+        final StrTokenizer tok = new StrTokenizer(input);
+        final String[] array = tok.getTokenArray();
+        final List<?> list = tok.getTokenList();
+        
+        assertEquals(Arrays.asList(array), list);
+        assertEquals(3, list.size());
+    }
+
+    //-----------------------------------------------------------------------
+    private void testCSV(final String data) {
+        this.testXSVAbc(StrTokenizer.getCSVInstance(data));
+        this.testXSVAbc(StrTokenizer.getCSVInstance(data.toCharArray()));
+    }
+
+    @Test
+    public void testCSVEmpty() {
+        this.testEmpty(StrTokenizer.getCSVInstance());
+        this.testEmpty(StrTokenizer.getCSVInstance(""));
+    }
+
+    @Test
+    public void testCSVSimple() {
+        this.testCSV(CSV_SIMPLE_FIXTURE);
+    }
+
+    @Test
+    public void testCSVSimpleNeedsTrim() {
+        this.testCSV("   " + CSV_SIMPLE_FIXTURE);
+        this.testCSV("   \n\t  " + CSV_SIMPLE_FIXTURE);
+        this.testCSV("   \n  " + CSV_SIMPLE_FIXTURE + "\n\n\r");
+    }
+
+    void testEmpty(final StrTokenizer tokenizer) {
+        this.checkClone(tokenizer);
+        assertFalse(tokenizer.hasNext());
+        assertFalse(tokenizer.hasPrevious());
+        assertEquals(null, tokenizer.nextToken());
+        assertEquals(0, tokenizer.size());
+        try {
+            tokenizer.next();
+            fail();
+        } catch (final NoSuchElementException ex) {}
+    }
+
+    @Test
+    public void testGetContent() {
+        final String input = "a   b c \"d e\" f ";
+        StrTokenizer tok = new StrTokenizer(input);
+        assertEquals(input, tok.getContent());
+
+        tok = new StrTokenizer(input.toCharArray());
+        assertEquals(input, tok.getContent());
+        
+        tok = new StrTokenizer();
+        assertEquals(null, tok.getContent());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testChaining() {
+        final StrTokenizer tok = new StrTokenizer();
+        assertEquals(tok, tok.reset());
+        assertEquals(tok, tok.reset(""));
+        assertEquals(tok, tok.reset(new char[0]));
+        assertEquals(tok, tok.setDelimiterChar(' '));
+        assertEquals(tok, tok.setDelimiterString(" "));
+        assertEquals(tok, tok.setDelimiterMatcher(null));
+        assertEquals(tok, tok.setQuoteChar(' '));
+        assertEquals(tok, tok.setQuoteMatcher(null));
+        assertEquals(tok, tok.setIgnoredChar(' '));
+        assertEquals(tok, tok.setIgnoredMatcher(null));
+        assertEquals(tok, tok.setTrimmerMatcher(null));
+        assertEquals(tok, tok.setEmptyTokenAsNull(false));
+        assertEquals(tok, tok.setIgnoreEmptyTokens(false));
+    }
+
+    /**
+     * Tests that the {@link StrTokenizer#clone()} clone method catches {@link CloneNotSupportedException} and returns
+     * <code>null</code>.
+     */
+    @Test
+    public void testCloneNotSupportedException() {
+        final Object notCloned = new StrTokenizer() {
+            @Override
+            Object cloneReset() throws CloneNotSupportedException {
+                throw new CloneNotSupportedException("test");
+            }
+        }.clone();
+        assertNull(notCloned);
+    }
+
+    @Test
+    public void testCloneNull() {
+        final StrTokenizer tokenizer = new StrTokenizer((char[]) null);
+        // Start sanity check
+        assertEquals(null, tokenizer.nextToken());
+        tokenizer.reset();
+        assertEquals(null, tokenizer.nextToken());
+        // End sanity check
+        final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
+        tokenizer.reset();
+        assertEquals(null, tokenizer.nextToken());
+        assertEquals(null, clonedTokenizer.nextToken());
+    }
+
+    @Test
+    public void testCloneReset() {
+        final char[] input = new char[]{'a'};
+        final StrTokenizer tokenizer = new StrTokenizer(input);
+        // Start sanity check
+        assertEquals("a", tokenizer.nextToken());
+        tokenizer.reset(input);
+        assertEquals("a", tokenizer.nextToken());
+        // End sanity check
+        final StrTokenizer clonedTokenizer = (StrTokenizer) tokenizer.clone();
+        input[0] = 'b';
+        tokenizer.reset(input);
+        assertEquals("b", tokenizer.nextToken());
+        assertEquals("a", clonedTokenizer.nextToken());
+    }
+  
+    // -----------------------------------------------------------------------
+    @Test
+    public void testConstructor_String() {
+        StrTokenizer tok = new StrTokenizer("a b");
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer("");
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((String) null);
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructor_String_char() {
+        StrTokenizer tok = new StrTokenizer("a b", ' ');
+        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer("", ' ');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((String) null, ' ');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructor_String_char_char() {
+        StrTokenizer tok = new StrTokenizer("a b", ' ', '"');
+        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
+        assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer("", ' ', '"');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((String) null, ' ', '"');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructor_charArray() {
+        StrTokenizer tok = new StrTokenizer("a b".toCharArray());
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer(new char[0]);
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((char[]) null);
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructor_charArray_char() {
+        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ');
+        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer(new char[0], ' ');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((char[]) null, ' ');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testConstructor_charArray_char_char() {
+        StrTokenizer tok = new StrTokenizer("a b".toCharArray(), ' ', '"');
+        assertEquals(1, tok.getDelimiterMatcher().isMatch(" ".toCharArray(), 0, 0, 1));
+        assertEquals(1, tok.getQuoteMatcher().isMatch("\"".toCharArray(), 0, 0, 1));
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer(new char[0], ' ', '"');
+        assertFalse(tok.hasNext());
+        
+        tok = new StrTokenizer((char[]) null, ' ', '"');
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReset() {
+        final StrTokenizer tok = new StrTokenizer("a b c");
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok.reset();
+        assertEquals("a", tok.next());
+        assertEquals("b", tok.next());
+        assertEquals("c", tok.next());
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReset_String() {
+        final StrTokenizer tok = new StrTokenizer("x x x");
+        tok.reset("d e");
+        assertEquals("d", tok.next());
+        assertEquals("e", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok.reset((String) null);
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testReset_charArray() {
+        final StrTokenizer tok = new StrTokenizer("x x x");
+        
+        final char[] array = new char[] {'a', 'b', 'c'};
+        tok.reset(array);
+        assertEquals("abc", tok.next());
+        assertFalse(tok.hasNext());
+        
+        tok.reset((char[]) null);
+        assertFalse(tok.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTSV() {
+        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE));
+        this.testXSVAbc(StrTokenizer.getTSVInstance(TSV_SIMPLE_FIXTURE.toCharArray()));
+    }
+
+    @Test
+    public void testTSVEmpty() {
+        this.testEmpty(StrTokenizer.getTSVInstance());
+        this.testEmpty(StrTokenizer.getTSVInstance(""));
+    }
+
+    void testXSVAbc(final StrTokenizer tokenizer) {
+        this.checkClone(tokenizer);
+        assertEquals(-1, tokenizer.previousIndex());
+        assertEquals(0, tokenizer.nextIndex());
+        assertEquals(null, tokenizer.previousToken());
+        assertEquals("A", tokenizer.nextToken());
+        assertEquals(1, tokenizer.nextIndex());
+        assertEquals("b", tokenizer.nextToken());
+        assertEquals(2, tokenizer.nextIndex());
+        assertEquals("c", tokenizer.nextToken());
+        assertEquals(3, tokenizer.nextIndex());
+        assertEquals(null, tokenizer.nextToken());
+        assertEquals(3, tokenizer.nextIndex());
+        assertEquals("c", tokenizer.previousToken());
+        assertEquals(2, tokenizer.nextIndex());
+        assertEquals("b", tokenizer.previousToken());
+        assertEquals(1, tokenizer.nextIndex());
+        assertEquals("A", tokenizer.previousToken());
+        assertEquals(0, tokenizer.nextIndex());
+        assertEquals(null, tokenizer.previousToken());
+        assertEquals(0, tokenizer.nextIndex());
+        assertEquals(-1, tokenizer.previousIndex());
+        assertEquals(3, tokenizer.size());
+    }
+
+    @Test
+    public void testIteration() {
+        final StrTokenizer tkn = new StrTokenizer("a b c");
+        assertFalse(tkn.hasPrevious());
+        try {
+            tkn.previous();
+            fail();
+        } catch (final NoSuchElementException ex) {}
+        assertTrue(tkn.hasNext());
+        
+        assertEquals("a", tkn.next());
+        try {
+            tkn.remove();
+            fail();
+        } catch (final UnsupportedOperationException ex) {}
+        try {
+            tkn.set("x");
+            fail();
+        } catch (final UnsupportedOperationException ex) {}
+        try {
+            tkn.add("y");
+            fail();
+        } catch (final UnsupportedOperationException ex) {}
+        assertTrue(tkn.hasPrevious());
+        assertTrue(tkn.hasNext());
+        
+        assertEquals("b", tkn.next());
+        assertTrue(tkn.hasPrevious());
+        assertTrue(tkn.hasNext());
+        
+        assertEquals("c", tkn.next());
+        assertTrue(tkn.hasPrevious());
+        assertFalse(tkn.hasNext());
+        
+        try {
+            tkn.next();
+            fail();
+        } catch (final NoSuchElementException ex) {}
+        assertTrue(tkn.hasPrevious());
+        assertFalse(tkn.hasNext());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTokenizeSubclassInputChange() {
+        final StrTokenizer tkn = new StrTokenizer("a b c d e") {
+            @Override
+            protected List<String> tokenize(final char[] chars, final int offset, final int count) {
+                return super.tokenize("w x y z".toCharArray(), 2, 5);
+            }
+        };
+        assertEquals("x", tkn.next());
+        assertEquals("y", tkn.next());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testTokenizeSubclassOutputChange() {
+        final StrTokenizer tkn = new StrTokenizer("a b c") {
+            @Override
+            protected List<String> tokenize(final char[] chars, final int offset, final int count) {
+                final List<String> list = super.tokenize(chars, offset, count);
+                Collections.reverse(list);
+                return list;
+            }
+        };
+        assertEquals("c", tkn.next());
+        assertEquals("b", tkn.next());
+        assertEquals("a", tkn.next());
+    }
+
+    //-----------------------------------------------------------------------
+    @Test
+    public void testToString() {
+        final StrTokenizer tkn = new StrTokenizer("a b c d e");
+        assertEquals("StrTokenizer[not tokenized yet]", tkn.toString());
+        tkn.next();
+        assertEquals("StrTokenizer[a, b, c, d, e]", tkn.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
new file mode 100644
index 0000000..f716763
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
@@ -0,0 +1,601 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import static org.apache.commons.text.StringEscapeUtils.escapeXSI;
+import static org.apache.commons.text.StringEscapeUtils.unescapeXSI;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit tests for {@link StringEscapeUtils}.
+ *
+ * <p>
+ * This code has been adapted from Apache Commons Lang 3.5.
+ * </p>
+ *
+ */
+public class StringEscapeUtilsTest {
+    private final static String FOO = "foo";
+
+    @Test
+    public void testConstructor() {
+        assertNotNull(new StringEscapeUtils());
+        final Constructor<?>[] cons = StringEscapeUtils.class.getDeclaredConstructors();
+        assertEquals(1, cons.length);
+        assertTrue(Modifier.isPublic(cons[0].getModifiers()));
+        assertTrue(Modifier.isPublic(StringEscapeUtils.class.getModifiers()));
+        assertFalse(Modifier.isFinal(StringEscapeUtils.class.getModifiers()));
+    }
+
+    @Test
+    public void testEscapeJava() throws IOException {
+        assertEquals(null, StringEscapeUtils.escapeJava(null));
+        try {
+            StringEscapeUtils.ESCAPE_JAVA.translate(null, null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+        try {
+            StringEscapeUtils.ESCAPE_JAVA.translate("", null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+
+        assertEscapeJava("empty string", "", "");
+        assertEscapeJava(FOO, FOO);
+        assertEscapeJava("tab", "\\t", "\t");
+        assertEscapeJava("backslash", "\\\\", "\\");
+        assertEscapeJava("single quote should not be escaped", "'", "'");
+        assertEscapeJava("\\\\\\b\\t\\r", "\\\b\t\r");
+        assertEscapeJava("\\u1234", "\u1234");
+        assertEscapeJava("\\u0234", "\u0234");
+        assertEscapeJava("\\u00EF", "\u00ef");
+        assertEscapeJava("\\u0001", "\u0001");
+        assertEscapeJava("Should use capitalized Unicode hex", "\\uABCD", "\uabcd");
+
+        assertEscapeJava("He didn't say, \\\"stop!\\\"",
+                "He didn't say, \"stop!\"");
+        assertEscapeJava("non-breaking space", "This space is non-breaking:" + "\\u00A0",
+                "This space is non-breaking:\u00a0");
+        assertEscapeJava("\\uABCD\\u1234\\u012C",
+                "\uABCD\u1234\u012C");
+    }
+
+    /**
+     * Tests https://issues.apache.org/jira/browse/LANG-421
+     */
+    @Test
+    public void testEscapeJavaWithSlash() {
+        final String input = "String with a slash (/) in it";
+
+        final String expected = input;
+        final String actual = StringEscapeUtils.escapeJava(input);
+
+        /**
+         * In 2.4 StringEscapeUtils.escapeJava(String) escapes '/' characters, which are not a valid character to escape
+         * in a Java string.
+         */
+        assertEquals(expected, actual);
+    }
+
+    private void assertEscapeJava(final String escaped, final String original) throws IOException {
+        assertEscapeJava(null, escaped, original);
+    }
+
+    private void assertEscapeJava(String message, final String expected, final String original) throws IOException {
+        final String converted = StringEscapeUtils.escapeJava(original);
+        message = "escapeJava(String) failed" + (message == null ? "" : (": " + message));
+        assertEquals(message, expected, converted);
+
+        final StringWriter writer = new StringWriter();
+        StringEscapeUtils.ESCAPE_JAVA.translate(original, writer);
+        assertEquals(expected, writer.toString());
+    }
+
+    @Test
+    public void testUnescapeJava() throws IOException {
+        assertEquals(null, StringEscapeUtils.unescapeJava(null));
+        try {
+            StringEscapeUtils.UNESCAPE_JAVA.translate(null, null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+        try {
+            StringEscapeUtils.UNESCAPE_JAVA.translate("", null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+        try {
+            StringEscapeUtils.unescapeJava("\\u02-3");
+            fail();
+        } catch (final RuntimeException ex) {
+        }
+
+        assertUnescapeJava("", "");
+        assertUnescapeJava("test", "test");
+        assertUnescapeJava("\ntest\b", "\\ntest\\b");
+        assertUnescapeJava("\u123425foo\ntest\b", "\\u123425foo\\ntest\\b");
+        assertUnescapeJava("'\foo\teste\r", "\\'\\foo\\teste\\r");
+        assertUnescapeJava("", "\\");
+        //foo
+        assertUnescapeJava("lowercase Unicode", "\uABCDx", "\\uabcdx");
+        assertUnescapeJava("uppercase Unicode", "\uABCDx", "\\uABCDx");
+        assertUnescapeJava("Unicode as final character", "\uABCD", "\\uabcd");
+    }
+
+    private void assertUnescapeJava(final String unescaped, final String original) throws IOException {
+        assertUnescapeJava(null, unescaped, original);
+    }
+
+    private void assertUnescapeJava(final String message, final String unescaped, final String original) throws IOException {
+        final String expected = unescaped;
+        final String actual = StringEscapeUtils.unescapeJava(original);
+
+        assertEquals("unescape(String) failed" +
+                        (message == null ? "" : (": " + message)) +
+                        ": expected '" + StringEscapeUtils.escapeJava(expected) +
+                        // we escape this so we can see it in the error message
+                        "' actual '" + StringEscapeUtils.escapeJava(actual) + "'",
+                expected, actual);
+
+        final StringWriter writer = new StringWriter();
+        StringEscapeUtils.UNESCAPE_JAVA.translate(original, writer);
+        assertEquals(unescaped, writer.toString());
+
+    }
+
+    @Test
+    public void testEscapeEcmaScript() {
+        assertEquals(null, StringEscapeUtils.escapeEcmaScript(null));
+        try {
+            StringEscapeUtils.ESCAPE_ECMASCRIPT.translate(null, null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+        try {
+            StringEscapeUtils.ESCAPE_ECMASCRIPT.translate("", null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+
+        assertEquals("He didn\\'t say, \\\"stop!\\\"", StringEscapeUtils.escapeEcmaScript("He didn't say, \"stop!\""));
+        assertEquals("document.getElementById(\\\"test\\\").value = \\'<script>alert(\\'aaa\\');<\\/script>\\';",
+                StringEscapeUtils.escapeEcmaScript("document.getElementById(\"test\").value = '<script>alert('aaa');</script>';"));
+    }
+
+
+    // HTML and XML
+    //--------------------------------------------------------------
+
+    private static final String[][] HTML_ESCAPES = {
+            {"no escaping", "plain text", "plain text"},
+            {"no escaping", "plain text", "plain text"},
+            {"empty string", "", ""},
+            {"null", null, null},
+            {"ampersand", "bread &amp; butter", "bread & butter"},
+            {"quotes", "&quot;bread&quot; &amp; butter", "\"bread\" & butter"},
+            {"final character only", "greater than &gt;", "greater than >"},
+            {"first character only", "&lt; less than", "< less than"},
+            {"apostrophe", "Huntington's chorea", "Huntington's chorea"},
+            {"languages", "English,Fran&ccedil;ais,\u65E5\u672C\u8A9E (nihongo)", "English,Fran\u00E7ais,\u65E5\u672C\u8A9E (nihongo)"},
+            {"8-bit ascii shouldn't number-escape", "\u0080\u009F", "\u0080\u009F"},
+    };
+
+    @Test
+    public void testEscapeHtml() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[1];
+            final String original = element[2];
+            assertEquals(message, expected, StringEscapeUtils.escapeHtml4(original));
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML4.translate(original, sw);
+            } catch (final IOException e) {
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(message, expected, actual);
+        }
+    }
+
+    @Test
+    public void testEscapeHtml4Once() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[1];
+            final String original = element[2];
+            assertEquals(message, expected, StringEscapeUtils.escapeHtml4Once(original));
+            assertEquals(message, expected, StringEscapeUtils.escapeHtml4Once(expected));
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML4_ONCE.translate(original, sw);
+            } catch (final IOException e) {
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(message, expected, actual);
+            final StringWriter sw2 = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML4_ONCE.translate(expected, sw2);
+            } catch (final IOException e) {
+            }
+            final String actual2 = original == null ? null : sw2.toString();
+            assertEquals(message, expected, actual2);
+        }
+    }
+
+    @Test
+    public void testEscapeHtml3Once() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[1];
+            final String original = element[2];
+            assertEquals(message, expected, StringEscapeUtils.escapeHtml3Once(original));
+            assertEquals(message, expected, StringEscapeUtils.escapeHtml3Once(expected));
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML3_ONCE.translate(original, sw);
+            } catch (final IOException e) {
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(message, expected, actual);
+            final StringWriter sw2 = new StringWriter();
+            try {
+                StringEscapeUtils.ESCAPE_HTML3_ONCE.translate(expected, sw2);
+            } catch (final IOException e) {
+            }
+            final String actual2 = original == null ? null : sw2.toString();
+            assertEquals(message, expected, actual2);
+        }
+    }
+
+    @Test
+    public void testUnescapeHtml4() {
+        for (final String[] element : HTML_ESCAPES) {
+            final String message = element[0];
+            final String expected = element[2];
+            final String original = element[1];
+            assertEquals(message, expected, StringEscapeUtils.unescapeHtml4(original));
+
+            final StringWriter sw = new StringWriter();
+            try {
+                StringEscapeUtils.UNESCAPE_HTML4.translate(original, sw);
+            } catch (final IOException e) {
+            }
+            final String actual = original == null ? null : sw.toString();
+            assertEquals(message, expected, actual);
+        }
+        // \u00E7 is a cedilla (c with wiggle under)
+        // note that the test string must be 7-bit-clean (Unicode escaped) or else it will compile incorrectly
+        // on some locales        
+        assertEquals("funny chars pass through OK", "Fran\u00E7ais", StringEscapeUtils.unescapeHtml4("Fran\u00E7ais"));
+
+        assertEquals("Hello&;World", StringEscapeUtils.unescapeHtml4("Hello&;World"));
+        assertEquals("Hello&#;World", StringEscapeUtils.unescapeHtml4("Hello&#;World"));
+        assertEquals("Hello&# ;World", StringEscapeUtils.unescapeHtml4("Hello&# ;World"));
+        assertEquals("Hello&##;World", StringEscapeUtils.unescapeHtml4("Hello&##;World"));
+    }
+
+    @Test
+    public void testUnescapeHexCharsHtml() {
+        // Simple easy to grok test 
+        assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#x80;&#x9F;"));
+        assertEquals("hex number unescape", "\u0080\u009F", StringEscapeUtils.unescapeHtml4("&#X80;&#X9F;"));
+        // Test all Character values:
+        for (char i = Character.MIN_VALUE; i < Character.MAX_VALUE; i++) {
+            final Character c1 = new Character(i);
+            final Character c2 = new Character((char)(i+1));
+            final String expected = c1.toString() + c2.toString();
+            final String escapedC1 = "&#x" + Integer.toHexString((c1.charValue())) + ";";
+            final String escapedC2 = "&#x" + Integer.toHexString((c2.charValue())) + ";";
+            assertEquals("hex number unescape index " + (int)i, expected, StringEscapeUtils.unescapeHtml4(escapedC1 + escapedC2));
+        }
+    }
+
+    @Test
+    public void testUnescapeUnknownEntity() throws Exception {
+        assertEquals("&zzzz;", StringEscapeUtils.unescapeHtml4("&zzzz;"));
+    }
+
+    @Test
+    public void testEscapeHtmlVersions() throws Exception {
+        assertEquals("&Beta;", StringEscapeUtils.escapeHtml4("\u0392"));
+        assertEquals("\u0392", StringEscapeUtils.unescapeHtml4("&Beta;"));
+
+        // TODO: refine API for escaping/unescaping specific HTML versions
+    }
+
+
+
+    @Test
+    public void testEscapeXml10() throws Exception {
+        assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml10("a<b>c\"d'e&f"));
+        assertEquals("XML 1.0 should not escape \t \n \r",
+                "a\tb\rc\nd", StringEscapeUtils.escapeXml10("a\tb\rc\nd"));
+        assertEquals("XML 1.0 should omit most #x0-x8 | #xb | #xc | #xe-#x19",
+                "ab", StringEscapeUtils.escapeXml10("a\u0000\u0001\u0008\u000b\u000c\u000e\u001fb"));
+        assertEquals("XML 1.0 should omit #xd800-#xdfff",
+                "a\ud7ff  \ue000b", StringEscapeUtils.escapeXml10("a\ud7ff\ud800 \udfff \ue000b"));
+        assertEquals("XML 1.0 should omit #xfffe | #xffff",
+                "a\ufffdb", StringEscapeUtils.escapeXml10("a\ufffd\ufffe\uffffb"));
+        assertEquals("XML 1.0 should escape #x7f-#x84 | #x86 - #x9f, for XML 1.1 compatibility",
+                "a\u007e&#127;&#132;\u0085&#134;&#159;\u00a0b", StringEscapeUtils.escapeXml10("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"));
+    }
+
+    @Test
+    public void testEscapeXml11() throws Exception {
+        assertEquals("a&lt;b&gt;c&quot;d&apos;e&amp;f", StringEscapeUtils.escapeXml11("a<b>c\"d'e&f"));
+        assertEquals("XML 1.1 should not escape \t \n \r",
+                "a\tb\rc\nd", StringEscapeUtils.escapeXml11("a\tb\rc\nd"));
+        assertEquals("XML 1.1 should omit #x0",
+                "ab", StringEscapeUtils.escapeXml11("a\u0000b"));
+        assertEquals("XML 1.1 should escape #x1-x8 | #xb | #xc | #xe-#x19",
+                "a&#1;&#8;&#11;&#12;&#14;&#31;b", StringEscapeUtils.escapeXml11("a\u0001\u0008\u000b\u000c\u000e\u001fb"));
+        assertEquals("XML 1.1 should escape #x7F-#x84 | #x86-#x9F",
+                "a\u007e&#127;&#132;\u0085&#134;&#159;\u00a0b", StringEscapeUtils.escapeXml11("a\u007e\u007f\u0084\u0085\u0086\u009f\u00a0b"));
+        assertEquals("XML 1.1 should omit #xd800-#xdfff",
+                "a\ud7ff  \ue000b", StringEscapeUtils.escapeXml11("a\ud7ff\ud800 \udfff \ue000b"));
+        assertEquals("XML 1.1 should omit #xfffe | #xffff",
+                "a\ufffdb", StringEscapeUtils.escapeXml11("a\ufffd\ufffe\uffffb"));
+    }
+
+    /**
+     * Reverse of the above.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/LANG-729">LANG-729</a>
+     */
+    @Test
+    public void testUnescapeXmlSupplementaryCharacters() {
+        assertEquals("Supplementary character must be represented using a single escape", "\uD84C\uDFB4",
+                StringEscapeUtils.unescapeXml("&#144308;") );
+
+        assertEquals("Supplementary characters mixed with basic characters should be decoded correctly", "a b c \uD84C\uDFB4",
+                StringEscapeUtils.unescapeXml("a b c &#144308;") );
+    }
+
+    // Tests issue #38569
+    // http://issues.apache.org/bugzilla/show_bug.cgi?id=38569
+    @Test
+    public void testStandaloneAmphersand() {
+        assertEquals("<P&O>", StringEscapeUtils.unescapeHtml4("&lt;P&O&gt;"));
+        assertEquals("test & <", StringEscapeUtils.unescapeHtml4("test & &lt;"));
+        assertEquals("<P&O>", StringEscapeUtils.unescapeXml("&lt;P&O&gt;"));
+        assertEquals("test & <", StringEscapeUtils.unescapeXml("test & &lt;"));
+    }
+
+    @Test
+    public void testLang313() {
+        assertEquals("& &", StringEscapeUtils.unescapeHtml4("& &amp;"));
+    }
+
+    @Test
+    public void testEscapeCsvString() throws Exception {
+        assertEquals("foo.bar",            StringEscapeUtils.escapeCsv("foo.bar"));
+        assertEquals("\"foo,bar\"",        StringEscapeUtils.escapeCsv("foo,bar"));
+        assertEquals("\"foo\nbar\"",       StringEscapeUtils.escapeCsv("foo\nbar"));
+        assertEquals("\"foo\rbar\"",       StringEscapeUtils.escapeCsv("foo\rbar"));
+        assertEquals("\"foo\"\"bar\"",     StringEscapeUtils.escapeCsv("foo\"bar"));
+        assertEquals("foo\uD84C\uDFB4bar", StringEscapeUtils.escapeCsv("foo\uD84C\uDFB4bar"));
+        assertEquals("",   StringEscapeUtils.escapeCsv(""));
+        assertEquals(null, StringEscapeUtils.escapeCsv(null));
+    }
+
+    @Test
+    public void testEscapeCsvWriter() throws Exception {
+        checkCsvEscapeWriter("foo.bar",            "foo.bar");
+        checkCsvEscapeWriter("\"foo,bar\"",        "foo,bar");
+        checkCsvEscapeWriter("\"foo\nbar\"",       "foo\nbar");
+        checkCsvEscapeWriter("\"foo\rbar\"",       "foo\rbar");
+        checkCsvEscapeWriter("\"foo\"\"bar\"",     "foo\"bar");
+        checkCsvEscapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
+        checkCsvEscapeWriter("", null);
+        checkCsvEscapeWriter("", "");
+    }
+
+    private void checkCsvEscapeWriter(final String expected, final String value) {
+        try {
+            final StringWriter writer = new StringWriter();
+            StringEscapeUtils.ESCAPE_CSV.translate(value, writer);
+            assertEquals(expected, writer.toString());
+        } catch (final IOException e) {
+            fail("Threw: " + e);
+        }
+    }
+
+    @Test
+    public void testUnescapeCsvString() throws Exception {
+        assertEquals("foo.bar",              StringEscapeUtils.unescapeCsv("foo.bar"));
+        assertEquals("foo,bar",              StringEscapeUtils.unescapeCsv("\"foo,bar\""));
+        assertEquals("foo\nbar",             StringEscapeUtils.unescapeCsv("\"foo\nbar\""));
+        assertEquals("foo\rbar",             StringEscapeUtils.unescapeCsv("\"foo\rbar\""));
+        assertEquals("foo\"bar",             StringEscapeUtils.unescapeCsv("\"foo\"\"bar\""));
+        assertEquals("foo\uD84C\uDFB4bar",   StringEscapeUtils.unescapeCsv("foo\uD84C\uDFB4bar"));
+        assertEquals("",   StringEscapeUtils.unescapeCsv(""));
+        assertEquals(null, StringEscapeUtils.unescapeCsv(null));
+
+        assertEquals("\"foo.bar\"",          StringEscapeUtils.unescapeCsv("\"foo.bar\""));
+    }
+
+    @Test
+    public void testUnescapeCsvWriter() throws Exception {
+        checkCsvUnescapeWriter("foo.bar",            "foo.bar");
+        checkCsvUnescapeWriter("foo,bar",            "\"foo,bar\"");
+        checkCsvUnescapeWriter("foo\nbar",           "\"foo\nbar\"");
+        checkCsvUnescapeWriter("foo\rbar",           "\"foo\rbar\"");
+        checkCsvUnescapeWriter("foo\"bar",           "\"foo\"\"bar\"");
+        checkCsvUnescapeWriter("foo\uD84C\uDFB4bar", "foo\uD84C\uDFB4bar");
+        checkCsvUnescapeWriter("", null);
+        checkCsvUnescapeWriter("", "");
+
+        checkCsvUnescapeWriter("\"foo.bar\"",        "\"foo.bar\"");
+    }
+
+    private void checkCsvUnescapeWriter(final String expected, final String value) {
+        try {
+            final StringWriter writer = new StringWriter();
+            StringEscapeUtils.UNESCAPE_CSV.translate(value, writer);
+            assertEquals(expected, writer.toString());
+        } catch (final IOException e) {
+            fail("Threw: " + e);
+        }
+    }
+
+    /**
+     * Tests // https://issues.apache.org/jira/browse/LANG-480
+     */
+    @Test
+    public void testEscapeHtmlHighUnicode() {
+        // this is the utf8 representation of the character:
+        // COUNTING ROD UNIT DIGIT THREE
+        // in Unicode
+        // codepoint: U+1D362
+        final byte[] data = new byte[] { (byte)0xF0, (byte)0x9D, (byte)0x8D, (byte)0xA2 };
+
+        final String original = new String(data, Charset.forName("UTF8"));
+
+        final String escaped = StringEscapeUtils.escapeHtml4( original );
+        assertEquals( "High Unicode should not have been escaped", original, escaped);
+
+        final String unescaped = StringEscapeUtils.unescapeHtml4( escaped );
+        assertEquals( "High Unicode should have been unchanged", original, unescaped);
+
+        // TODO: I think this should hold, needs further investigation
+        //        String unescapedFromEntity = StringEscapeUtils.unescapeHtml4( "&#119650;" );
+        //        assertEquals( "High Unicode should have been unescaped", original, unescapedFromEntity);
+    }
+
+    /**
+     * Tests https://issues.apache.org/jira/browse/LANG-339
+     */
+    @Test
+    public void testEscapeHiragana() {
+        // Some random Japanese Unicode characters
+        final String original = "\u304B\u304C\u3068";
+        final String escaped = StringEscapeUtils.escapeHtml4(original);
+        assertEquals( "Hiragana character Unicode behaviour should not be being escaped by escapeHtml4",
+                original, escaped);
+
+        final String unescaped = StringEscapeUtils.unescapeHtml4( escaped );
+
+        assertEquals( "Hiragana character Unicode behaviour has changed - expected no unescaping", escaped, unescaped);
+    }
+
+    /**
+     * Tests https://issues.apache.org/jira/browse/LANG-708
+     *
+     * @throws IOException
+     *             if an I/O error occurs
+     */
+    @Test
+    public void testLang708() throws IOException {
+        byte[] inputBytes = Files.readAllBytes(Paths.get("src/test/resources/stringEscapeUtilsTestData.txt"));
+        final String input = new String(inputBytes, StandardCharsets.UTF_8);
+        final String escaped = StringEscapeUtils.escapeEcmaScript(input);
+        // just the end:
+        assertTrue(escaped, escaped.endsWith("}]"));
+        // a little more:
+        assertTrue(escaped, escaped.endsWith("\"valueCode\\\":\\\"\\\"}]"));
+    }
+
+    /**
+     * Tests https://issues.apache.org/jira/browse/LANG-911
+     */
+    @Test
+    public void testLang911() {
+        final String bellsTest = "\ud83d\udc80\ud83d\udd14";
+        final String value = StringEscapeUtils.escapeJava(bellsTest);
+        final String valueTest = StringEscapeUtils.unescapeJava(value);
+        assertEquals(bellsTest, valueTest);
+    }
+
+    @Test
+    public void testEscapeJson() {
+        assertEquals(null, StringEscapeUtils.escapeJson(null));
+        try {
+            StringEscapeUtils.ESCAPE_JSON.translate(null, null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+        try {
+            StringEscapeUtils.ESCAPE_JSON.translate("", null);
+            fail();
+        } catch (final IOException ex) {
+            fail();
+        } catch (final IllegalArgumentException ex) {
+        }
+
+        assertEquals("He didn't say, \\\"stop!\\\"", StringEscapeUtils.escapeJson("He didn't say, \"stop!\""));
+
+        final String expected = "\\\"foo\\\" isn't \\\"bar\\\". specials: \\b\\r\\n\\f\\t\\\\\\/";
+        final String input ="\"foo\" isn't \"bar\". specials: \b\r\n\f\t\\/";
+
+        assertEquals(expected, StringEscapeUtils.escapeJson(input));
+    }
+
+    @Test
+    public void testBuilder() {
+        String result = StringEscapeUtils.builder(StringEscapeUtils.ESCAPE_XML10).escape("<").append(">").toString();
+        assertEquals("&lt;>", result);
+    }
+
+    @Test
+    public void testEscapeXSI() {
+        assertNull(null, escapeXSI(null));
+        assertEquals("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"", escapeXSI("He didn't say, \"Stop!\""));
+        assertEquals("\\\\", escapeXSI("\\"));
+        assertEquals("", escapeXSI("\n"));
+    }
+
+    @Test
+    public void testUnscapeXSI() {
+        assertNull(null, unescapeXSI(null));
+        assertEquals("\"", unescapeXSI("\\\""));
+        assertEquals("He didn't say, \"Stop!\"", unescapeXSI("He\\ didn\\'t\\ say,\\ \\\"Stop!\\\""));
+        assertEquals("\\", unescapeXSI("\\\\"));
+        assertEquals("", unescapeXSI("\\"));
+    }
+
+}
\ No newline at end of file


[09/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StrBuilderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StrBuilderTest.java b/src/test/java/org/apache/commons/text/beta/StrBuilderTest.java
deleted file mode 100644
index 91700f0..0000000
--- a/src/test/java/org/apache/commons/text/beta/StrBuilderTest.java
+++ /dev/null
@@ -1,2007 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.text.beta;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.nio.CharBuffer;
-import java.util.Arrays;
-
-/**
- * Unit tests for {@link StrBuilder}.
- */
-public class StrBuilderTest {
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testConstructors() {
-        final StrBuilder sb0 = new StrBuilder();
-        assertEquals(32, sb0.capacity());
-        assertEquals(0, sb0.length());
-        assertEquals(0, sb0.size());
-
-        final StrBuilder sb1 = new StrBuilder(32);
-        assertEquals(32, sb1.capacity());
-        assertEquals(0, sb1.length());
-        assertEquals(0, sb1.size());
-
-        final StrBuilder sb2 = new StrBuilder(0);
-        assertEquals(32, sb2.capacity());
-        assertEquals(0, sb2.length());
-        assertEquals(0, sb2.size());
-
-        final StrBuilder sb3 = new StrBuilder(-1);
-        assertEquals(32, sb3.capacity());
-        assertEquals(0, sb3.length());
-        assertEquals(0, sb3.size());
-
-        final StrBuilder sb4 = new StrBuilder(1);
-        assertEquals(1, sb4.capacity());
-        assertEquals(0, sb4.length());
-        assertEquals(0, sb4.size());
-
-        final StrBuilder sb5 = new StrBuilder((String) null);
-        assertEquals(32, sb5.capacity());
-        assertEquals(0, sb5.length());
-        assertEquals(0, sb5.size());
-
-        final StrBuilder sb6 = new StrBuilder("");
-        assertEquals(32, sb6.capacity());
-        assertEquals(0, sb6.length());
-        assertEquals(0, sb6.size());
-
-        final StrBuilder sb7 = new StrBuilder("foo");
-        assertEquals(35, sb7.capacity());
-        assertEquals(3, sb7.length());
-        assertEquals(3, sb7.size());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testChaining() {
-        final StrBuilder sb = new StrBuilder();
-        assertSame(sb, sb.setNewLineText(null));
-        assertSame(sb, sb.setNullText(null));
-        assertSame(sb, sb.setLength(1));
-        assertSame(sb, sb.setCharAt(0, 'a'));
-        assertSame(sb, sb.ensureCapacity(0));
-        assertSame(sb, sb.minimizeCapacity());
-        assertSame(sb, sb.clear());
-        assertSame(sb, sb.reverse());
-        assertSame(sb, sb.trim());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReadFromReader() throws Exception {
-        String s = "";
-        for (int i = 0; i < 100; ++i) {
-            final StrBuilder sb = new StrBuilder();
-            final int len = sb.readFrom(new StringReader(s));
-
-            assertEquals(s.length(), len);
-            assertEquals(s, sb.toString());
-
-            s += Integer.toString(i);
-        }
-    }
-
-    @Test
-    public void testReadFromReaderAppendsToEnd() throws Exception {
-        final StrBuilder sb = new StrBuilder("Test");
-        sb.readFrom(new StringReader(" 123"));
-        assertEquals("Test 123", sb.toString());
-    }
-
-    @Test
-    public void testReadFromCharBuffer() throws Exception {
-        String s = "";
-        for (int i = 0; i < 100; ++i) {
-            final StrBuilder sb = new StrBuilder();
-            final int len = sb.readFrom(CharBuffer.wrap(s));
-
-            assertEquals(s.length(), len);
-            assertEquals(s, sb.toString());
-
-            s += Integer.toString(i);
-        }
-    }
-
-    @Test
-    public void testReadFromCharBufferAppendsToEnd() throws Exception {
-        final StrBuilder sb = new StrBuilder("Test");
-        sb.readFrom(CharBuffer.wrap(" 123"));
-        assertEquals("Test 123", sb.toString());
-    }
-
-    @Test
-    public void testReadFromReadable() throws Exception {
-        String s = "";
-        for (int i = 0; i < 100; ++i) {
-            final StrBuilder sb = new StrBuilder();
-            final int len = sb.readFrom(new MockReadable(s));
-
-            assertEquals(s.length(), len);
-            assertEquals(s, sb.toString());
-
-            s += Integer.toString(i);
-        }
-    }
-
-    @Test
-    public void testReadFromReadableAppendsToEnd() throws Exception {
-        final StrBuilder sb = new StrBuilder("Test");
-        sb.readFrom(new MockReadable(" 123"));
-        assertEquals("Test 123", sb.toString());
-    }
-
-    private static class MockReadable implements Readable {
-
-        private final CharBuffer src;
-
-        public MockReadable(final String src) {
-            this.src = CharBuffer.wrap(src);
-        }
-
-        @Override
-        public int read(final CharBuffer cb) throws IOException {
-            return src.read(cb);
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testGetSetNewLineText() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(null, sb.getNewLineText());
-
-        sb.setNewLineText("#");
-        assertEquals("#", sb.getNewLineText());
-
-        sb.setNewLineText("");
-        assertEquals("", sb.getNewLineText());
-
-        sb.setNewLineText((String) null);
-        assertEquals(null, sb.getNewLineText());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testGetSetNullText() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(null, sb.getNullText());
-
-        sb.setNullText("null");
-        assertEquals("null", sb.getNullText());
-
-        sb.setNullText("");
-        assertEquals(null, sb.getNullText());
-
-        sb.setNullText("NULL");
-        assertEquals("NULL", sb.getNullText());
-
-        sb.setNullText((String) null);
-        assertEquals(null, sb.getNullText());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCapacityAndLength() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(32, sb.capacity());
-        assertEquals(0, sb.length());
-        assertEquals(0, sb.size());
-        assertTrue(sb.isEmpty());
-
-        sb.minimizeCapacity();
-        assertEquals(0, sb.capacity());
-        assertEquals(0, sb.length());
-        assertEquals(0, sb.size());
-        assertTrue(sb.isEmpty());
-
-        sb.ensureCapacity(32);
-        assertTrue(sb.capacity() >= 32);
-        assertEquals(0, sb.length());
-        assertEquals(0, sb.size());
-        assertTrue(sb.isEmpty());
-
-        sb.append("foo");
-        assertTrue(sb.capacity() >= 32);
-        assertEquals(3, sb.length());
-        assertEquals(3, sb.size());
-        assertTrue(sb.isEmpty() == false);
-
-        sb.clear();
-        assertTrue(sb.capacity() >= 32);
-        assertEquals(0, sb.length());
-        assertEquals(0, sb.size());
-        assertTrue(sb.isEmpty());
-
-        sb.append("123456789012345678901234567890123");
-        assertTrue(sb.capacity() > 32);
-        assertEquals(33, sb.length());
-        assertEquals(33, sb.size());
-        assertTrue(sb.isEmpty() == false);
-
-        sb.ensureCapacity(16);
-        assertTrue(sb.capacity() > 16);
-        assertEquals(33, sb.length());
-        assertEquals(33, sb.size());
-        assertTrue(sb.isEmpty() == false);
-
-        sb.minimizeCapacity();
-        assertEquals(33, sb.capacity());
-        assertEquals(33, sb.length());
-        assertEquals(33, sb.size());
-        assertTrue(sb.isEmpty() == false);
-
-        try {
-            sb.setLength(-1);
-            fail("setLength(-1) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-
-        sb.setLength(33);
-        assertEquals(33, sb.capacity());
-        assertEquals(33, sb.length());
-        assertEquals(33, sb.size());
-        assertTrue(sb.isEmpty() == false);
-
-        sb.setLength(16);
-        assertTrue(sb.capacity() >= 16);
-        assertEquals(16, sb.length());
-        assertEquals(16, sb.size());
-        assertEquals("1234567890123456", sb.toString());
-        assertTrue(sb.isEmpty() == false);
-
-        sb.setLength(32);
-        assertTrue(sb.capacity() >= 32);
-        assertEquals(32, sb.length());
-        assertEquals(32, sb.size());
-        assertEquals("1234567890123456\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sb.toString());
-        assertTrue(sb.isEmpty() == false);
-
-        sb.setLength(0);
-        assertTrue(sb.capacity() >= 32);
-        assertEquals(0, sb.length());
-        assertEquals(0, sb.size());
-        assertTrue(sb.isEmpty());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testLength() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.length());
-        
-        sb.append("Hello");
-        assertEquals(5, sb.length());
-    }
-
-    @Test
-    public void testSetLength() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append("Hello");
-        sb.setLength(2);  // shorten
-        assertEquals("He", sb.toString());
-        sb.setLength(2);  // no change
-        assertEquals("He", sb.toString());
-        sb.setLength(3);  // lengthen
-        assertEquals("He\0", sb.toString());
-
-        try {
-            sb.setLength(-1);
-            fail("setLength(-1) expected StringIndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCapacity() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(sb.buffer.length, sb.capacity());
-        
-        sb.append("HelloWorldHelloWorldHelloWorldHelloWorld");
-        assertEquals(sb.buffer.length, sb.capacity());
-    }
-
-    @Test
-    public void testEnsureCapacity() {
-        final StrBuilder sb = new StrBuilder();
-        sb.ensureCapacity(2);
-        assertTrue(sb.capacity() >= 2);
-        
-        sb.ensureCapacity(-1);
-        assertTrue(sb.capacity() >= 0);
-        
-        sb.append("HelloWorld");
-        sb.ensureCapacity(40);
-        assertTrue(sb.capacity() >= 40);
-    }
-
-    @Test
-    public void testMinimizeCapacity() {
-        final StrBuilder sb = new StrBuilder();
-        sb.minimizeCapacity();
-        assertEquals(0, sb.capacity());
-        
-        sb.append("HelloWorld");
-        sb.minimizeCapacity();
-        assertEquals(10, sb.capacity());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSize() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.size());
-        
-        sb.append("Hello");
-        assertEquals(5, sb.size());
-    }
-
-    @Test
-    public void testIsEmpty() {
-        final StrBuilder sb = new StrBuilder();
-        assertTrue(sb.isEmpty());
-        
-        sb.append("Hello");
-        assertFalse(sb.isEmpty());
-        
-        sb.clear();
-        assertTrue(sb.isEmpty());
-    }
-
-    @Test
-    public void testClear() {
-        final StrBuilder sb = new StrBuilder();
-        sb.append("Hello");
-        sb.clear();
-        assertEquals(0, sb.length());
-        assertTrue(sb.buffer.length >= 5);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCharAt() {
-        final StrBuilder sb = new StrBuilder();
-        try {
-            sb.charAt(0);
-            fail("charAt(0) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        try {
-            sb.charAt(-1);
-            fail("charAt(-1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        sb.append("foo");
-        assertEquals('f', sb.charAt(0));
-        assertEquals('o', sb.charAt(1));
-        assertEquals('o', sb.charAt(2));
-        try {
-            sb.charAt(-1);
-            fail("charAt(-1) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        try {
-            sb.charAt(3);
-            fail("charAt(3) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSetCharAt() {
-        final StrBuilder sb = new StrBuilder();
-        try {
-            sb.setCharAt(0, 'f');
-            fail("setCharAt(0,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        try {
-            sb.setCharAt(-1, 'f');
-            fail("setCharAt(-1,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        sb.append("foo");
-        sb.setCharAt(0, 'b');
-        sb.setCharAt(1, 'a');
-        sb.setCharAt(2, 'r');
-        try {
-            sb.setCharAt(3, '!');
-            fail("setCharAt(3,) expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {
-            // expected
-        }
-        assertEquals("bar", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testDeleteCharAt() {
-        final StrBuilder sb = new StrBuilder("abc");
-        sb.deleteCharAt(0);
-        assertEquals("bc", sb.toString()); 
-        
-        try {
-            sb.deleteCharAt(1000);
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testToCharArray() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.toCharArray().length);
-
-        char[] a = sb.toCharArray();
-        assertNotNull("toCharArray() result is null", a);
-        assertEquals("toCharArray() result is too large", 0, a.length);
-
-        sb.append("junit");
-        a = sb.toCharArray();
-        assertEquals("toCharArray() result incorrect length", 5, a.length);
-        assertTrue("toCharArray() result does not match", Arrays.equals("junit".toCharArray(), a));
-    }
-
-    @Test
-    public void testToCharArrayIntInt() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(0, sb.toCharArray(0, 0).length);
-
-        sb.append("junit");
-        char[] a = sb.toCharArray(0, 20); // too large test
-        assertEquals("toCharArray(int,int) result incorrect length", 5, a.length);
-        assertTrue("toCharArray(int,int) result does not match", Arrays.equals("junit".toCharArray(), a));
-
-        a = sb.toCharArray(0, 4);
-        assertEquals("toCharArray(int,int) result incorrect length", 4, a.length);
-        assertTrue("toCharArray(int,int) result does not match", Arrays.equals("juni".toCharArray(), a));
-
-        a = sb.toCharArray(0, 4);
-        assertEquals("toCharArray(int,int) result incorrect length", 4, a.length);
-        assertTrue("toCharArray(int,int) result does not match", Arrays.equals("juni".toCharArray(), a));
-
-        a = sb.toCharArray(0, 1);
-        assertNotNull("toCharArray(int,int) result is null", a);
-
-        try {
-            sb.toCharArray(-1, 5);
-            fail("no string index out of bound on -1");
-        } catch (final IndexOutOfBoundsException e) {
-        }
-
-        try {
-            sb.toCharArray(6, 5);
-            fail("no string index out of bound on -1");
-        } catch (final IndexOutOfBoundsException e) {
-        }
-    }
-
-    @Test
-    public void testGetChars ( ) {
-        final StrBuilder sb = new StrBuilder();
-        
-        char[] input = new char[10];
-        char[] a = sb.getChars(input);
-        assertSame (input, a);
-        assertTrue(Arrays.equals(new char[10], a));
-        
-        sb.append("junit");
-        a = sb.getChars(input);
-        assertSame(input, a);
-        assertTrue(Arrays.equals(new char[] {'j','u','n','i','t',0,0,0,0,0},a));
-        
-        a = sb.getChars(null);
-        assertNotSame(input,a);
-        assertEquals(5,a.length);
-        assertTrue(Arrays.equals("junit".toCharArray(),a));
-        
-        input = new char[5];
-        a = sb.getChars(input);
-        assertSame(input, a);
-        
-        input = new char[4];
-        a = sb.getChars(input);
-        assertNotSame(input, a);
-    }
-
-    @Test
-    public void testGetCharsIntIntCharArrayInt( ) {
-        final StrBuilder sb = new StrBuilder();
-               
-        sb.append("junit");
-        char[] a = new char[5];
-        sb.getChars(0,5,a,0);
-        assertTrue(Arrays.equals(new char[] {'j','u','n','i','t'},a));
-        
-        a = new char[5];
-        sb.getChars(0,2,a,3);
-        assertTrue(Arrays.equals(new char[] {0,0,0,'j','u'},a));
-        
-        try {
-            sb.getChars(-1,0,a,0);
-            fail("no exception");
-        }
-        catch (final IndexOutOfBoundsException e) {
-        }
-        
-        try {
-            sb.getChars(0,-1,a,0);
-            fail("no exception");
-        }
-        catch (final IndexOutOfBoundsException e) {
-        }
-        
-        try {
-            sb.getChars(0,20,a,0);
-            fail("no exception");
-        }
-        catch (final IndexOutOfBoundsException e) {
-        }
-        
-        try {
-            sb.getChars(4,2,a,0);
-            fail("no exception");
-        }
-        catch (final IndexOutOfBoundsException e) {
-        }
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testDeleteIntInt() {
-        StrBuilder sb = new StrBuilder("abc");
-        sb.delete(0, 1);
-        assertEquals("bc", sb.toString()); 
-        sb.delete(1, 2);
-        assertEquals("b", sb.toString());
-        sb.delete(0, 1);
-        assertEquals("", sb.toString()); 
-        sb.delete(0, 1000);
-        assertEquals("", sb.toString()); 
-        
-        try {
-            sb.delete(1, 2);
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-        try {
-            sb.delete(-1, 1);
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        sb = new StrBuilder("anything");
-        try {
-            sb.delete(2, 1);
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testDeleteAll_char() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.deleteAll('X');
-        assertEquals("abcbccba", sb.toString());
-        sb.deleteAll('a');
-        assertEquals("bcbccb", sb.toString());
-        sb.deleteAll('c');
-        assertEquals("bbb", sb.toString());
-        sb.deleteAll('b');
-        assertEquals("", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteAll('b');
-        assertEquals("", sb.toString());
-    }
-
-    @Test
-    public void testDeleteFirst_char() {
-        StrBuilder sb = new StrBuilder("abcba");
-        sb.deleteFirst('X');
-        assertEquals("abcba", sb.toString());
-        sb.deleteFirst('a');
-        assertEquals("bcba", sb.toString());
-        sb.deleteFirst('c');
-        assertEquals("bba", sb.toString());
-        sb.deleteFirst('b');
-        assertEquals("ba", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteFirst('b');
-        assertEquals("", sb.toString());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testDeleteAll_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.deleteAll((String) null);
-        assertEquals("abcbccba", sb.toString());
-        sb.deleteAll("");
-        assertEquals("abcbccba", sb.toString());
-        
-        sb.deleteAll("X");
-        assertEquals("abcbccba", sb.toString());
-        sb.deleteAll("a");
-        assertEquals("bcbccb", sb.toString());
-        sb.deleteAll("c");
-        assertEquals("bbb", sb.toString());
-        sb.deleteAll("b");
-        assertEquals("", sb.toString());
-
-        sb = new StrBuilder("abcbccba");
-        sb.deleteAll("bc");
-        assertEquals("acba", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteAll("bc");
-        assertEquals("", sb.toString());
-    }
-
-    @Test
-    public void testDeleteFirst_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.deleteFirst((String) null);
-        assertEquals("abcbccba", sb.toString());
-        sb.deleteFirst("");
-        assertEquals("abcbccba", sb.toString());
-
-        sb.deleteFirst("X");
-        assertEquals("abcbccba", sb.toString());
-        sb.deleteFirst("a");
-        assertEquals("bcbccba", sb.toString());
-        sb.deleteFirst("c");
-        assertEquals("bbccba", sb.toString());
-        sb.deleteFirst("b");
-        assertEquals("bccba", sb.toString());
-
-        sb = new StrBuilder("abcbccba");
-        sb.deleteFirst("bc");
-        assertEquals("abccba", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteFirst("bc");
-        assertEquals("", sb.toString());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testDeleteAll_StrMatcher() {
-        StrBuilder sb = new StrBuilder("A0xA1A2yA3");
-        sb.deleteAll((StrMatcher) null);
-        assertEquals("A0xA1A2yA3", sb.toString());
-        sb.deleteAll(A_NUMBER_MATCHER);
-        assertEquals("xy", sb.toString());
-
-        sb = new StrBuilder("Ax1");
-        sb.deleteAll(A_NUMBER_MATCHER);
-        assertEquals("Ax1", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteAll(A_NUMBER_MATCHER);
-        assertEquals("", sb.toString());
-    }
-
-    @Test
-    public void testDeleteFirst_StrMatcher() {
-        StrBuilder sb = new StrBuilder("A0xA1A2yA3");
-        sb.deleteFirst((StrMatcher) null);
-        assertEquals("A0xA1A2yA3", sb.toString());
-        sb.deleteFirst(A_NUMBER_MATCHER);
-        assertEquals("xA1A2yA3", sb.toString());
-
-        sb = new StrBuilder("Ax1");
-        sb.deleteFirst(A_NUMBER_MATCHER);
-        assertEquals("Ax1", sb.toString());
-
-        sb = new StrBuilder("");
-        sb.deleteFirst(A_NUMBER_MATCHER);
-        assertEquals("", sb.toString());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testReplace_int_int_String() {
-        StrBuilder sb = new StrBuilder("abc");
-        sb.replace(0, 1, "d");
-        assertEquals("dbc", sb.toString());
-        sb.replace(0, 1, "aaa");
-        assertEquals("aaabc", sb.toString());
-        sb.replace(0, 3, "");
-        assertEquals("bc", sb.toString());
-        sb.replace(1, 2, (String) null);
-        assertEquals("b", sb.toString());
-        sb.replace(1, 1000, "text");
-        assertEquals("btext", sb.toString());
-        sb.replace(0, 1000, "text");
-        assertEquals("text", sb.toString());
-        
-        sb = new StrBuilder("atext");
-        sb.replace(1, 1, "ny");
-        assertEquals("anytext", sb.toString());
-        try {
-            sb.replace(2, 1, "anything");
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        sb = new StrBuilder();
-        try {
-            sb.replace(1, 2, "anything");
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-        try {
-            sb.replace(-1, 1, "anything");
-            fail("Expected IndexOutOfBoundsException");
-        } catch (final IndexOutOfBoundsException e) {}
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReplaceAll_char_char() {
-        final StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceAll('x', 'y');
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll('a', 'd');
-        assertEquals("dbcbccbd", sb.toString());
-        sb.replaceAll('b', 'e');
-        assertEquals("dececced", sb.toString());
-        sb.replaceAll('c', 'f');
-        assertEquals("defeffed", sb.toString());
-        sb.replaceAll('d', 'd');
-        assertEquals("defeffed", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReplaceFirst_char_char() {
-        final StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceFirst('x', 'y');
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst('a', 'd');
-        assertEquals("dbcbccba", sb.toString());
-        sb.replaceFirst('b', 'e');
-        assertEquals("decbccba", sb.toString());
-        sb.replaceFirst('c', 'f');
-        assertEquals("defbccba", sb.toString());
-        sb.replaceFirst('d', 'd');
-        assertEquals("defbccba", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReplaceAll_String_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceAll((String) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll((String) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll("", null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll("", "anything");
-        assertEquals("abcbccba", sb.toString());
-        
-        sb.replaceAll("x", "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll("a", "d");
-        assertEquals("dbcbccbd", sb.toString());
-        sb.replaceAll("d", null);
-        assertEquals("bcbccb", sb.toString());
-        sb.replaceAll("cb", "-");
-        assertEquals("b-c-", sb.toString());
-        
-        sb = new StrBuilder("abcba");
-        sb.replaceAll("b", "xbx");
-        assertEquals("axbxcxbxa", sb.toString());
-        
-        sb = new StrBuilder("bb");
-        sb.replaceAll("b", "xbx");
-        assertEquals("xbxxbx", sb.toString());
-    }
-
-    @Test
-    public void testReplaceFirst_String_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceFirst((String) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst((String) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst("", null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst("", "anything");
-        assertEquals("abcbccba", sb.toString());
-        
-        sb.replaceFirst("x", "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst("a", "d");
-        assertEquals("dbcbccba", sb.toString());
-        sb.replaceFirst("d", null);
-        assertEquals("bcbccba", sb.toString());
-        sb.replaceFirst("cb", "-");
-        assertEquals("b-ccba", sb.toString());
-        
-        sb = new StrBuilder("abcba");
-        sb.replaceFirst("b", "xbx");
-        assertEquals("axbxcba", sb.toString());
-        
-        sb = new StrBuilder("bb");
-        sb.replaceFirst("b", "xbx");
-        assertEquals("xbxb", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReplaceAll_StrMatcher_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceAll((StrMatcher) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll((StrMatcher) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll(StrMatcher.noneMatcher(), null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll(StrMatcher.noneMatcher(), "anything");
-        assertEquals("abcbccba", sb.toString());
-        
-        sb.replaceAll(StrMatcher.charMatcher('x'), "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceAll(StrMatcher.charMatcher('a'), "d");
-        assertEquals("dbcbccbd", sb.toString());
-        sb.replaceAll(StrMatcher.charMatcher('d'), null);
-        assertEquals("bcbccb", sb.toString());
-        sb.replaceAll(StrMatcher.stringMatcher("cb"), "-");
-        assertEquals("b-c-", sb.toString());
-        
-        sb = new StrBuilder("abcba");
-        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("axbxcxbxa", sb.toString());
-        
-        sb = new StrBuilder("bb");
-        sb.replaceAll(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("xbxxbx", sb.toString());
-        
-        sb = new StrBuilder("A1-A2A3-A4");
-        sb.replaceAll(A_NUMBER_MATCHER, "***");
-        assertEquals("***-******-***", sb.toString());
-
-        sb = new StrBuilder("Dear X, hello X.");
-        sb.replaceAll(StrMatcher.stringMatcher("X"), "012345678901234567");
-        assertEquals("Dear 012345678901234567, hello 012345678901234567.", sb.toString());
-    }
-
-    @Test
-    public void testReplaceFirst_StrMatcher_String() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replaceFirst((StrMatcher) null, null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst((StrMatcher) null, "anything");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.noneMatcher(), null);
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.noneMatcher(), "anything");
-        assertEquals("abcbccba", sb.toString());
-        
-        sb.replaceFirst(StrMatcher.charMatcher('x'), "y");
-        assertEquals("abcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.charMatcher('a'), "d");
-        assertEquals("dbcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.charMatcher('d'), null);
-        assertEquals("bcbccba", sb.toString());
-        sb.replaceFirst(StrMatcher.stringMatcher("cb"), "-");
-        assertEquals("b-ccba", sb.toString());
-        
-        sb = new StrBuilder("abcba");
-        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("axbxcba", sb.toString());
-        
-        sb = new StrBuilder("bb");
-        sb.replaceFirst(StrMatcher.charMatcher('b'), "xbx");
-        assertEquals("xbxb", sb.toString());
-        
-        sb = new StrBuilder("A1-A2A3-A4");
-        sb.replaceFirst(A_NUMBER_MATCHER, "***");
-        assertEquals("***-A2A3-A4", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryMatcher() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replace((StrMatcher) null, "x", 0, sb.length(), -1);
-        assertEquals("abcbccba", sb.toString());
-        
-        sb.replace(StrMatcher.charMatcher('a'), "x", 0, sb.length(), -1);
-        assertEquals("xbcbccbx", sb.toString());
-        
-        sb.replace(StrMatcher.stringMatcher("cb"), "x", 0, sb.length(), -1);
-        assertEquals("xbxcxx", sb.toString());
-        
-        sb = new StrBuilder("A1-A2A3-A4");
-        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
-        assertEquals("***-******-***", sb.toString());
-        
-        sb = new StrBuilder();
-        sb.replace(A_NUMBER_MATCHER, "***", 0, sb.length(), -1);
-        assertEquals("", sb.toString());
-    }
-
-    @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryReplace() {
-        StrBuilder sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "cb", 0, sb.length(), -1);
-        assertEquals("abcbccba", sb.toString());
-        
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "-", 0, sb.length(), -1);
-        assertEquals("ab-c-a", sb.toString());
-        
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "+++", 0, sb.length(), -1);
-        assertEquals("ab+++c+++a", sb.toString());
-        
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), "", 0, sb.length(), -1);
-        assertEquals("abca", sb.toString());
-        
-        sb = new StrBuilder("abcbccba");
-        sb.replace(StrMatcher.stringMatcher("cb"), null, 0, sb.length(), -1);
-        assertEquals("abca", sb.toString());
-    }
-
-    @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryStartIndex() {
-        StrBuilder sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, sb.length(), -1);
-        assertEquals("-x--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 1, sb.length(), -1);
-        assertEquals("aax--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, sb.length(), -1);
-        assertEquals("aax--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 3, sb.length(), -1);
-        assertEquals("aax--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 4, sb.length(), -1);
-        assertEquals("aaxa-ay-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 5, sb.length(), -1);
-        assertEquals("aaxaa-y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 6, sb.length(), -1);
-        assertEquals("aaxaaaay-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 7, sb.length(), -1);
-        assertEquals("aaxaaaay-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 8, sb.length(), -1);
-        assertEquals("aaxaaaay-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 9, sb.length(), -1);
-        assertEquals("aaxaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 10, sb.length(), -1);
-        assertEquals("aaxaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        try {
-            sb.replace(StrMatcher.stringMatcher("aa"), "-", 11, sb.length(), -1);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        assertEquals("aaxaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        try {
-            sb.replace(StrMatcher.stringMatcher("aa"), "-", -1, sb.length(), -1);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        assertEquals("aaxaaaayaa", sb.toString());
-    }
-
-    @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryEndIndex() {
-        StrBuilder sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 0, -1);
-        assertEquals("aaxaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 2, -1);
-        assertEquals("-xaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 3, -1);
-        assertEquals("-xaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 4, -1);
-        assertEquals("-xaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 5, -1);
-        assertEquals("-x-aayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 6, -1);
-        assertEquals("-x-aayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 7, -1);
-        assertEquals("-x--yaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 8, -1);
-        assertEquals("-x--yaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 9, -1);
-        assertEquals("-x--yaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
-        assertEquals("-x--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 1000, -1);
-        assertEquals("-x--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        try {
-            sb.replace(StrMatcher.stringMatcher("aa"), "-", 2, 1, -1);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        assertEquals("aaxaaaayaa", sb.toString());
-    }
-
-    @Test
-    public void testReplace_StrMatcher_String_int_int_int_VaryCount() {
-        StrBuilder sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, -1);
-        assertEquals("-x--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 0);
-        assertEquals("aaxaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 1);
-        assertEquals("-xaaaayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 2);
-        assertEquals("-x-aayaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 3);
-        assertEquals("-x--yaa", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 4);
-        assertEquals("-x--y-", sb.toString());
-        
-        sb = new StrBuilder("aaxaaaayaa");
-        sb.replace(StrMatcher.stringMatcher("aa"), "-", 0, 10, 5);
-        assertEquals("-x--y-", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testReverse() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals("", sb.reverse().toString());
-        
-        sb.clear().append(true);
-        assertEquals("eurt", sb.reverse().toString());
-        assertEquals("true", sb.reverse().toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTrim() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals("", sb.reverse().toString());
-        
-        sb.clear().append(" \u0000 ");
-        assertEquals("", sb.trim().toString());
-        
-        sb.clear().append(" \u0000 a b c");
-        assertEquals("a b c", sb.trim().toString());
-        
-        sb.clear().append("a b c \u0000 ");
-        assertEquals("a b c", sb.trim().toString());
-        
-        sb.clear().append(" \u0000 a b c \u0000 ");
-        assertEquals("a b c", sb.trim().toString());
-        
-        sb.clear().append("a b c");
-        assertEquals("a b c", sb.trim().toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testStartsWith() {
-        final StrBuilder sb = new StrBuilder();
-        assertFalse(sb.startsWith("a"));
-        assertFalse(sb.startsWith(null));
-        assertTrue(sb.startsWith(""));
-        sb.append("abc");
-        assertTrue(sb.startsWith("a"));
-        assertTrue(sb.startsWith("ab"));
-        assertTrue(sb.startsWith("abc"));
-        assertFalse(sb.startsWith("cba"));
-    }
-
-    @Test
-    public void testEndsWith() {
-        final StrBuilder sb = new StrBuilder();
-        assertFalse(sb.endsWith("a"));
-        assertFalse(sb.endsWith("c"));
-        assertTrue(sb.endsWith(""));
-        assertFalse(sb.endsWith(null));
-        sb.append("abc");
-        assertTrue(sb.endsWith("c"));
-        assertTrue(sb.endsWith("bc"));
-        assertTrue(sb.endsWith("abc"));
-        assertFalse(sb.endsWith("cba"));
-        assertFalse(sb.endsWith("abcd"));
-        assertFalse(sb.endsWith(" abc"));
-        assertFalse(sb.endsWith("abc "));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSubSequenceIntInt() {
-       final StrBuilder sb = new StrBuilder ("hello goodbye");
-       // Start index is negative
-       try {
-            sb.subSequence(-1, 5);
-            fail();
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        // End index is negative
-       try {
-            sb.subSequence(2, -1);
-            fail();
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        // End index greater than length()
-        try {
-            sb.subSequence(2, sb.length() + 1);
-            fail();
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        // Start index greater then end index
-        try {
-            sb.subSequence(3, 2);
-            fail();
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        // Normal cases
-        assertEquals ("hello", sb.subSequence(0, 5));
-        assertEquals ("hello goodbye".subSequence(0, 6), sb.subSequence(0, 6));
-        assertEquals ("goodbye", sb.subSequence(6, 13));
-        assertEquals ("hello goodbye".subSequence(6,13), sb.subSequence(6, 13));
-    }
-
-    @Test
-    public void testSubstringInt() {
-        final StrBuilder sb = new StrBuilder ("hello goodbye");
-        assertEquals ("goodbye", sb.substring(6));
-        assertEquals ("hello goodbye".substring(6), sb.substring(6));
-        assertEquals ("hello goodbye", sb.substring(0));
-        assertEquals ("hello goodbye".substring(0), sb.substring(0));
-        try {
-            sb.substring(-1);
-            fail ();
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        try {
-            sb.substring(15);
-            fail ();
-        } catch (final IndexOutOfBoundsException e) {}
-    
-    }
-    
-    @Test
-    public void testSubstringIntInt() {
-        final StrBuilder sb = new StrBuilder ("hello goodbye");
-        assertEquals ("hello", sb.substring(0, 5));
-        assertEquals ("hello goodbye".substring(0, 6), sb.substring(0, 6));
-        
-        assertEquals ("goodbye", sb.substring(6, 13));
-        assertEquals ("hello goodbye".substring(6,13), sb.substring(6, 13));
-        
-        assertEquals ("goodbye", sb.substring(6, 20));
-        
-        try {
-            sb.substring(-1, 5);
-            fail();
-        } catch (final IndexOutOfBoundsException e) {}
-        
-        try {
-            sb.substring(15, 20);
-            fail();
-        } catch (final IndexOutOfBoundsException e) {}
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testMidString() {
-        final StrBuilder sb = new StrBuilder("hello goodbye hello");
-        assertEquals("goodbye", sb.midString(6, 7));
-        assertEquals("hello", sb.midString(0, 5));
-        assertEquals("hello", sb.midString(-5, 5));
-        assertEquals("", sb.midString(0, -1));
-        assertEquals("", sb.midString(20, 2));
-        assertEquals("hello", sb.midString(14, 22));
-    }
-
-    @Test
-    public void testRightString() {
-        final StrBuilder sb = new StrBuilder("left right");
-        assertEquals("right", sb.rightString(5));
-        assertEquals("", sb.rightString(0));
-        assertEquals("", sb.rightString(-5));
-        assertEquals("left right", sb.rightString(15));
-    }
-
-    @Test
-    public void testLeftString() {
-        final StrBuilder sb = new StrBuilder("left right");
-        assertEquals("left", sb.leftString(4));
-        assertEquals("", sb.leftString(0));
-        assertEquals("", sb.leftString(-5));
-        assertEquals("left right", sb.leftString(15));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testContains_char() {
-        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
-        assertTrue(sb.contains('a'));
-        assertTrue(sb.contains('o'));
-        assertTrue(sb.contains('z'));
-        assertFalse(sb.contains('1'));
-    }
-
-    @Test
-    public void testContains_String() {
-        final StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
-        assertTrue(sb.contains("a"));
-        assertTrue(sb.contains("pq"));
-        assertTrue(sb.contains("z"));
-        assertFalse(sb.contains("zyx"));
-        assertFalse(sb.contains((String) null));
-    }
-
-    @Test
-    public void testContains_StrMatcher() {
-        StrBuilder sb = new StrBuilder("abcdefghijklmnopqrstuvwxyz");
-        assertTrue(sb.contains(StrMatcher.charMatcher('a')));
-        assertTrue(sb.contains(StrMatcher.stringMatcher("pq")));
-        assertTrue(sb.contains(StrMatcher.charMatcher('z')));
-        assertFalse(sb.contains(StrMatcher.stringMatcher("zy")));
-        assertFalse(sb.contains((StrMatcher) null));
-
-        sb = new StrBuilder();
-        assertFalse(sb.contains(A_NUMBER_MATCHER));
-        sb.append("B A1 C");
-        assertTrue(sb.contains(A_NUMBER_MATCHER));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testIndexOf_char() {
-        final StrBuilder sb = new StrBuilder("abab");
-        assertEquals(0, sb.indexOf('a'));
-        
-        // should work like String#indexOf
-        assertEquals("abab".indexOf('a'), sb.indexOf('a'));
-
-        assertEquals(1, sb.indexOf('b'));
-        assertEquals("abab".indexOf('b'), sb.indexOf('b'));
-
-        assertEquals(-1, sb.indexOf('z'));
-    }
-
-    @Test
-    public void testIndexOf_char_int() {
-        StrBuilder sb = new StrBuilder("abab");
-        assertEquals(0, sb.indexOf('a', -1));
-        assertEquals(0, sb.indexOf('a', 0));
-        assertEquals(2, sb.indexOf('a', 1));
-        assertEquals(-1, sb.indexOf('a', 4));
-        assertEquals(-1, sb.indexOf('a', 5));
-
-        // should work like String#indexOf
-        assertEquals("abab".indexOf('a', 1), sb.indexOf('a', 1));
-
-        assertEquals(3, sb.indexOf('b', 2));
-        assertEquals("abab".indexOf('b', 2), sb.indexOf('b', 2));
-
-        assertEquals(-1, sb.indexOf('z', 2));
-
-        sb = new StrBuilder("xyzabc");
-        assertEquals(2, sb.indexOf('z', 0));
-        assertEquals(-1, sb.indexOf('z', 3));
-    }
-
-    @Test
-    public void testLastIndexOf_char() {
-        final StrBuilder sb = new StrBuilder("abab");
-        
-        assertEquals (2, sb.lastIndexOf('a'));
-        //should work like String#lastIndexOf
-        assertEquals ("abab".lastIndexOf('a'), sb.lastIndexOf('a'));
-        
-        assertEquals(3, sb.lastIndexOf('b'));
-        assertEquals ("abab".lastIndexOf('b'), sb.lastIndexOf('b'));
-        
-        assertEquals (-1, sb.lastIndexOf('z'));
-    }
-
-    @Test
-    public void testLastIndexOf_char_int() {
-        StrBuilder sb = new StrBuilder("abab");
-        assertEquals(-1, sb.lastIndexOf('a', -1));
-        assertEquals(0, sb.lastIndexOf('a', 0));
-        assertEquals(0, sb.lastIndexOf('a', 1));
-
-        // should work like String#lastIndexOf
-        assertEquals("abab".lastIndexOf('a', 1), sb.lastIndexOf('a', 1));
-
-        assertEquals(1, sb.lastIndexOf('b', 2));
-        assertEquals("abab".lastIndexOf('b', 2), sb.lastIndexOf('b', 2));
-
-        assertEquals(-1, sb.lastIndexOf('z', 2));
-
-        sb = new StrBuilder("xyzabc");
-        assertEquals(2, sb.lastIndexOf('z', sb.length()));
-        assertEquals(-1, sb.lastIndexOf('z', 1));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testIndexOf_String() {
-        final StrBuilder sb = new StrBuilder("abab");
-        
-        assertEquals(0, sb.indexOf("a"));
-        //should work like String#indexOf
-        assertEquals("abab".indexOf("a"), sb.indexOf("a"));
-        
-        assertEquals(0, sb.indexOf("ab"));
-        //should work like String#indexOf
-        assertEquals("abab".indexOf("ab"), sb.indexOf("ab"));
-        
-        assertEquals(1, sb.indexOf("b"));
-        assertEquals("abab".indexOf("b"), sb.indexOf("b"));
-        
-        assertEquals(1, sb.indexOf("ba"));
-        assertEquals("abab".indexOf("ba"), sb.indexOf("ba"));
-        
-        assertEquals(-1, sb.indexOf("z"));
-        
-        assertEquals(-1, sb.indexOf((String) null));
-    }
-
-    @Test
-    public void testIndexOf_String_int() {
-        StrBuilder sb = new StrBuilder("abab");
-        assertEquals(0, sb.indexOf("a", -1));
-        assertEquals(0, sb.indexOf("a", 0));
-        assertEquals(2, sb.indexOf("a", 1));
-        assertEquals(2, sb.indexOf("a", 2));
-        assertEquals(-1, sb.indexOf("a", 3));
-        assertEquals(-1, sb.indexOf("a", 4));
-        assertEquals(-1, sb.indexOf("a", 5));
-        
-        assertEquals(-1, sb.indexOf("abcdef", 0));
-        assertEquals(0, sb.indexOf("", 0));
-        assertEquals(1, sb.indexOf("", 1));
-        
-        //should work like String#indexOf
-        assertEquals ("abab".indexOf("a", 1), sb.indexOf("a", 1));
-        
-        assertEquals(2, sb.indexOf("ab", 1));
-        //should work like String#indexOf
-        assertEquals("abab".indexOf("ab", 1), sb.indexOf("ab", 1));
-        
-        assertEquals(3, sb.indexOf("b", 2));
-        assertEquals("abab".indexOf("b", 2), sb.indexOf("b", 2));
-        
-        assertEquals(1, sb.indexOf("ba", 1));
-        assertEquals("abab".indexOf("ba", 2), sb.indexOf("ba", 2));
-        
-        assertEquals(-1, sb.indexOf("z", 2));
-        
-        sb = new StrBuilder("xyzabc");
-        assertEquals(2, sb.indexOf("za", 0));
-        assertEquals(-1, sb.indexOf("za", 3));
-        
-        assertEquals(-1, sb.indexOf((String) null, 2));
-    }
-
-    @Test
-    public void testLastIndexOf_String() {
-        final StrBuilder sb = new StrBuilder("abab");
-        
-        assertEquals(2, sb.lastIndexOf("a"));
-        //should work like String#lastIndexOf
-        assertEquals("abab".lastIndexOf("a"), sb.lastIndexOf("a"));
-        
-        assertEquals(2, sb.lastIndexOf("ab"));
-        //should work like String#lastIndexOf
-        assertEquals("abab".lastIndexOf("ab"), sb.lastIndexOf("ab"));
-        
-        assertEquals(3, sb.lastIndexOf("b"));
-        assertEquals("abab".lastIndexOf("b"), sb.lastIndexOf("b"));
-        
-        assertEquals(1, sb.lastIndexOf("ba"));
-        assertEquals("abab".lastIndexOf("ba"), sb.lastIndexOf("ba"));
-        
-        assertEquals(-1, sb.lastIndexOf("z"));
-        
-        assertEquals(-1, sb.lastIndexOf((String) null));
-    }
-
-    @Test
-    public void testLastIndexOf_String_int() {
-        StrBuilder sb = new StrBuilder("abab");
-        assertEquals(-1, sb.lastIndexOf("a", -1));
-        assertEquals(0, sb.lastIndexOf("a", 0));
-        assertEquals(0, sb.lastIndexOf("a", 1));
-        assertEquals(2, sb.lastIndexOf("a", 2));
-        assertEquals(2, sb.lastIndexOf("a", 3));
-        assertEquals(2, sb.lastIndexOf("a", 4));
-        assertEquals(2, sb.lastIndexOf("a", 5));
-        
-        assertEquals(-1, sb.lastIndexOf("abcdef", 3));
-        assertEquals("abab".lastIndexOf("", 3), sb.lastIndexOf("", 3));
-        assertEquals("abab".lastIndexOf("", 1), sb.lastIndexOf("", 1));
-        
-        //should work like String#lastIndexOf
-        assertEquals("abab".lastIndexOf("a", 1), sb.lastIndexOf("a", 1));
-        
-        assertEquals(0, sb.lastIndexOf("ab", 1));
-        //should work like String#lastIndexOf
-        assertEquals("abab".lastIndexOf("ab", 1), sb.lastIndexOf("ab", 1));
-        
-        assertEquals(1, sb.lastIndexOf("b", 2));
-        assertEquals("abab".lastIndexOf("b", 2), sb.lastIndexOf("b", 2));
-        
-        assertEquals(1, sb.lastIndexOf("ba", 2));
-        assertEquals("abab".lastIndexOf("ba", 2), sb.lastIndexOf("ba", 2));
-        
-        assertEquals(-1, sb.lastIndexOf("z", 2));
-        
-        sb = new StrBuilder("xyzabc");
-        assertEquals(2, sb.lastIndexOf("za", sb.length()));
-        assertEquals(-1, sb.lastIndexOf("za", 1));
-        
-        assertEquals(-1, sb.lastIndexOf((String) null, 2));
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testIndexOf_StrMatcher() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.indexOf((StrMatcher) null));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a')));
-        
-        sb.append("ab bd");
-        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a')));
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b')));
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher()));
-        assertEquals(4, sb.indexOf(StrMatcher.charMatcher('d')));
-        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher()));
-        assertEquals(-1, sb.indexOf((StrMatcher) null));
-        
-        sb.append(" A1 junction");
-        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER));
-    }
-
-    @Test
-    public void testIndexOf_StrMatcher_int() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.indexOf((StrMatcher) null, 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 0));
-        
-        sb.append("ab bd");
-        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), -2));
-        assertEquals(0, sb.indexOf(StrMatcher.charMatcher('a'), 0));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('a'), 20));
-        
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), -1));
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 0));
-        assertEquals(1, sb.indexOf(StrMatcher.charMatcher('b'), 1));
-        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 2));
-        assertEquals(3, sb.indexOf(StrMatcher.charMatcher('b'), 3));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 4));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 5));
-        assertEquals(-1, sb.indexOf(StrMatcher.charMatcher('b'), 6));
-        
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), -2));
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 0));
-        assertEquals(2, sb.indexOf(StrMatcher.spaceMatcher(), 2));
-        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 4));
-        assertEquals(-1, sb.indexOf(StrMatcher.spaceMatcher(), 20));
-        
-        assertEquals(-1, sb.indexOf(StrMatcher.noneMatcher(), 0));
-        assertEquals(-1, sb.indexOf((StrMatcher) null, 0));
-        
-        sb.append(" A1 junction with A2");
-        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 5));
-        assertEquals(6, sb.indexOf(A_NUMBER_MATCHER, 6));
-        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 7));
-        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 22));
-        assertEquals(23, sb.indexOf(A_NUMBER_MATCHER, 23));
-        assertEquals(-1, sb.indexOf(A_NUMBER_MATCHER, 24));
-    }
-
-    @Test
-    public void testLastIndexOf_StrMatcher() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a')));
-        
-        sb.append("ab bd");
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a')));
-        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b')));
-        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher()));
-        assertEquals(4, sb.lastIndexOf(StrMatcher.charMatcher('d')));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher()));
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null));
-        
-        sb.append(" A1 junction");
-        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER));
-    }
-
-    @Test
-    public void testLastIndexOf_StrMatcher_int() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 2));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -1));
-        
-        sb.append("ab bd");
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('a'), -2));
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 0));
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 2));
-        assertEquals(0, sb.lastIndexOf(StrMatcher.charMatcher('a'), 20));
-        
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), -1));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 0));
-        assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 1));
-        assertEquals(1, sb.lastIndexOf(StrMatcher.charMatcher('b'), 2));
-        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 3));
-        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 4));
-        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 5));
-        assertEquals(3, sb.lastIndexOf(StrMatcher.charMatcher('b'), 6));
-        
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), -2));
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.spaceMatcher(), 0));
-        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 2));
-        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 4));
-        assertEquals(2, sb.lastIndexOf(StrMatcher.spaceMatcher(), 20));
-        
-        assertEquals(-1, sb.lastIndexOf(StrMatcher.noneMatcher(), 0));
-        assertEquals(-1, sb.lastIndexOf((StrMatcher) null, 0));
-        
-        sb.append(" A1 junction with A2");
-        assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 5));
-        assertEquals(-1, sb.lastIndexOf(A_NUMBER_MATCHER, 6)); // A matches, 1 is outside bounds
-        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 7));
-        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 22));
-        assertEquals(6, sb.lastIndexOf(A_NUMBER_MATCHER, 23)); // A matches, 2 is outside bounds
-        assertEquals(23, sb.lastIndexOf(A_NUMBER_MATCHER, 24));
-    }
-
-    static final StrMatcher A_NUMBER_MATCHER = new StrMatcher() {
-        @Override
-        public int isMatch(final char[] buffer, int pos, final int bufferStart, final int bufferEnd) {
-            if (buffer[pos] == 'A') {
-                pos++;
-                if (pos < bufferEnd && buffer[pos] >= '0' && buffer[pos] <= '9') {
-                    return 2;
-                }
-            }
-            return 0;
-        }
-    };
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAsTokenizer() throws Exception {
-        // from Javadoc
-        final StrBuilder b = new StrBuilder();
-        b.append("a b ");
-        final StrTokenizer t = b.asTokenizer();
-        
-        final String[] tokens1 = t.getTokenArray();
-        assertEquals(2, tokens1.length);
-        assertEquals("a", tokens1[0]);
-        assertEquals("b", tokens1[1]);
-        assertEquals(2, t.size());
-        
-        b.append("c d ");
-        final String[] tokens2 = t.getTokenArray();
-        assertEquals(2, tokens2.length);
-        assertEquals("a", tokens2[0]);
-        assertEquals("b", tokens2[1]);
-        assertEquals(2, t.size());
-        assertEquals("a", t.next());
-        assertEquals("b", t.next());
-        
-        t.reset();
-        final String[] tokens3 = t.getTokenArray();
-        assertEquals(4, tokens3.length);
-        assertEquals("a", tokens3[0]);
-        assertEquals("b", tokens3[1]);
-        assertEquals("c", tokens3[2]);
-        assertEquals("d", tokens3[3]);
-        assertEquals(4, t.size());
-        assertEquals("a", t.next());
-        assertEquals("b", t.next());
-        assertEquals("c", t.next());
-        assertEquals("d", t.next());
-        
-        assertEquals("a b c d ", t.getContent());
-    }
-
-    // -----------------------------------------------------------------------
-    @Test
-    public void testAsReader() throws Exception {
-        final StrBuilder sb = new StrBuilder("some text");
-        Reader reader = sb.asReader();
-        assertTrue(reader.ready());
-        final char[] buf = new char[40];
-        assertEquals(9, reader.read(buf));
-        assertEquals("some text", new String(buf, 0, 9));
-        
-        assertEquals(-1, reader.read());
-        assertFalse(reader.ready());
-        assertEquals(0, reader.skip(2));
-        assertEquals(0, reader.skip(-1));
-        
-        assertTrue(reader.markSupported());
-        reader = sb.asReader();
-        assertEquals('s', reader.read());
-        reader.mark(-1);
-        char[] array = new char[3];
-        assertEquals(3, reader.read(array, 0, 3));
-        assertEquals('o', array[0]);
-        assertEquals('m', array[1]);
-        assertEquals('e', array[2]);
-        reader.reset();
-        assertEquals(1, reader.read(array, 1, 1));
-        assertEquals('o', array[0]);
-        assertEquals('o', array[1]);
-        assertEquals('e', array[2]);
-        assertEquals(2, reader.skip(2));
-        assertEquals(' ', reader.read());
-        
-        assertTrue(reader.ready());
-        reader.close();
-        assertTrue(reader.ready());
-        
-        reader = sb.asReader();
-        array = new char[3];
-        try {
-            reader.read(array, -1, 0);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        try {
-            reader.read(array, 0, -1);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        try {
-            reader.read(array, 100, 1);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        try {
-            reader.read(array, 0, 100);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        try {
-            reader.read(array, Integer.MAX_VALUE, Integer.MAX_VALUE);
-            fail();
-        } catch (final IndexOutOfBoundsException ex) {}
-        
-        assertEquals(0, reader.read(array, 0, 0));
-        assertEquals(0, array[0]);
-        assertEquals(0, array[1]);
-        assertEquals(0, array[2]);
-        
-        reader.skip(9);
-        assertEquals(-1, reader.read(array, 0, 1));
-        
-        reader.reset();
-        array = new char[30];
-        assertEquals(9, reader.read(array, 0, 30));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAsWriter() throws Exception {
-        final StrBuilder sb = new StrBuilder("base");
-        final Writer writer = sb.asWriter();
-        
-        writer.write('l');
-        assertEquals("basel", sb.toString());
-        
-        writer.write(new char[] {'i', 'n'});
-        assertEquals("baselin", sb.toString());
-        
-        writer.write(new char[] {'n', 'e', 'r'}, 1, 2);
-        assertEquals("baseliner", sb.toString());
-        
-        writer.write(" rout");
-        assertEquals("baseliner rout", sb.toString());
-        
-        writer.write("ping that server", 1, 3);
-        assertEquals("baseliner routing", sb.toString());
-        
-        writer.flush();  // no effect
-        assertEquals("baseliner routing", sb.toString());
-        
-        writer.close();  // no effect
-        assertEquals("baseliner routing", sb.toString());
-        
-        writer.write(" hi");  // works after close
-        assertEquals("baseliner routing hi", sb.toString());
-        
-        sb.setLength(4);  // mix and match
-        writer.write('d');
-        assertEquals("based", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testEqualsIgnoreCase() {
-        final StrBuilder sb1 = new StrBuilder();
-        final StrBuilder sb2 = new StrBuilder();
-        assertTrue(sb1.equalsIgnoreCase(sb1));
-        assertTrue(sb1.equalsIgnoreCase(sb2));
-        assertTrue(sb2.equalsIgnoreCase(sb2));
-        
-        sb1.append("abc");
-        assertFalse(sb1.equalsIgnoreCase(sb2));
-        
-        sb2.append("ABC");
-        assertTrue(sb1.equalsIgnoreCase(sb2));
-        
-        sb2.clear().append("abc");
-        assertTrue(sb1.equalsIgnoreCase(sb2));
-        assertTrue(sb1.equalsIgnoreCase(sb1));
-        assertTrue(sb2.equalsIgnoreCase(sb2));
-        
-        sb2.clear().append("aBc");
-        assertTrue(sb1.equalsIgnoreCase(sb2));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testEquals() {
-        final StrBuilder sb1 = new StrBuilder();
-        final StrBuilder sb2 = new StrBuilder();
-        assertTrue(sb1.equals(sb2));
-        assertTrue(sb1.equals(sb1));
-        assertTrue(sb2.equals(sb2));
-        assertTrue(sb1.equals((Object) sb2));
-        
-        sb1.append("abc");
-        assertFalse(sb1.equals(sb2));
-        assertFalse(sb1.equals((Object) sb2));
-        
-        sb2.append("ABC");
-        assertFalse(sb1.equals(sb2));
-        assertFalse(sb1.equals((Object) sb2));
-        
-        sb2.clear().append("abc");
-        assertTrue(sb1.equals(sb2));
-        assertTrue(sb1.equals((Object) sb2));
-        
-        assertFalse(sb1.equals(Integer.valueOf(1)));
-        assertFalse(sb1.equals("abc"));
-    }
-
-    @Test
-    public void test_LANG_1131_EqualsWithNullStrBuilder() throws Exception {
-        final StrBuilder sb = new StrBuilder();
-        final StrBuilder other = null;
-        assertFalse(sb.equals(other));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testHashCode() {
-        final StrBuilder sb = new StrBuilder();
-        final int hc1a = sb.hashCode();
-        final int hc1b = sb.hashCode();
-        assertEquals(0, hc1a);
-        assertEquals(hc1a, hc1b);
-        
-        sb.append("abc");
-        final int hc2a = sb.hashCode();
-        final int hc2b = sb.hashCode();
-        assertTrue(hc2a != 0);
-        assertEquals(hc2a, hc2b);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testToString() {
-        final StrBuilder sb = new StrBuilder("abc");
-        assertEquals("abc", sb.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testToStringBuffer() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(new StringBuffer().toString(), sb.toStringBuffer().toString());
-        
-        sb.append("junit");
-        assertEquals(new StringBuffer("junit").toString(), sb.toStringBuffer().toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testToStringBuilder() {
-        final StrBuilder sb = new StrBuilder();
-        assertEquals(new StringBuilder().toString(), sb.toStringBuilder().toString());
-        
-        sb.append("junit");
-        assertEquals(new StringBuilder("junit").toString(), sb.toStringBuilder().toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testLang294() {
-        final StrBuilder sb = new StrBuilder("\n%BLAH%\nDo more stuff\neven more stuff\n%BLAH%\n");
-        sb.deleteAll("\n%BLAH%");
-        assertEquals("\nDo more stuff\neven more stuff\n", sb.toString()); 
-    }
-
-    @Test
-    public void testIndexOfLang294() {
-        final StrBuilder sb = new StrBuilder("onetwothree");
-        sb.deleteFirst("three");
-        assertEquals(-1, sb.indexOf("three"));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testLang295() {
-        final StrBuilder sb = new StrBuilder("onetwothree");
-        sb.deleteFirst("three");
-        assertFalse( "The contains(char) method is looking beyond the end of the string", sb.contains('h'));
-        assertEquals( "The indexOf(char) method is looking beyond the end of the string", -1, sb.indexOf('h'));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testLang412Right() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadRight(null, 10, '*');
-        assertEquals( "Failed to invoke appendFixedWidthPadRight correctly", "**********", sb.toString());
-    }
-
-    @Test
-    public void testLang412Left() {
-        final StrBuilder sb = new StrBuilder();
-        sb.appendFixedWidthPadLeft(null, 10, '*');
-        assertEquals( "Failed to invoke appendFixedWidthPadLeft correctly", "**********", sb.toString());
-    }
-
-    @Test
-    public void testAsBuilder() {
-        final StrBuilder sb = new StrBuilder().appendAll("Lorem", " ", "ipsum", " ", "dolor");
-        assertEquals(sb.toString(), sb.build());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendCharBuffer() {
-        final StrBuilder sb1 = new StrBuilder();
-        final CharBuffer buf = CharBuffer.allocate(10);
-        buf.append("0123456789");
-        buf.flip();
-        sb1.append(buf);
-        assertEquals("0123456789", sb1.toString());
-
-        final StrBuilder sb2 = new StrBuilder();
-        sb2.append(buf, 1, 8);
-        assertEquals("12345678", sb2.toString());
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testAppendToWriter() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final StringWriter writer = new StringWriter();
-        writer.append("Test ");
-
-        sb.appendTo(writer);
-
-        assertEquals("Test 1234567890", writer.toString());
-    }
-
-    @Test
-    public void testAppendToStringBuilder() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final StringBuilder builder = new StringBuilder("Test ");
-
-        sb.appendTo(builder);
-
-        assertEquals("Test 1234567890", builder.toString());
-    }
-
-    @Test
-    public void testAppendToStringBuffer() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final StringBuffer buffer = new StringBuffer("Test ");
-
-        sb.appendTo(buffer);
-
-        assertEquals("Test 1234567890", buffer.toString());
-    }
-
-    @Test
-    public void testAppendToCharBuffer() throws Exception {
-        final StrBuilder sb = new StrBuilder("1234567890");
-        final String text = "Test ";
-        final CharBuffer buffer = CharBuffer.allocate(sb.size() + text.length());
-        buffer.put(text);
-
-        sb.appendTo(buffer);
-
-        buffer.flip();
-        assertEquals("Test 1234567890", buffer.toString());
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StrLookupTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StrLookupTest.java b/src/test/java/org/apache/commons/text/beta/StrLookupTest.java
deleted file mode 100644
index 77ffc5f..0000000
--- a/src/test/java/org/apache/commons/text/beta/StrLookupTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link StrLookup}.
- */
-public class StrLookupTest  {
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testNoneLookup() {
-        assertEquals(null, StrLookup.noneLookup().lookup(null));
-        assertEquals(null, StrLookup.noneLookup().lookup(""));
-        assertEquals(null, StrLookup.noneLookup().lookup("any"));
-    }
-
-    @Test
-    public void testSystemProperiesLookup() {
-        assertEquals(System.getProperty("os.name"), StrLookup.systemPropertiesLookup().lookup("os.name"));
-        assertEquals(null, StrLookup.systemPropertiesLookup().lookup(""));
-        assertEquals(null, StrLookup.systemPropertiesLookup().lookup("other"));
-        try {
-            StrLookup.systemPropertiesLookup().lookup(null);
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
-    }
-
-    /**
-     * Tests that a lookup object for system properties can deal with a full
-     * replacement of the system properties object. This test is related to
-     * LANG-1055.
-     */
-    @Test
-    public void testSystemPropertiesLookupReplacedProperties() {
-        final Properties oldProperties = System.getProperties();
-        final String osName = "os.name";
-        final String newOsName = oldProperties.getProperty(osName) + "_changed";
-
-        final StrLookup<String> sysLookup = StrLookup.systemPropertiesLookup();
-        final Properties newProps = new Properties();
-        newProps.setProperty(osName, newOsName);
-        System.setProperties(newProps);
-        try {
-            assertEquals("Changed properties not detected", newOsName, sysLookup.lookup(osName));
-        } finally {
-            System.setProperties(oldProperties);
-        }
-    }
-
-    /**
-     * Tests that a lookup object for system properties sees changes on system
-     * properties. This test is related to LANG-1141.
-     */
-    @Test
-    public void testSystemPropertiesLookupUpdatedProperty() {
-        final String osName = "os.name";
-        final String oldOs = System.getProperty(osName);
-        final String newOsName = oldOs + "_changed";
-
-        final StrLookup<String> sysLookup = StrLookup.systemPropertiesLookup();
-        System.setProperty(osName, newOsName);
-        try {
-            assertEquals("Changed properties not detected", newOsName, sysLookup.lookup(osName));
-        } finally {
-            System.setProperty(osName, oldOs);
-        }
-    }
-
-    @Test
-    public void testMapLookup() {
-        final Map<String, Object> map = new HashMap<>();
-        map.put("key", "value");
-        map.put("number", Integer.valueOf(2));
-        assertEquals("value", StrLookup.mapLookup(map).lookup("key"));
-        assertEquals("2", StrLookup.mapLookup(map).lookup("number"));
-        assertEquals(null, StrLookup.mapLookup(map).lookup(null));
-        assertEquals(null, StrLookup.mapLookup(map).lookup(""));
-        assertEquals(null, StrLookup.mapLookup(map).lookup("other"));
-    }
-
-    @Test
-    public void testMapLookup_nullMap() {
-        final Map<String, ?> map = null;
-        assertEquals(null, StrLookup.mapLookup(map).lookup(null));
-        assertEquals(null, StrLookup.mapLookup(map).lookup(""));
-        assertEquals(null, StrLookup.mapLookup(map).lookup("any"));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/beta/StrMatcherTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/beta/StrMatcherTest.java b/src/test/java/org/apache/commons/text/beta/StrMatcherTest.java
deleted file mode 100644
index ef9356a..0000000
--- a/src/test/java/org/apache/commons/text/beta/StrMatcherTest.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- * 
- *      http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-/**
- * Unit tests for {@link StrMatcher}.
- */
-public class StrMatcherTest  {
-
-    private static final char[] BUFFER1 = "0,1\t2 3\n\r\f\u0000'\"".toCharArray();
-
-    private static final char[] BUFFER2 = "abcdef".toCharArray();
-
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCommaMatcher() {
-        final StrMatcher matcher = StrMatcher.commaMatcher();
-        assertSame(matcher, StrMatcher.commaMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 0));
-        assertEquals(1, matcher.isMatch(BUFFER1, 1));
-        assertEquals(0, matcher.isMatch(BUFFER1, 2));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTabMatcher() {
-        final StrMatcher matcher = StrMatcher.tabMatcher();
-        assertSame(matcher, StrMatcher.tabMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 2));
-        assertEquals(1, matcher.isMatch(BUFFER1, 3));
-        assertEquals(0, matcher.isMatch(BUFFER1, 4));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSpaceMatcher() {
-        final StrMatcher matcher = StrMatcher.spaceMatcher();
-        assertSame(matcher, StrMatcher.spaceMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 4));
-        assertEquals(1, matcher.isMatch(BUFFER1, 5));
-        assertEquals(0, matcher.isMatch(BUFFER1, 6));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSplitMatcher() {
-        final StrMatcher matcher = StrMatcher.splitMatcher();
-        assertSame(matcher, StrMatcher.splitMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 2));
-        assertEquals(1, matcher.isMatch(BUFFER1, 3));
-        assertEquals(0, matcher.isMatch(BUFFER1, 4));
-        assertEquals(1, matcher.isMatch(BUFFER1, 5));
-        assertEquals(0, matcher.isMatch(BUFFER1, 6));
-        assertEquals(1, matcher.isMatch(BUFFER1, 7));
-        assertEquals(1, matcher.isMatch(BUFFER1, 8));
-        assertEquals(1, matcher.isMatch(BUFFER1, 9));
-        assertEquals(0, matcher.isMatch(BUFFER1, 10));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testTrimMatcher() {
-        final StrMatcher matcher = StrMatcher.trimMatcher();
-        assertSame(matcher, StrMatcher.trimMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 2));
-        assertEquals(1, matcher.isMatch(BUFFER1, 3));
-        assertEquals(0, matcher.isMatch(BUFFER1, 4));
-        assertEquals(1, matcher.isMatch(BUFFER1, 5));
-        assertEquals(0, matcher.isMatch(BUFFER1, 6));
-        assertEquals(1, matcher.isMatch(BUFFER1, 7));
-        assertEquals(1, matcher.isMatch(BUFFER1, 8));
-        assertEquals(1, matcher.isMatch(BUFFER1, 9));
-        assertEquals(1, matcher.isMatch(BUFFER1, 10));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testSingleQuoteMatcher() {
-        final StrMatcher matcher = StrMatcher.singleQuoteMatcher();
-        assertSame(matcher, StrMatcher.singleQuoteMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 10));
-        assertEquals(1, matcher.isMatch(BUFFER1, 11));
-        assertEquals(0, matcher.isMatch(BUFFER1, 12));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testDoubleQuoteMatcher() {
-        final StrMatcher matcher = StrMatcher.doubleQuoteMatcher();
-        assertSame(matcher, StrMatcher.doubleQuoteMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 11));
-        assertEquals(1, matcher.isMatch(BUFFER1, 12));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testQuoteMatcher() {
-        final StrMatcher matcher = StrMatcher.quoteMatcher();
-        assertSame(matcher, StrMatcher.quoteMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 10));
-        assertEquals(1, matcher.isMatch(BUFFER1, 11));
-        assertEquals(1, matcher.isMatch(BUFFER1, 12));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testNoneMatcher() {
-        final StrMatcher matcher = StrMatcher.noneMatcher();
-        assertSame(matcher, StrMatcher.noneMatcher());
-        assertEquals(0, matcher.isMatch(BUFFER1, 0));
-        assertEquals(0, matcher.isMatch(BUFFER1, 1));
-        assertEquals(0, matcher.isMatch(BUFFER1, 2));
-        assertEquals(0, matcher.isMatch(BUFFER1, 3));
-        assertEquals(0, matcher.isMatch(BUFFER1, 4));
-        assertEquals(0, matcher.isMatch(BUFFER1, 5));
-        assertEquals(0, matcher.isMatch(BUFFER1, 6));
-        assertEquals(0, matcher.isMatch(BUFFER1, 7));
-        assertEquals(0, matcher.isMatch(BUFFER1, 8));
-        assertEquals(0, matcher.isMatch(BUFFER1, 9));
-        assertEquals(0, matcher.isMatch(BUFFER1, 10));
-        assertEquals(0, matcher.isMatch(BUFFER1, 11));
-        assertEquals(0, matcher.isMatch(BUFFER1, 12));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCharMatcher_char() {
-        final StrMatcher matcher = StrMatcher.charMatcher('c');
-        assertEquals(0, matcher.isMatch(BUFFER2, 0));
-        assertEquals(0, matcher.isMatch(BUFFER2, 1));
-        assertEquals(1, matcher.isMatch(BUFFER2, 2));
-        assertEquals(0, matcher.isMatch(BUFFER2, 3));
-        assertEquals(0, matcher.isMatch(BUFFER2, 4));
-        assertEquals(0, matcher.isMatch(BUFFER2, 5));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCharSetMatcher_String() {
-        final StrMatcher matcher = StrMatcher.charSetMatcher("ace");
-        assertEquals(1, matcher.isMatch(BUFFER2, 0));
-        assertEquals(0, matcher.isMatch(BUFFER2, 1));
-        assertEquals(1, matcher.isMatch(BUFFER2, 2));
-        assertEquals(0, matcher.isMatch(BUFFER2, 3));
-        assertEquals(1, matcher.isMatch(BUFFER2, 4));
-        assertEquals(0, matcher.isMatch(BUFFER2, 5));
-        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher(""));
-        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher((String) null));
-        assertTrue(StrMatcher.charSetMatcher("a") instanceof StrMatcher.CharMatcher);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testCharSetMatcher_charArray() {
-        final StrMatcher matcher = StrMatcher.charSetMatcher("ace".toCharArray());
-        assertEquals(1, matcher.isMatch(BUFFER2, 0));
-        assertEquals(0, matcher.isMatch(BUFFER2, 1));
-        assertEquals(1, matcher.isMatch(BUFFER2, 2));
-        assertEquals(0, matcher.isMatch(BUFFER2, 3));
-        assertEquals(1, matcher.isMatch(BUFFER2, 4));
-        assertEquals(0, matcher.isMatch(BUFFER2, 5));
-        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher(new char[0]));
-        assertSame(StrMatcher.noneMatcher(), StrMatcher.charSetMatcher((char[]) null));
-        assertTrue(StrMatcher.charSetMatcher("a".toCharArray()) instanceof StrMatcher.CharMatcher);
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testStringMatcher_String() {
-        final StrMatcher matcher = StrMatcher.stringMatcher("bc");
-        assertEquals(0, matcher.isMatch(BUFFER2, 0));
-        assertEquals(2, matcher.isMatch(BUFFER2, 1));
-        assertEquals(0, matcher.isMatch(BUFFER2, 2));
-        assertEquals(0, matcher.isMatch(BUFFER2, 3));
-        assertEquals(0, matcher.isMatch(BUFFER2, 4));
-        assertEquals(0, matcher.isMatch(BUFFER2, 5));
-        assertSame(StrMatcher.noneMatcher(), StrMatcher.stringMatcher(""));
-        assertSame(StrMatcher.noneMatcher(), StrMatcher.stringMatcher((String) null));
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
-    public void testMatcherIndices() {
-        // remember that the API contract is tight for the isMatch() method
-        // all the onus is on the caller, so invalid inputs are not
-        // the concern of StrMatcher, and are not bugs
-        final StrMatcher matcher = StrMatcher.stringMatcher("bc");
-        assertEquals(2, matcher.isMatch(BUFFER2, 1, 1, BUFFER2.length));
-        assertEquals(2, matcher.isMatch(BUFFER2, 1, 0, 3));
-        assertEquals(0, matcher.isMatch(BUFFER2, 1, 0, 2));
-    }
-
-}


[47/50] [abbrv] [text] (doc) userguide replace "text.beta." with "text."

Posted by ch...@apache.org.
(doc) userguide replace "text.beta." with "text."


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/dc10b4c1
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/dc10b4c1
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/dc10b4c1

Branch: refs/heads/release
Commit: dc10b4c1045cbd485752b7f9a0e3b6969f3eb98a
Parents: 1911d42
Author: Rob Tompkins <ch...@apache.org>
Authored: Sun Feb 26 20:16:58 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Sun Feb 26 20:16:58 2017 -0500

----------------------------------------------------------------------
 src/site/xdoc/userguide.xml | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/dc10b4c1/src/site/xdoc/userguide.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/userguide.xml b/src/site/xdoc/userguide.xml
index 8803797..a54fd16 100644
--- a/src/site/xdoc/userguide.xml
+++ b/src/site/xdoc/userguide.xml
@@ -31,10 +31,10 @@ limitations under the License.
         <h2>Users Guide</h2>
         <br/>
         <a href="#Description">[Description]</a>
-        <a href="#text.beta.">[text.beta.*]</a>
-        <a href="#text.beta.diff.">[text.beta.diff.*]</a>
-        <a href="#text.beta.similarity.">[text.beta.similarity.*]</a>
-        <a href="#text.beta.translate.">[text.beta.translate.*]</a>
+        <a href="#text.">[text.*]</a>
+        <a href="#text.diff.">[text.diff.*]</a>
+        <a href="#text.similarity.">[text.similarity.*]</a>
+        <a href="#text.translate.">[text.translate.*]</a>
         <br/>
         <br/>
       </div>
@@ -48,7 +48,7 @@ limitations under the License.
       </p>
     </section>
 
-    <section name="text.beta.*">
+    <section name="text.*">
 
       <p>Originally the text package was added in Commons Lang 2.2. However, its
         new home is here. It provides, amongst other
@@ -72,7 +72,7 @@ limitations under the License.
           It's provides ways in which to generate pieces of text, such as might
           be used for default passwords. StringEscapeUtils contains methods to
           escape and unescape Java, JavaScript, HTML, XML and SQL. It is worth noting that
-          the package <code>org.apache.commons.text.beta.translate</code> holds the
+          the package <code>org.apache.commons.text.translate</code> holds the
           functionality underpinning the StringEscapeUtils with mappings and translations
           between such mappings for the sake of doing String escaping. StrTokenizer is
           an improved alternative to java.util.StringTokenizer.
@@ -80,7 +80,7 @@ limitations under the License.
       </subsection>
 
       <subsection name="Similarity and Distance">
-        <p>The <code>org.apache.commons.text.beta.similarity</code> packages contains various different mechanisms of
+        <p>The <code>org.apache.commons.text.similarity</code> packages contains various different mechanisms of
           calculating "similarity scores" as well as "edit distances between Strings. Note,
           the difference between a "similarity score" and a "distance function" is that
           a distance functions meets the following qualifications:
@@ -120,7 +120,7 @@ limitations under the License.
 
       <subsection
               name="Text diff'ing">
-        <p>The <code>org.apache.commons.text.beta.diff</code> package contains code for
+        <p>The <code>org.apache.commons.text.diff</code> package contains code for
           doing diff between strings. The initial implementation of the Myers algorithm was adapted from the
           commons-collections sequence package.
         </p>
@@ -129,7 +129,7 @@ limitations under the License.
 
     </section>
 
-    <section name="text.beta.diff.*">
+    <section name="text.diff.*">
       <!--
       CommandVisitor
       DeleteCommand
@@ -147,7 +147,7 @@ limitations under the License.
       </p>
     </section>
 
-    <section name="text.beta.similarity.*">
+    <section name="text.similarity.*">
       <!--
       Enum
       EnumUtils


[30/50] [abbrv] [text] TEXT-65: 174 checkstyle errors

Posted by ch...@apache.org.
TEXT-65: 174 checkstyle errors


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/1035cd6d
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/1035cd6d
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/1035cd6d

Branch: refs/heads/release
Commit: 1035cd6de87ece49aa2fdd7faa23e004e5748daf
Parents: c7cf533
Author: Rob Tompkins <ch...@apache.org>
Authored: Sat Feb 11 10:46:12 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Sat Feb 11 10:46:12 2017 -0500

----------------------------------------------------------------------
 checkstyle-suppressions.xml                     |  6 ++-
 .../java/org/apache/commons/text/StrLookup.java |  1 +
 .../org/apache/commons/text/StrMatcher.java     |  8 ++--
 .../org/apache/commons/text/StrSubstitutor.java | 47 +++++++++++++-------
 4 files changed, 39 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/1035cd6d/checkstyle-suppressions.xml
----------------------------------------------------------------------
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
index f577e79..d6634e3 100644
--- a/checkstyle-suppressions.xml
+++ b/checkstyle-suppressions.xml
@@ -32,6 +32,8 @@
   <suppress checks="MagicNumber" files="JaroWinklerDistance.java" lines="0-99999" />
   <suppress checks="NoWhitespaceAfter" files="JaroWinklerDistance.java" lines="0-99999" />
   <suppress checks="FileLength" files="StrBuilder.java" lines="0-99999" />
-  <suppress checks="MagicNumber" files="StrBuilder.java" lines="0-99999"/>
-  <suppress checks="MagicNumber" files="StringEscapeUtils.java" lines="0-99999"/>
+  <suppress checks="MagicNumber" files="StrBuilder.java" lines="0-99999" />
+  <suppress checks="MagicNumber" files="StringEscapeUtils.java" lines="0-99999" />
+  <suppress checks="EmptyBlock" files="StrLookup.java" lines="0-99999" />
+  <suppress checks="MagicNumber" files="StrMatcher.java" lines="0-99999" />
 </suppressions>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/1035cd6d/src/main/java/org/apache/commons/text/StrLookup.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrLookup.java b/src/main/java/org/apache/commons/text/StrLookup.java
index f9bffb5..7c87670 100644
--- a/src/main/java/org/apache/commons/text/StrLookup.java
+++ b/src/main/java/org/apache/commons/text/StrLookup.java
@@ -31,6 +31,7 @@ import java.util.Map;
  * For example, it would be possible to implement a lookup that used the
  * key as a primary key, and looked up the value on demand from the database
  *
+ * @param <V> the type of the values supported by the lookup
  * @since 1.0
  */
 public abstract class StrLookup<V> {

http://git-wip-us.apache.org/repos/asf/commons-text/blob/1035cd6d/src/main/java/org/apache/commons/text/StrMatcher.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrMatcher.java b/src/main/java/org/apache/commons/text/StrMatcher.java
index 97d6673..357118c 100644
--- a/src/main/java/org/apache/commons/text/StrMatcher.java
+++ b/src/main/java/org/apache/commons/text/StrMatcher.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -277,7 +277,7 @@ public abstract class StrMatcher {
          *
          * @param chars  the characters to match, must not be null
          */
-        CharSetMatcher(final char chars[]) {
+        CharSetMatcher(final char[] chars) {
             super();
             this.chars = chars.clone();
             Arrays.sort(this.chars);
@@ -371,7 +371,7 @@ public abstract class StrMatcher {
             }
             return len;
         }
-        
+
         @Override
         public String toString() {
             return super.toString() + ' ' + Arrays.toString(chars);

http://git-wip-us.apache.org/repos/asf/commons-text/blob/1035cd6d/src/main/java/org/apache/commons/text/StrSubstitutor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/StrSubstitutor.java b/src/main/java/org/apache/commons/text/StrSubstitutor.java
index 00d05f7..82a4e22 100644
--- a/src/main/java/org/apache/commons/text/StrSubstitutor.java
+++ b/src/main/java/org/apache/commons/text/StrSubstitutor.java
@@ -152,7 +152,7 @@ public class StrSubstitutor {
      */
     private StrMatcher suffixMatcher;
     /**
-     * Stores the default variable value delimiter
+     * Stores the default variable value delimiter.
      */
     private StrMatcher valueDelimiterMatcher;
     /**
@@ -195,7 +195,10 @@ public class StrSubstitutor {
      * @return the result of the replace operation
      * @throws IllegalArgumentException if the prefix or suffix is null
      */
-    public static <V> String replace(final Object source, final Map<String, V> valueMap, final String prefix, final String suffix) {
+    public static <V> String replace(final Object source,
+                                     final Map<String, V> valueMap,
+                                     final String prefix,
+                                     final String suffix) {
         return new StrSubstitutor(valueMap, prefix, suffix).replace(source);
     }
 
@@ -211,10 +214,10 @@ public class StrSubstitutor {
         if (valueProperties == null) {
             return source.toString();
         }
-        final Map<String,String> valueMap = new HashMap<>();
+        final Map<String, String> valueMap = new HashMap<>();
         final Enumeration<?> propNames = valueProperties.propertyNames();
         while (propNames.hasMoreElements()) {
-            final String propName = (String)propNames.nextElement();
+            final String propName = (String) propNames.nextElement();
             final String propValue = valueProperties.getProperty(propName);
             valueMap.put(propName, propValue);
         }
@@ -390,7 +393,7 @@ public class StrSubstitutor {
             return null;
         }
         final StrBuilder buf = new StrBuilder(source);
-        if (substitute(buf, 0, source.length()) == false) {
+        if (!substitute(buf, 0, source.length())) {
             return source;
         }
         return buf.toString();
@@ -413,7 +416,7 @@ public class StrSubstitutor {
             return null;
         }
         final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        if (substitute(buf, 0, length) == false) {
+        if (!substitute(buf, 0, length)) {
             return source.substring(offset, offset + length);
         }
         return buf.toString();
@@ -628,7 +631,7 @@ public class StrSubstitutor {
             return false;
         }
         final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        if (substitute(buf, 0, length) == false) {
+        if (!substitute(buf, 0, length)) {
             return false;
         }
         source.replace(offset, offset + length, buf.toString());
@@ -669,7 +672,7 @@ public class StrSubstitutor {
             return false;
         }
         final StrBuilder buf = new StrBuilder(length).append(source, offset, length);
-        if (substitute(buf, 0, length) == false) {
+        if (!substitute(buf, 0, length)) {
             return false;
         }
         source.replace(offset, offset + length, buf.toString());
@@ -780,9 +783,11 @@ public class StrSubstitutor {
                     int nestedVarCount = 0;
                     while (pos < bufEnd) {
                         if (substitutionInVariablesEnabled
-                                && (endMatchLen = pfxMatcher.isMatch(chars,
-                                        pos, offset, bufEnd)) != 0) {
+                                && pfxMatcher.isMatch(chars,
+                                        pos, offset, bufEnd) != 0) {
                             // found a nested variable start
+                            endMatchLen = pfxMatcher.isMatch(chars,
+                                    pos, offset, bufEnd);
                             nestedVarCount++;
                             pos += endMatchLen;
                             continue;
@@ -813,12 +818,17 @@ public class StrSubstitutor {
                                     final char [] varNameExprChars = varNameExpr.toCharArray();
                                     int valueDelimiterMatchLen = 0;
                                     for (int i = 0; i < varNameExprChars.length; i++) {
-                                        // if there's any nested variable when nested variable substitution disabled, then stop resolving name and default value.
+                                        // if there's any nested variable when nested variable substitution disabled,
+                                        // then stop resolving name and default value.
                                         if (!substitutionInVariablesEnabled
-                                                && pfxMatcher.isMatch(varNameExprChars, i, i, varNameExprChars.length) != 0) {
+                                                && pfxMatcher.isMatch(varNameExprChars,
+                                                                        i,
+                                                                        i,
+                                                                        varNameExprChars.length) != 0) {
                                             break;
                                         }
-                                        if ((valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, i)) != 0) {
+                                        if (valueDelimMatcher.isMatch(varNameExprChars, i) != 0) {
+                                            valueDelimiterMatchLen = valueDelimMatcher.isMatch(varNameExprChars, i);
                                             varName = varNameExpr.substring(0, i);
                                             varDefaultValue = varNameExpr.substring(i + valueDelimiterMatchLen);
                                             break;
@@ -884,7 +894,7 @@ public class StrSubstitutor {
      * @param priorVariables  the list of prior variables
      */
     private void checkCyclicSubstitution(final String varName, final List<String> priorVariables) {
-        if (priorVariables.contains(varName) == false) {
+        if (!priorVariables.contains(varName)) {
             return;
         }
         final StrBuilder buf = new StrBuilder(256);
@@ -912,7 +922,10 @@ public class StrSubstitutor {
      * @param endPos  the end position of the variable including the suffix, valid
      * @return the variable's value or <b>null</b> if the variable is unknown
      */
-    protected String resolveVariable(final String variableName, final StrBuilder buf, final int startPos, final int endPos) {
+    protected String resolveVariable(final String variableName,
+                                     final StrBuilder buf,
+                                     final int startPos,
+                                     final int endPos) {
         final StrLookup<?> resolver = getVariableResolver();
         if (resolver == null) {
             return null;
@@ -1189,7 +1202,7 @@ public class StrSubstitutor {
     /**
      * Returns the flag controlling whether escapes are preserved during
      * substitution.
-     * 
+     *
      * @return the preserve escape flag
      */
     public boolean isPreserveEscapes() {
@@ -1204,7 +1217,7 @@ public class StrSubstitutor {
      * character is removed during substitution (e.g.
      * <code>$${this-is-escaped}</code> becomes
      * <code>${this-is-escaped}</code>).  The default value is <b>false</b>
-     * 
+     *
      * @param preserveEscapes true if escapes are to be preserved
      */
     public void setPreserveEscapes(final boolean preserveEscapes) {


[45/50] [abbrv] [text] TEXT-69: simplifying ternary that returns boolean value

Posted by ch...@apache.org.
TEXT-69: simplifying ternary that returns boolean value


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/4bc51591
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/4bc51591
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/4bc51591

Branch: refs/heads/release
Commit: 4bc51591fe9d482a7fdbb21373b51f3f70765bac
Parents: 867c38f
Author: Rob Tompkins <ch...@apache.org>
Authored: Wed Feb 22 13:23:36 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Wed Feb 22 13:23:36 2017 -0500

----------------------------------------------------------------------
 .../apache/commons/text/translate/NumericEntityUnescaper.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/4bc51591/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
index e8f59c6..4a89153 100644
--- a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
@@ -32,7 +32,7 @@ import java.util.EnumSet;
 public class NumericEntityUnescaper extends CharSequenceTranslator {
 
     /** NumericEntityUnescaper option enum. */
-    public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
+    public enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
 
     /** EnumSet of OPTIONS, given from the constructor. */
     private final EnumSet<OPTION> options;
@@ -68,7 +68,7 @@ public class NumericEntityUnescaper extends CharSequenceTranslator {
      * @return whether the option is set
      */
     public boolean isSet(final OPTION option) {
-        return options == null ? false : options.contains(option);
+        return options != null && options.contains(option);
     }
 
     /**


[34/50] [abbrv] [text] chore: site, release history

Posted by ch...@apache.org.
chore: site, release history


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/01e630b4
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/01e630b4
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/01e630b4

Branch: refs/heads/release
Commit: 01e630b4e9c82156340c416db94a39b158e4e085
Parents: c7cf533
Author: Rob Tompkins <ch...@apache.org>
Authored: Tue Feb 14 21:05:49 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Tue Feb 14 21:05:49 2017 -0500

----------------------------------------------------------------------
 .../release-notes/RELEASE-NOTES-1.0-beta-1.txt  | 113 +++++++++++++++++++
 src/site/xdoc/release-history.xml               |   6 +-
 2 files changed, 117 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/01e630b4/src/site/resources/release-notes/RELEASE-NOTES-1.0-beta-1.txt
----------------------------------------------------------------------
diff --git a/src/site/resources/release-notes/RELEASE-NOTES-1.0-beta-1.txt b/src/site/resources/release-notes/RELEASE-NOTES-1.0-beta-1.txt
new file mode 100644
index 0000000..56769a8
--- /dev/null
+++ b/src/site/resources/release-notes/RELEASE-NOTES-1.0-beta-1.txt
@@ -0,0 +1,113 @@
+                          Apache Commons Text
+                           Version 1.0-beta-1
+                             Release Notes
+
+
+INTRODUCTION
+============
+
+This document contains the release notes for the 1.0-beta-1 version of Apache
+Commons Text. Commons Text is a set of utility functions and reusable components
+for the purpose of processing and manipulating text that should be of use in a
+Java environment.
+
+Apache Commons Text is a library focused on algorithms working on strings.
+
+A NOTE ON THE HISTORY OF THE CODE
+=================================
+
+The codebase began in the fall of 2014 as a location for housing algorithms for
+operating on Strings that seemed to have a more complex nature than those which
+would be considered a needed extension to java.lang. Thus, a new component,
+different from Apache Commons Lang was warranted. As the project evolved, it was
+noticed that Commons Lang had considerable more text manipulation tools than
+the average Java application developer would need or even want. So, we have
+decided to move the more esoteric String processing algorithms out of Commons
+Lang into Commons Text.
+
+JAVA 9 SUPPORT
+==============
+
+At our time of release our build succeeds with Java 9-ea build 153, and we
+believe all of our features to be Java 9 compatible.
+
+NEW FEATURES
+============
+
+o TEXT-56:   Move CvsTranslators out of StringEscapeUtils and make them DRY
+             Thanks to Jarek Strzeleck.
+o TEXT-40:   Escape HTML characters only once Thanks to Sampanna Kahu.
+o TEXT-32:   Add LCS similarity and distance
+o TEXT-34:   Add class to generate random strings
+o TEXT-29:   Add a builder to StringEscapeUtils
+o TEXT-28:   Add shell/XSI escape/unescape support
+o TEXT-2:    Add Jaccard Index and Jaccard Distance Thanks to Don Jeba.
+o TEXT-27:   Move org.apache.commons.lang3.StringEscapeUtils.java into text
+o TEXT-23:   Moving from commons-lang, the package org.apache.commons.lang3.text
+o TEXT-10:   A more complex Levenshtein distance Thanks to Don Jeba.
+o TEXT-24:   Add coveralls and Travis.ci integration
+o TEXT-19:   Add alphabet converter Thanks to Eyal Allweil.
+o TEXT-13:   Create Commons Text logo
+o TEXT-7:    Write user guide
+o TEXT-15:   Human name parser
+o TEXT-3:    Add Cosine Similarity and Cosine Distance
+o TEXT-4:    Port Myers algorithm from [collections]
+o TEXT-1:    Add Hamming distance
+o TEXT-9:    Incorporate String algorithms from Commons Lang Thanks to britter.
+
+FIXED BUGS
+==========
+
+Note. We recognize the curiosity of a new component having "fixed bugs," but a
+considerable number of files were migrated over from Commons Lang, some of which
+needed fixes.
+
+o TEXT-62:   Incorporate suggestions from RC2 into 1.0 release.
+o TEXT-60:   Upgrading Jacoco for Java 9-ea compatibility. Thanks to Lee Adcock.
+o TEXT-52:   Possible attacks through StringEscapeUtils.escapeEcmaScrip better
+             javadoc
+o TEXT-37:   Global vs local source of randomness
+o TEXT-38:   Fluent API in "RandomStringBuilder"
+o TEXT-26:   Fix JaroWinklerDistance in the manner of LUCENE-1297
+o TEXT-35:   Unfinished class Javadoc for CosineDistance
+o TEXT-22:   LevenshteinDistance reduce memory consumption
+o TEXT-5:    IP clearance for the names package
+o TEXT-11:   Work on the string metric, distance, and similarity definitions for
+             the project
+o TEXT-12:   Create StringDistanceFrom class that contains a StringMetric and
+             the "left" side string. This would have a method that accepts the
+             "right" side string to test. Thanks to Jonathan baker.
+o TEXT-8:    Change (R) StringMetric.compare(CS left, CS right) to "apply" so
+             that it is consistent with BiFunction. Thanks to Jonathan Baker.
+o TEXT-6:    Allow extra information (e.g. Levenshtein threshold) to be stored
+             as (final) fields in the StringMetric instance. Thanks to Jonathan
+             Baker.
+
+CHANGES
+=======
+
+o TEXT-61:   Naming packages org.apache.commons.text.beta Thanks to Lee Adcock.
+o TEXT-58:   Refactor EntityArrays to have unmodifiableMaps in leu of String[][]
+o TEXT-53:   Prepare site for 1.0 release
+o TEXT-50:   Upgrade from commons-parent version 41 to version 42
+o TEXT-33:   Consolidating since tags at 1.0, removing deprecated methods
+o TEXT-16:   Improve HumanNameParser
+
+REMOVED
+=======
+
+o TEXT-55:   Remove WordUtils to be added back in an upcoming 1.X release
+o TEXT-51:   Remove RandomStringGenerator to be added back in the 1.1 release
+o TEXT-31:   Remove org.apache.commons.text.names, for later release than 1.0
+
+
+Historical list of changes: http://commons.apache.org/text/changes-report.html
+
+For complete information on Apache Commons Text, including instructions on how
+to submit bug reports, patches, or suggestions for improvement, see the Apache
+Apache Commons Text website:
+
+http://commons.apache.org/text/
+
+Have fun!
+-Apache Commons Text team
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-text/blob/01e630b4/src/site/xdoc/release-history.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/release-history.xml b/src/site/xdoc/release-history.xml
index 22b3b4c..b91841b 100644
--- a/src/site/xdoc/release-history.xml
+++ b/src/site/xdoc/release-history.xml
@@ -27,8 +27,10 @@ limitations under the License.
 <!-- TODO: Add the Java version for each release -->
 
 <table>
-<tr><th>Version</th><th>Release date</th><th>Javadoc</th><th>Release notes</th></tr>
-<tr><td>1.0</td><td>tba</td><td><a href="apidocs/index.html">0.1-SNAPSHOT</a></td><td>Release forthcoming</td></tr>
+<tr><th>Version</th><th>Release date</th><th>Required Java Version</th><th>Javadoc</th><th>Release notes</th></tr>
+<tr>
+  <td>1.0-beta-1</td><td>2-9-2017</td><td>7.0</td><td><a href="javadocs/api-1.0-beta-1/">api-1.0-beta-1</a></td><td><a href="/RELEASE-NOTES.txt">release notes for 1.0-beta-1</a></td>
+</tr>
 </table>
 
 </section>


[33/50] [abbrv] [text] TEXT-65: 3 TODO checkstyle errors

Posted by ch...@apache.org.
TEXT-65: 3 TODO checkstyle errors


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/0900a4c9
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/0900a4c9
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/0900a4c9

Branch: refs/heads/release
Commit: 0900a4c91cece58e6d14faeb92507c544a731df1
Parents: 3e07584
Author: Rob Tompkins <ch...@apache.org>
Authored: Tue Feb 14 20:55:14 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Tue Feb 14 20:55:14 2017 -0500

----------------------------------------------------------------------
 checkstyle-suppressions.xml                             |  4 ++++
 .../commons/text/translate/NumericEntityUnescaper.java  |  2 +-
 .../apache/commons/text/translate/UnicodeEscaper.java   | 12 ++++++++----
 .../apache/commons/text/translate/UnicodeUnescaper.java | 11 ++++++-----
 .../text/translate/UnicodeUnpairedSurrogateRemover.java |  2 +-
 5 files changed, 20 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/0900a4c9/checkstyle-suppressions.xml
----------------------------------------------------------------------
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
index cc03b22..d52e173 100644
--- a/checkstyle-suppressions.xml
+++ b/checkstyle-suppressions.xml
@@ -53,4 +53,8 @@
   <suppress checks="MagicNumber" files="NumericEntityUnescaper.java" lines="0-99999" />
 
   <suppress checks="MagicNumber" files="OctalUnescaper.java" lines="0-99999" />
+
+  <suppress checks="MagicNumber" files="UnicodeEscaper.java" lines="0-99999" />
+
+  <suppress checks="MagicNumber" files="UnicodeUnescaper.java" lines="0-99999" />
 </suppressions>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/0900a4c9/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
index 42b38ef..6060cf8 100644
--- a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
@@ -35,7 +35,7 @@ public class NumericEntityUnescaper extends CharSequenceTranslator {
     public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
 
     /** EnumSet of OPTIONS, given from the constructor. */
-    // TODO?: Create an OptionsSet class to hide some of the conditional logic below
+    // TODO: Create an OptionsSet class to hide some of the conditional logic below
     private final EnumSet<OPTION> options;
 
     /**

http://git-wip-us.apache.org/repos/asf/commons-text/blob/0900a4c9/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java b/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
index 04b24e2..8fba4b4 100644
--- a/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
@@ -26,14 +26,18 @@ import java.io.Writer;
  */
 public class UnicodeEscaper extends CodePointTranslator {
 
+    /** int value representing the lowest codepoint boundary. */
     private final int below;
+    /** int value representing the highest codepoint boundary. */
     private final int above;
+    /** whether to escape between the boundaries or outside them. */
     private final boolean between;
 
     /**
-     * <p>Constructs a <code>UnicodeEscaper</code> for all characters. </p>
+     * <p>Constructs a <code>UnicodeEscaper</code> for all characters.
+     * </p>
      */
-    public UnicodeEscaper(){
+    public UnicodeEscaper() {
         this(0, Integer.MAX_VALUE, true);
     }
 
@@ -124,8 +128,8 @@ public class UnicodeEscaper extends CodePointTranslator {
     }
 
     /**
-     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX"}
-     * 
+     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX"}.
+     *
      * @param codepoint
      *            a Unicode code point
      * @return the hex string for the given codepoint

http://git-wip-us.apache.org/repos/asf/commons-text/blob/0900a4c9/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java b/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
index 3a91d6c..1665d91 100644
--- a/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,8 +20,8 @@ import java.io.IOException;
 import java.io.Writer;
 
 /**
- * Translates escaped Unicode values of the form \\u+\d\d\d\d back to 
- * Unicode. It supports multiple 'u' characters and will work with or 
+ * Translates escaped Unicode values of the form \\u+\d\d\d\d back to
+ * Unicode. It supports multiple 'u' characters and will work with or
  * without the +.
  *
  * @since 1.0
@@ -56,7 +56,8 @@ public class UnicodeUnescaper extends CharSequenceTranslator {
                 }
                 return i + 4;
             }
-            throw new IllegalArgumentException("Less than 4 hex digits in unicode value: '" + input.subSequence(index, input.length())
+            throw new IllegalArgumentException("Less than 4 hex digits in unicode value: '"
+                    + input.subSequence(index, input.length())
                     + "' due to end of CharSequence");
         }
         return 0;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/0900a4c9/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java b/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
index ca90b89..09d69c7 100644
--- a/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
@@ -26,7 +26,7 @@ import java.io.Writer;
  */
 public class UnicodeUnpairedSurrogateRemover extends CodePointTranslator {
     /**
-     * Implementation of translate that throws out unpaired surrogates. 
+     * Implementation of translate that throws out unpaired surrogates.
      * {@inheritDoc}
      */
     @Override


[03/50] [abbrv] [text] Putting release history in master branch from 1.0-beta-1

Posted by ch...@apache.org.
Putting release history in master branch from 1.0-beta-1


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/80ec859d
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/80ec859d
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/80ec859d

Branch: refs/heads/release
Commit: 80ec859d8f2a5318d19e7b2735a6c985297f558e
Parents: 5066ac6 65e4314
Author: Rob Tompkins <ch...@apache.org>
Authored: Thu Feb 9 08:18:43 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Thu Feb 9 08:18:43 2017 -0500

----------------------------------------------------------------------
 pom.xml | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/80ec859d/pom.xml
----------------------------------------------------------------------


[16/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/EntityArrays.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/EntityArrays.java b/src/main/java/org/apache/commons/text/translate/EntityArrays.java
new file mode 100644
index 0000000..f5876f2
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/EntityArrays.java
@@ -0,0 +1,445 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Class holding various entity data for HTML and XML - generally for use with
+ * the LookupTranslator.
+ * All Maps are generated using <code>java.util.Collections.unmodifiableMap()</code>.
+ *
+ * @since 1.0
+ */
+public class EntityArrays {
+
+   /**
+     * A Map&lt;CharSequence, CharSequence&gt; to to escape
+     * <a href="https://secure.wikimedia.org/wikipedia/en/wiki/ISO/IEC_8859-1">ISO-8859-1</a>
+     * characters to their named HTML 3.x equivalents.
+     */
+    public static final Map<CharSequence, CharSequence> ISO8859_1_ESCAPE;
+    static {
+        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
+        initialMap.put("\u00A0", "&nbsp;"); // non-breaking space
+        initialMap.put("\u00A1", "&iexcl;"); // inverted exclamation mark
+        initialMap.put("\u00A2", "&cent;"); // cent sign
+        initialMap.put("\u00A3", "&pound;"); // pound sign
+        initialMap.put("\u00A4", "&curren;"); // currency sign
+        initialMap.put("\u00A5", "&yen;"); // yen sign = yuan sign
+        initialMap.put("\u00A6", "&brvbar;"); // broken bar = broken vertical bar
+        initialMap.put("\u00A7", "&sect;"); // section sign
+        initialMap.put("\u00A8", "&uml;"); // diaeresis = spacing diaeresis
+        initialMap.put("\u00A9", "&copy;"); // � - copyright sign
+        initialMap.put("\u00AA", "&ordf;"); // feminine ordinal indicator
+        initialMap.put("\u00AB", "&laquo;"); // left-pointing double angle quotation mark = left pointing guillemet
+        initialMap.put("\u00AC", "&not;"); // not sign
+        initialMap.put("\u00AD", "&shy;"); // soft hyphen = discretionary hyphen
+        initialMap.put("\u00AE", "&reg;"); // � - registered trademark sign
+        initialMap.put("\u00AF", "&macr;"); // macron = spacing macron = overline = APL overbar
+        initialMap.put("\u00B0", "&deg;"); // degree sign
+        initialMap.put("\u00B1", "&plusmn;"); // plus-minus sign = plus-or-minus sign
+        initialMap.put("\u00B2", "&sup2;"); // superscript two = superscript digit two = squared
+        initialMap.put("\u00B3", "&sup3;"); // superscript three = superscript digit three = cubed
+        initialMap.put("\u00B4", "&acute;"); // acute accent = spacing acute
+        initialMap.put("\u00B5", "&micro;"); // micro sign
+        initialMap.put("\u00B6", "&para;"); // pilcrow sign = paragraph sign
+        initialMap.put("\u00B7", "&middot;"); // middle dot = Georgian comma = Greek middle dot
+        initialMap.put("\u00B8", "&cedil;"); // cedilla = spacing cedilla
+        initialMap.put("\u00B9", "&sup1;"); // superscript one = superscript digit one
+        initialMap.put("\u00BA", "&ordm;"); // masculine ordinal indicator
+        initialMap.put("\u00BB", "&raquo;"); // right-pointing double angle quotation mark = right pointing guillemet
+        initialMap.put("\u00BC", "&frac14;"); // vulgar fraction one quarter = fraction one quarter
+        initialMap.put("\u00BD", "&frac12;"); // vulgar fraction one half = fraction one half
+        initialMap.put("\u00BE", "&frac34;"); // vulgar fraction three quarters = fraction three quarters
+        initialMap.put("\u00BF", "&iquest;"); // inverted question mark = turned question mark
+        initialMap.put("\u00C0", "&Agrave;"); // � - uppercase A, grave accent
+        initialMap.put("\u00C1", "&Aacute;"); // � - uppercase A, acute accent
+        initialMap.put("\u00C2", "&Acirc;"); // � - uppercase A, circumflex accent
+        initialMap.put("\u00C3", "&Atilde;"); // � - uppercase A, tilde
+        initialMap.put("\u00C4", "&Auml;"); // � - uppercase A, umlaut
+        initialMap.put("\u00C5", "&Aring;"); // � - uppercase A, ring
+        initialMap.put("\u00C6", "&AElig;"); // � - uppercase AE
+        initialMap.put("\u00C7", "&Ccedil;"); // � - uppercase C, cedilla
+        initialMap.put("\u00C8", "&Egrave;"); // � - uppercase E, grave accent
+        initialMap.put("\u00C9", "&Eacute;"); // � - uppercase E, acute accent
+        initialMap.put("\u00CA", "&Ecirc;"); // � - uppercase E, circumflex accent
+        initialMap.put("\u00CB", "&Euml;"); // � - uppercase E, umlaut
+        initialMap.put("\u00CC", "&Igrave;"); // � - uppercase I, grave accent
+        initialMap.put("\u00CD", "&Iacute;"); // � - uppercase I, acute accent
+        initialMap.put("\u00CE", "&Icirc;"); // � - uppercase I, circumflex accent
+        initialMap.put("\u00CF", "&Iuml;"); // � - uppercase I, umlaut
+        initialMap.put("\u00D0", "&ETH;"); // � - uppercase Eth, Icelandic
+        initialMap.put("\u00D1", "&Ntilde;"); // � - uppercase N, tilde
+        initialMap.put("\u00D2", "&Ograve;"); // � - uppercase O, grave accent
+        initialMap.put("\u00D3", "&Oacute;"); // � - uppercase O, acute accent
+        initialMap.put("\u00D4", "&Ocirc;"); // � - uppercase O, circumflex accent
+        initialMap.put("\u00D5", "&Otilde;"); // � - uppercase O, tilde
+        initialMap.put("\u00D6", "&Ouml;"); // � - uppercase O, umlaut
+        initialMap.put("\u00D7", "&times;"); // multiplication sign
+        initialMap.put("\u00D8", "&Oslash;"); // � - uppercase O, slash
+        initialMap.put("\u00D9", "&Ugrave;"); // � - uppercase U, grave accent
+        initialMap.put("\u00DA", "&Uacute;"); // � - uppercase U, acute accent
+        initialMap.put("\u00DB", "&Ucirc;"); // � - uppercase U, circumflex accent
+        initialMap.put("\u00DC", "&Uuml;"); // � - uppercase U, umlaut
+        initialMap.put("\u00DD", "&Yacute;"); // � - uppercase Y, acute accent
+        initialMap.put("\u00DE", "&THORN;"); // � - uppercase THORN, Icelandic
+        initialMap.put("\u00DF", "&szlig;"); // � - lowercase sharps, German
+        initialMap.put("\u00E0", "&agrave;"); // � - lowercase a, grave accent
+        initialMap.put("\u00E1", "&aacute;"); // � - lowercase a, acute accent
+        initialMap.put("\u00E2", "&acirc;"); // � - lowercase a, circumflex accent
+        initialMap.put("\u00E3", "&atilde;"); // � - lowercase a, tilde
+        initialMap.put("\u00E4", "&auml;"); // � - lowercase a, umlaut
+        initialMap.put("\u00E5", "&aring;"); // � - lowercase a, ring
+        initialMap.put("\u00E6", "&aelig;"); // � - lowercase ae
+        initialMap.put("\u00E7", "&ccedil;"); // � - lowercase c, cedilla
+        initialMap.put("\u00E8", "&egrave;"); // � - lowercase e, grave accent
+        initialMap.put("\u00E9", "&eacute;"); // � - lowercase e, acute accent
+        initialMap.put("\u00EA", "&ecirc;"); // � - lowercase e, circumflex accent
+        initialMap.put("\u00EB", "&euml;"); // � - lowercase e, umlaut
+        initialMap.put("\u00EC", "&igrave;"); // � - lowercase i, grave accent
+        initialMap.put("\u00ED", "&iacute;"); // � - lowercase i, acute accent
+        initialMap.put("\u00EE", "&icirc;"); // � - lowercase i, circumflex accent
+        initialMap.put("\u00EF", "&iuml;"); // � - lowercase i, umlaut
+        initialMap.put("\u00F0", "&eth;"); // � - lowercase eth, Icelandic
+        initialMap.put("\u00F1", "&ntilde;"); // � - lowercase n, tilde
+        initialMap.put("\u00F2", "&ograve;"); // � - lowercase o, grave accent
+        initialMap.put("\u00F3", "&oacute;"); // � - lowercase o, acute accent
+        initialMap.put("\u00F4", "&ocirc;"); // � - lowercase o, circumflex accent
+        initialMap.put("\u00F5", "&otilde;"); // � - lowercase o, tilde
+        initialMap.put("\u00F6", "&ouml;"); // � - lowercase o, umlaut
+        initialMap.put("\u00F7", "&divide;"); // division sign
+        initialMap.put("\u00F8", "&oslash;"); // � - lowercase o, slash
+        initialMap.put("\u00F9", "&ugrave;"); // � - lowercase u, grave accent
+        initialMap.put("\u00FA", "&uacute;"); // � - lowercase u, acute accent
+        initialMap.put("\u00FB", "&ucirc;"); // � - lowercase u, circumflex accent
+        initialMap.put("\u00FC", "&uuml;"); // � - lowercase u, umlaut
+        initialMap.put("\u00FD", "&yacute;"); // � - lowercase y, acute accent
+        initialMap.put("\u00FE", "&thorn;"); // � - lowercase thorn, Icelandic
+        initialMap.put("\u00FF", "&yuml;"); // � - lowercase y, umlaut
+        ISO8859_1_ESCAPE = Collections.unmodifiableMap(initialMap);
+    }
+
+    /**
+     * Reverse of {@link #ISO8859_1_ESCAPE} for unescaping purposes.
+     */
+    public static final Map<CharSequence, CharSequence> ISO8859_1_UNESCAPE;
+    static {
+        ISO8859_1_UNESCAPE = Collections.unmodifiableMap(invert(ISO8859_1_ESCAPE));
+    }
+
+    /**
+     * A Map&lt;CharSequence, CharSequence&gt; to escape additional
+     * <a href="http://www.w3.org/TR/REC-html40/sgml/entities.html">character entity
+     * references</a>. Note that this must be used with {@link #ISO8859_1_ESCAPE} to get the full list of
+     * HTML 4.0 character entities.
+     */
+    public static final Map<CharSequence, CharSequence> HTML40_EXTENDED_ESCAPE;
+    static {
+        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
+        // <!-- Latin Extended-B -->
+        initialMap.put("\u0192", "&fnof;"); // latin small f with hook = function= florin, U+0192 ISOtech -->
+        // <!-- Greek -->
+        initialMap.put("\u0391", "&Alpha;"); // greek capital letter alpha, U+0391 -->
+        initialMap.put("\u0392", "&Beta;"); // greek capital letter beta, U+0392 -->
+        initialMap.put("\u0393", "&Gamma;"); // greek capital letter gamma,U+0393 ISOgrk3 -->
+        initialMap.put("\u0394", "&Delta;"); // greek capital letter delta,U+0394 ISOgrk3 -->
+        initialMap.put("\u0395", "&Epsilon;"); // greek capital letter epsilon, U+0395 -->
+        initialMap.put("\u0396", "&Zeta;"); // greek capital letter zeta, U+0396 -->
+        initialMap.put("\u0397", "&Eta;"); // greek capital letter eta, U+0397 -->
+        initialMap.put("\u0398", "&Theta;"); // greek capital letter theta,U+0398 ISOgrk3 -->
+        initialMap.put("\u0399", "&Iota;"); // greek capital letter iota, U+0399 -->
+        initialMap.put("\u039A", "&Kappa;"); // greek capital letter kappa, U+039A -->
+        initialMap.put("\u039B", "&Lambda;"); // greek capital letter lambda,U+039B ISOgrk3 -->
+        initialMap.put("\u039C", "&Mu;"); // greek capital letter mu, U+039C -->
+        initialMap.put("\u039D", "&Nu;"); // greek capital letter nu, U+039D -->
+        initialMap.put("\u039E", "&Xi;"); // greek capital letter xi, U+039E ISOgrk3 -->
+        initialMap.put("\u039F", "&Omicron;"); // greek capital letter omicron, U+039F -->
+        initialMap.put("\u03A0", "&Pi;"); // greek capital letter pi, U+03A0 ISOgrk3 -->
+        initialMap.put("\u03A1", "&Rho;"); // greek capital letter rho, U+03A1 -->
+        // <!-- there is no Sigmaf, and no U+03A2 character either -->
+        initialMap.put("\u03A3", "&Sigma;"); // greek capital letter sigma,U+03A3 ISOgrk3 -->
+        initialMap.put("\u03A4", "&Tau;"); // greek capital letter tau, U+03A4 -->
+        initialMap.put("\u03A5", "&Upsilon;"); // greek capital letter upsilon,U+03A5 ISOgrk3 -->
+        initialMap.put("\u03A6", "&Phi;"); // greek capital letter phi,U+03A6 ISOgrk3 -->
+        initialMap.put("\u03A7", "&Chi;"); // greek capital letter chi, U+03A7 -->
+        initialMap.put("\u03A8", "&Psi;"); // greek capital letter psi,U+03A8 ISOgrk3 -->
+        initialMap.put("\u03A9", "&Omega;"); // greek capital letter omega,U+03A9 ISOgrk3 -->
+        initialMap.put("\u03B1", "&alpha;"); // greek small letter alpha,U+03B1 ISOgrk3 -->
+        initialMap.put("\u03B2", "&beta;"); // greek small letter beta, U+03B2 ISOgrk3 -->
+        initialMap.put("\u03B3", "&gamma;"); // greek small letter gamma,U+03B3 ISOgrk3 -->
+        initialMap.put("\u03B4", "&delta;"); // greek small letter delta,U+03B4 ISOgrk3 -->
+        initialMap.put("\u03B5", "&epsilon;"); // greek small letter epsilon,U+03B5 ISOgrk3 -->
+        initialMap.put("\u03B6", "&zeta;"); // greek small letter zeta, U+03B6 ISOgrk3 -->
+        initialMap.put("\u03B7", "&eta;"); // greek small letter eta, U+03B7 ISOgrk3 -->
+        initialMap.put("\u03B8", "&theta;"); // greek small letter theta,U+03B8 ISOgrk3 -->
+        initialMap.put("\u03B9", "&iota;"); // greek small letter iota, U+03B9 ISOgrk3 -->
+        initialMap.put("\u03BA", "&kappa;"); // greek small letter kappa,U+03BA ISOgrk3 -->
+        initialMap.put("\u03BB", "&lambda;"); // greek small letter lambda,U+03BB ISOgrk3 -->
+        initialMap.put("\u03BC", "&mu;"); // greek small letter mu, U+03BC ISOgrk3 -->
+        initialMap.put("\u03BD", "&nu;"); // greek small letter nu, U+03BD ISOgrk3 -->
+        initialMap.put("\u03BE", "&xi;"); // greek small letter xi, U+03BE ISOgrk3 -->
+        initialMap.put("\u03BF", "&omicron;"); // greek small letter omicron, U+03BF NEW -->
+        initialMap.put("\u03C0", "&pi;"); // greek small letter pi, U+03C0 ISOgrk3 -->
+        initialMap.put("\u03C1", "&rho;"); // greek small letter rho, U+03C1 ISOgrk3 -->
+        initialMap.put("\u03C2", "&sigmaf;"); // greek small letter final sigma,U+03C2 ISOgrk3 -->
+        initialMap.put("\u03C3", "&sigma;"); // greek small letter sigma,U+03C3 ISOgrk3 -->
+        initialMap.put("\u03C4", "&tau;"); // greek small letter tau, U+03C4 ISOgrk3 -->
+        initialMap.put("\u03C5", "&upsilon;"); // greek small letter upsilon,U+03C5 ISOgrk3 -->
+        initialMap.put("\u03C6", "&phi;"); // greek small letter phi, U+03C6 ISOgrk3 -->
+        initialMap.put("\u03C7", "&chi;"); // greek small letter chi, U+03C7 ISOgrk3 -->
+        initialMap.put("\u03C8", "&psi;"); // greek small letter psi, U+03C8 ISOgrk3 -->
+        initialMap.put("\u03C9", "&omega;"); // greek small letter omega,U+03C9 ISOgrk3 -->
+        initialMap.put("\u03D1", "&thetasym;"); // greek small letter theta symbol,U+03D1 NEW -->
+        initialMap.put("\u03D2", "&upsih;"); // greek upsilon with hook symbol,U+03D2 NEW -->
+        initialMap.put("\u03D6", "&piv;"); // greek pi symbol, U+03D6 ISOgrk3 -->
+        // <!-- General Punctuation -->
+        initialMap.put("\u2022", "&bull;"); // bullet = black small circle,U+2022 ISOpub -->
+        // <!-- bullet is NOT the same as bullet operator, U+2219 -->
+        initialMap.put("\u2026", "&hellip;"); // horizontal ellipsis = three dot leader,U+2026 ISOpub -->
+        initialMap.put("\u2032", "&prime;"); // prime = minutes = feet, U+2032 ISOtech -->
+        initialMap.put("\u2033", "&Prime;"); // double prime = seconds = inches,U+2033 ISOtech -->
+        initialMap.put("\u203E", "&oline;"); // overline = spacing overscore,U+203E NEW -->
+        initialMap.put("\u2044", "&frasl;"); // fraction slash, U+2044 NEW -->
+        // <!-- Letterlike Symbols -->
+        initialMap.put("\u2118", "&weierp;"); // script capital P = power set= Weierstrass p, U+2118 ISOamso -->
+        initialMap.put("\u2111", "&image;"); // blackletter capital I = imaginary part,U+2111 ISOamso -->
+        initialMap.put("\u211C", "&real;"); // blackletter capital R = real part symbol,U+211C ISOamso -->
+        initialMap.put("\u2122", "&trade;"); // trade mark sign, U+2122 ISOnum -->
+        initialMap.put("\u2135", "&alefsym;"); // alef symbol = first transfinite cardinal,U+2135 NEW -->
+        // <!-- alef symbol is NOT the same as hebrew letter alef,U+05D0 although the
+        // same glyph could be used to depict both characters -->
+        // <!-- Arrows -->
+        initialMap.put("\u2190", "&larr;"); // leftwards arrow, U+2190 ISOnum -->
+        initialMap.put("\u2191", "&uarr;"); // upwards arrow, U+2191 ISOnum-->
+        initialMap.put("\u2192", "&rarr;"); // rightwards arrow, U+2192 ISOnum -->
+        initialMap.put("\u2193", "&darr;"); // downwards arrow, U+2193 ISOnum -->
+        initialMap.put("\u2194", "&harr;"); // left right arrow, U+2194 ISOamsa -->
+        initialMap.put("\u21B5", "&crarr;"); // downwards arrow with corner leftwards= carriage return, U+21B5 NEW -->
+        initialMap.put("\u21D0", "&lArr;"); // leftwards double arrow, U+21D0 ISOtech -->
+        // <!-- ISO 10646 does not say that lArr is the same as the 'is implied by'
+        // arrow but also does not have any other character for that function.
+        // So ? lArr canbe used for 'is implied by' as ISOtech suggests -->
+        initialMap.put("\u21D1", "&uArr;"); // upwards double arrow, U+21D1 ISOamsa -->
+        initialMap.put("\u21D2", "&rArr;"); // rightwards double arrow,U+21D2 ISOtech -->
+        // <!-- ISO 10646 does not say this is the 'implies' character but does not
+        // have another character with this function so ?rArr can be used for
+        // 'implies' as ISOtech suggests -->
+        initialMap.put("\u21D3", "&dArr;"); // downwards double arrow, U+21D3 ISOamsa -->
+        initialMap.put("\u21D4", "&hArr;"); // left right double arrow,U+21D4 ISOamsa -->
+        // <!-- Mathematical Operators -->
+        initialMap.put("\u2200", "&forall;"); // for all, U+2200 ISOtech -->
+        initialMap.put("\u2202", "&part;"); // partial differential, U+2202 ISOtech -->
+        initialMap.put("\u2203", "&exist;"); // there exists, U+2203 ISOtech -->
+        initialMap.put("\u2205", "&empty;"); // empty set = null set = diameter,U+2205 ISOamso -->
+        initialMap.put("\u2207", "&nabla;"); // nabla = backward difference,U+2207 ISOtech -->
+        initialMap.put("\u2208", "&isin;"); // element of, U+2208 ISOtech -->
+        initialMap.put("\u2209", "&notin;"); // not an element of, U+2209 ISOtech -->
+        initialMap.put("\u220B", "&ni;"); // contains as member, U+220B ISOtech -->
+        // <!-- should there be a more memorable name than 'ni'? -->
+        initialMap.put("\u220F", "&prod;"); // n-ary product = product sign,U+220F ISOamsb -->
+        // <!-- prod is NOT the same character as U+03A0 'greek capital letter pi'
+        // though the same glyph might be used for both -->
+        initialMap.put("\u2211", "&sum;"); // n-ary summation, U+2211 ISOamsb -->
+        // <!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
+        // though the same glyph might be used for both -->
+        initialMap.put("\u2212", "&minus;"); // minus sign, U+2212 ISOtech -->
+        initialMap.put("\u2217", "&lowast;"); // asterisk operator, U+2217 ISOtech -->
+        initialMap.put("\u221A", "&radic;"); // square root = radical sign,U+221A ISOtech -->
+        initialMap.put("\u221D", "&prop;"); // proportional to, U+221D ISOtech -->
+        initialMap.put("\u221E", "&infin;"); // infinity, U+221E ISOtech -->
+        initialMap.put("\u2220", "&ang;"); // angle, U+2220 ISOamso -->
+        initialMap.put("\u2227", "&and;"); // logical and = wedge, U+2227 ISOtech -->
+        initialMap.put("\u2228", "&or;"); // logical or = vee, U+2228 ISOtech -->
+        initialMap.put("\u2229", "&cap;"); // intersection = cap, U+2229 ISOtech -->
+        initialMap.put("\u222A", "&cup;"); // union = cup, U+222A ISOtech -->
+        initialMap.put("\u222B", "&int;"); // integral, U+222B ISOtech -->
+        initialMap.put("\u2234", "&there4;"); // therefore, U+2234 ISOtech -->
+        initialMap.put("\u223C", "&sim;"); // tilde operator = varies with = similar to,U+223C ISOtech -->
+        // <!-- tilde operator is NOT the same character as the tilde, U+007E,although
+        // the same glyph might be used to represent both -->
+        initialMap.put("\u2245", "&cong;"); // approximately equal to, U+2245 ISOtech -->
+        initialMap.put("\u2248", "&asymp;"); // almost equal to = asymptotic to,U+2248 ISOamsr -->
+        initialMap.put("\u2260", "&ne;"); // not equal to, U+2260 ISOtech -->
+        initialMap.put("\u2261", "&equiv;"); // identical to, U+2261 ISOtech -->
+        initialMap.put("\u2264", "&le;"); // less-than or equal to, U+2264 ISOtech -->
+        initialMap.put("\u2265", "&ge;"); // greater-than or equal to,U+2265 ISOtech -->
+        initialMap.put("\u2282", "&sub;"); // subset of, U+2282 ISOtech -->
+        initialMap.put("\u2283", "&sup;"); // superset of, U+2283 ISOtech -->
+        // <!-- note that nsup, 'not a superset of, U+2283' is not covered by the
+        // Symbol font encoding and is not included. Should it be, for symmetry?
+        // It is in ISOamsn -->,
+        initialMap.put("\u2284", "&nsub;"); // not a subset of, U+2284 ISOamsn -->
+        initialMap.put("\u2286", "&sube;"); // subset of or equal to, U+2286 ISOtech -->
+        initialMap.put("\u2287", "&supe;"); // superset of or equal to,U+2287 ISOtech -->
+        initialMap.put("\u2295", "&oplus;"); // circled plus = direct sum,U+2295 ISOamsb -->
+        initialMap.put("\u2297", "&otimes;"); // circled times = vector product,U+2297 ISOamsb -->
+        initialMap.put("\u22A5", "&perp;"); // up tack = orthogonal to = perpendicular,U+22A5 ISOtech -->
+        initialMap.put("\u22C5", "&sdot;"); // dot operator, U+22C5 ISOamsb -->
+        // <!-- dot operator is NOT the same character as U+00B7 middle dot -->
+        // <!-- Miscellaneous Technical -->
+        initialMap.put("\u2308", "&lceil;"); // left ceiling = apl upstile,U+2308 ISOamsc -->
+        initialMap.put("\u2309", "&rceil;"); // right ceiling, U+2309 ISOamsc -->
+        initialMap.put("\u230A", "&lfloor;"); // left floor = apl downstile,U+230A ISOamsc -->
+        initialMap.put("\u230B", "&rfloor;"); // right floor, U+230B ISOamsc -->
+        initialMap.put("\u2329", "&lang;"); // left-pointing angle bracket = bra,U+2329 ISOtech -->
+        // <!-- lang is NOT the same character as U+003C 'less than' or U+2039 'single left-pointing angle quotation
+        // mark' -->
+        initialMap.put("\u232A", "&rang;"); // right-pointing angle bracket = ket,U+232A ISOtech -->
+        // <!-- rang is NOT the same character as U+003E 'greater than' or U+203A
+        // 'single right-pointing angle quotation mark' -->
+        // <!-- Geometric Shapes -->
+        initialMap.put("\u25CA", "&loz;"); // lozenge, U+25CA ISOpub -->
+        // <!-- Miscellaneous Symbols -->
+        initialMap.put("\u2660", "&spades;"); // black spade suit, U+2660 ISOpub -->
+        // <!-- black here seems to mean filled as opposed to hollow -->
+        initialMap.put("\u2663", "&clubs;"); // black club suit = shamrock,U+2663 ISOpub -->
+        initialMap.put("\u2665", "&hearts;"); // black heart suit = valentine,U+2665 ISOpub -->
+        initialMap.put("\u2666", "&diams;"); // black diamond suit, U+2666 ISOpub -->
+
+        // <!-- Latin Extended-A -->
+        initialMap.put("\u0152", "&OElig;"); // -- latin capital ligature OE,U+0152 ISOlat2 -->
+        initialMap.put("\u0153", "&oelig;"); // -- latin small ligature oe, U+0153 ISOlat2 -->
+        // <!-- ligature is a misnomer, this is a separate character in some languages -->
+        initialMap.put("\u0160", "&Scaron;"); // -- latin capital letter S with caron,U+0160 ISOlat2 -->
+        initialMap.put("\u0161", "&scaron;"); // -- latin small letter s with caron,U+0161 ISOlat2 -->
+        initialMap.put("\u0178", "&Yuml;"); // -- latin capital letter Y with diaeresis,U+0178 ISOlat2 -->
+        // <!-- Spacing Modifier Letters -->
+        initialMap.put("\u02C6", "&circ;"); // -- modifier letter circumflex accent,U+02C6 ISOpub -->
+        initialMap.put("\u02DC", "&tilde;"); // small tilde, U+02DC ISOdia -->
+        // <!-- General Punctuation -->
+        initialMap.put("\u2002", "&ensp;"); // en space, U+2002 ISOpub -->
+        initialMap.put("\u2003", "&emsp;"); // em space, U+2003 ISOpub -->
+        initialMap.put("\u2009", "&thinsp;"); // thin space, U+2009 ISOpub -->
+        initialMap.put("\u200C", "&zwnj;"); // zero width non-joiner,U+200C NEW RFC 2070 -->
+        initialMap.put("\u200D", "&zwj;"); // zero width joiner, U+200D NEW RFC 2070 -->
+        initialMap.put("\u200E", "&lrm;"); // left-to-right mark, U+200E NEW RFC 2070 -->
+        initialMap.put("\u200F", "&rlm;"); // right-to-left mark, U+200F NEW RFC 2070 -->
+        initialMap.put("\u2013", "&ndash;"); // en dash, U+2013 ISOpub -->
+        initialMap.put("\u2014", "&mdash;"); // em dash, U+2014 ISOpub -->
+        initialMap.put("\u2018", "&lsquo;"); // left single quotation mark,U+2018 ISOnum -->
+        initialMap.put("\u2019", "&rsquo;"); // right single quotation mark,U+2019 ISOnum -->
+        initialMap.put("\u201A", "&sbquo;"); // single low-9 quotation mark, U+201A NEW -->
+        initialMap.put("\u201C", "&ldquo;"); // left double quotation mark,U+201C ISOnum -->
+        initialMap.put("\u201D", "&rdquo;"); // right double quotation mark,U+201D ISOnum -->
+        initialMap.put("\u201E", "&bdquo;"); // double low-9 quotation mark, U+201E NEW -->
+        initialMap.put("\u2020", "&dagger;"); // dagger, U+2020 ISOpub -->
+        initialMap.put("\u2021", "&Dagger;"); // double dagger, U+2021 ISOpub -->
+        initialMap.put("\u2030", "&permil;"); // per mille sign, U+2030 ISOtech -->
+        initialMap.put("\u2039", "&lsaquo;"); // single left-pointing angle quotation mark,U+2039 ISO proposed -->
+        // <!-- lsaquo is proposed but not yet ISO standardized -->
+        initialMap.put("\u203A", "&rsaquo;"); // single right-pointing angle quotation mark,U+203A ISO proposed -->
+        // <!-- rsaquo is proposed but not yet ISO standardized -->
+        initialMap.put("\u20AC", "&euro;"); // -- euro sign, U+20AC NEW -->
+        HTML40_EXTENDED_ESCAPE = Collections.unmodifiableMap(initialMap);
+    }
+
+    /**
+     * Reverse of {@link #HTML40_EXTENDED_ESCAPE} for unescaping purposes.
+     */
+    public static final Map<CharSequence, CharSequence> HTML40_EXTENDED_UNESCAPE;
+    static {
+        HTML40_EXTENDED_UNESCAPE = Collections.unmodifiableMap(invert(HTML40_EXTENDED_ESCAPE));
+    }
+
+    /**
+     * A Map&lt;CharSequence, CharSequence&gt; to escape the basic XML and HTML
+     * character entities.
+     *
+     * Namely: {@code " & < >}
+     */
+    public static final Map<CharSequence, CharSequence> BASIC_ESCAPE;
+    static {
+        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
+        initialMap.put("\"", "&quot;"); // " - double-quote
+        initialMap.put("&", "&amp;");   // & - ampersand
+        initialMap.put("<", "&lt;");    // < - less-than
+        initialMap.put(">", "&gt;");    // > - greater-than
+        BASIC_ESCAPE = Collections.unmodifiableMap(initialMap);
+    }
+
+    /**
+     * Reverse of {@link #BASIC_ESCAPE} for unescaping purposes.
+     */
+    public static final Map<CharSequence, CharSequence> BASIC_UNESCAPE;
+    static {
+        BASIC_UNESCAPE = Collections.unmodifiableMap(invert(BASIC_ESCAPE));
+    }
+
+    /**
+     * A Map&lt;CharSequence, CharSequence&gt; to escape the apostrophe character to
+     * its XML character entity.
+     */
+    public static final Map<CharSequence, CharSequence> APOS_ESCAPE;
+    static {
+        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
+        initialMap.put("'","&apos;"); // XML apostrophe
+        APOS_ESCAPE = Collections.unmodifiableMap(initialMap);
+    }
+
+    /**
+     * Reverse of {@link #APOS_ESCAPE} for unescaping purposes.
+     */
+    public static final Map<CharSequence, CharSequence> APOS_UNESCAPE;
+    static {
+        APOS_UNESCAPE = Collections.unmodifiableMap(invert(APOS_ESCAPE));
+    }
+
+    /**
+     * A Map&lt;CharSequence, CharSequence&gt; to escape the Java
+     * control characters.
+     *
+     * Namely: {@code \b \n \t \f \r}
+     */
+    public static final Map<CharSequence, CharSequence> JAVA_CTRL_CHARS_ESCAPE;
+    static {
+        Map<CharSequence, CharSequence> initialMap = new HashMap<>();
+        initialMap.put("\b", "\\b");
+        initialMap.put("\n", "\\n");
+        initialMap.put("\t", "\\t");
+        initialMap.put("\f", "\\f");
+        initialMap.put("\r", "\\r");
+        JAVA_CTRL_CHARS_ESCAPE = Collections.unmodifiableMap(initialMap);
+    }
+
+    /**
+     * Reverse of {@link #JAVA_CTRL_CHARS_ESCAPE} for unescaping purposes.
+     */
+    public static final Map<CharSequence, CharSequence> JAVA_CTRL_CHARS_UNESCAPE;
+    static {
+        JAVA_CTRL_CHARS_UNESCAPE = Collections.unmodifiableMap(invert(JAVA_CTRL_CHARS_ESCAPE));
+    }
+
+    /**
+     * Used to invert an escape Map into an unescape Map
+     * @param map Map&lt;String, String&gt; to be inverted
+     * @return Map&lt;String, String&gt; inverted array
+     */
+    public static Map<CharSequence, CharSequence> invert(final Map<CharSequence, CharSequence> map) {
+        Map<CharSequence, CharSequence> newMap = new HashMap<>();
+        Iterator<Map.Entry<CharSequence, CharSequence>> it = map.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<CharSequence, CharSequence> pair = it.next();
+            newMap.put((CharSequence) pair.getValue(), (CharSequence) pair.getKey());
+        }
+        return newMap;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java b/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
new file mode 100644
index 0000000..22549fa
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/JavaUnicodeEscaper.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+/**
+ * Translates codepoints to their Unicode escaped value suitable for Java source.
+ *
+ * @since 1.0
+ */
+public class JavaUnicodeEscaper extends UnicodeEscaper {
+
+    /**
+     * <p>
+     * Constructs a <code>JavaUnicodeEscaper</code> above the specified value (exclusive).
+     * </p>
+     * 
+     * @param codepoint
+     *            above which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static JavaUnicodeEscaper above(final int codepoint) {
+        return outsideOf(0, codepoint);
+    }
+
+    /**
+     * <p>
+     * Constructs a <code>JavaUnicodeEscaper</code> below the specified value (exclusive).
+     * </p>
+     * 
+     * @param codepoint
+     *            below which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static JavaUnicodeEscaper below(final int codepoint) {
+        return outsideOf(codepoint, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>
+     * Constructs a <code>JavaUnicodeEscaper</code> between the specified values (inclusive).
+     * </p>
+     * 
+     * @param codepointLow
+     *            above which to escape
+     * @param codepointHigh
+     *            below which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static JavaUnicodeEscaper between(final int codepointLow, final int codepointHigh) {
+        return new JavaUnicodeEscaper(codepointLow, codepointHigh, true);
+    }
+
+    /**
+     * <p>
+     * Constructs a <code>JavaUnicodeEscaper</code> outside of the specified values (exclusive).
+     * </p>
+     * 
+     * @param codepointLow
+     *            below which to escape
+     * @param codepointHigh
+     *            above which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static JavaUnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) {
+        return new JavaUnicodeEscaper(codepointLow, codepointHigh, false);
+    }
+
+    /**
+     * <p>
+     * Constructs a <code>JavaUnicodeEscaper</code> for the specified range. This is the underlying method for the
+     * other constructors/builders. The <code>below</code> and <code>above</code> boundaries are inclusive when
+     * <code>between</code> is <code>true</code> and exclusive when it is <code>false</code>.
+     * </p>
+     * 
+     * @param below
+     *            int value representing the lowest codepoint boundary
+     * @param above
+     *            int value representing the highest codepoint boundary
+     * @param between
+     *            whether to escape between the boundaries or outside them
+     */
+    public JavaUnicodeEscaper(final int below, final int above, final boolean between) {
+        super(below, above, between);
+    }
+
+    /**
+     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX\\uXXXX"}
+     * 
+     * @param codepoint
+     *            a Unicode code point
+     * @return the hex string for the given codepoint
+     */
+    @Override
+    protected String toUtf16Escape(final int codepoint) {
+        final char[] surrogatePair = Character.toChars(codepoint);
+        return "\\u" + hex(surrogatePair[0]) + "\\u" + hex(surrogatePair[1]);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/LookupTranslator.java b/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
new file mode 100644
index 0000000..ab3a7f6
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/LookupTranslator.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.security.InvalidParameterException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Translates a value using a lookup table.
+ *
+ * @since 1.0
+ */
+public class LookupTranslator extends CharSequenceTranslator {
+
+    private final Map<String, String> lookupMap;
+    private final HashSet<Character> prefixSet;
+    private final int shortest;
+    private final int longest;
+
+    /**
+     * Define the lookup table to be used in translation
+     *
+     * Note that, as of Lang 3.1 (the orgin of this code), the key to the lookup
+     * table is converted to a java.lang.String. This is because we need the key
+     * to support hashCode and equals(Object), allowing it to be the key for a
+     * HashMap. See LANG-882.
+     *
+     * @param lookupMap Map&lt;CharSequence, CharSequence&gt; table of translator
+     *                  mappings
+     */
+    public LookupTranslator(final Map<CharSequence, CharSequence> lookupMap) {
+        if (lookupMap == null) {
+            throw new InvalidParameterException("lookupMap cannot be null");
+        }
+        this.lookupMap = new HashMap<>();
+        prefixSet = new HashSet<>();
+        int _shortest = Integer.MAX_VALUE;
+        int _longest = 0;
+        Iterator<Map.Entry<CharSequence, CharSequence>> it = lookupMap.entrySet().iterator();
+
+        while (it.hasNext()) {
+            Map.Entry<CharSequence, CharSequence> pair = it.next();
+            this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
+            this.prefixSet.add((pair.getKey()).charAt(0));
+            final int sz = pair.getKey().length();
+            if (sz < _shortest) {
+                _shortest = sz;
+            }
+            if (sz > _longest) {
+                _longest = sz;
+            }
+        }
+        shortest = _shortest;
+        longest = _longest;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        // check if translation exists for the input at position index
+        if (prefixSet.contains(input.charAt(index))) {
+            int max = longest;
+            if (index + longest > input.length()) {
+                max = input.length() - index;
+            }
+            // implement greedy algorithm by trying maximum match first
+            for (int i = max; i >= shortest; i--) {
+                final CharSequence subSeq = input.subSequence(index, index + i);
+                final String result = lookupMap.get(subSeq.toString());
+
+                if (result != null) {
+                    out.write(result);
+                    return i;
+                }
+            }
+        }
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
new file mode 100644
index 0000000..a852964
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityEscaper.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Translates codepoints to their XML numeric entity escaped value.
+ *
+ * @since 1.0
+ */
+public class NumericEntityEscaper extends CodePointTranslator {
+
+    private final int below;
+    private final int above;
+    private final boolean between;
+
+    /**
+     * <p>Constructs a <code>NumericEntityEscaper</code> for the specified range. This is
+     * the underlying method for the other constructors/builders. The <code>below</code>
+     * and <code>above</code> boundaries are inclusive when <code>between</code> is
+     * <code>true</code> and exclusive when it is <code>false</code>. </p>
+     *
+     * @param below int value representing the lowest codepoint boundary
+     * @param above int value representing the highest codepoint boundary
+     * @param between whether to escape between the boundaries or outside them
+     */
+    private NumericEntityEscaper(final int below, final int above, final boolean between) {
+        this.below = below;
+        this.above = above;
+        this.between = between;
+    }
+
+    /**
+     * <p>Constructs a <code>NumericEntityEscaper</code> for all characters. </p>
+     */
+    public NumericEntityEscaper() {
+        this(0, Integer.MAX_VALUE, true);
+    }
+
+    /**
+     * <p>Constructs a <code>NumericEntityEscaper</code> below the specified value (exclusive). </p>
+     *
+     * @param codepoint below which to escape
+     * @return the newly created {@code NumericEntityEscaper} instance
+     */
+    public static NumericEntityEscaper below(final int codepoint) {
+        return outsideOf(codepoint, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Constructs a <code>NumericEntityEscaper</code> above the specified value (exclusive). </p>
+     *
+     * @param codepoint above which to escape
+     * @return the newly created {@code NumericEntityEscaper} instance
+     */
+    public static NumericEntityEscaper above(final int codepoint) {
+        return outsideOf(0, codepoint);
+    }
+
+    /**
+     * <p>Constructs a <code>NumericEntityEscaper</code> between the specified values (inclusive). </p>
+     *
+     * @param codepointLow above which to escape
+     * @param codepointHigh below which to escape
+     * @return the newly created {@code NumericEntityEscaper} instance
+     */
+    public static NumericEntityEscaper between(final int codepointLow, final int codepointHigh) {
+        return new NumericEntityEscaper(codepointLow, codepointHigh, true);
+    }
+
+    /**
+     * <p>Constructs a <code>NumericEntityEscaper</code> outside of the specified values (exclusive). </p>
+     *
+     * @param codepointLow below which to escape
+     * @param codepointHigh above which to escape
+     * @return the newly created {@code NumericEntityEscaper} instance
+     */
+    public static NumericEntityEscaper outsideOf(final int codepointLow, final int codepointHigh) {
+        return new NumericEntityEscaper(codepointLow, codepointHigh, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean translate(final int codepoint, final Writer out) throws IOException {
+        if(between) {
+            if (codepoint < below || codepoint > above) {
+                return false;
+            }
+        } else {
+            if (codepoint >= below && codepoint <= above) {
+                return false;
+            }
+        }
+
+        out.write("&#");
+        out.write(Integer.toString(codepoint, 10));
+        out.write(';');
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
new file mode 100644
index 0000000..8b3d7c7
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/NumericEntityUnescaper.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.EnumSet;
+
+/**
+ * Translate XML numeric entities of the form &amp;#[xX]?\d+;? to 
+ * the specific codepoint.
+ *
+ * Note that the semi-colon is optional.
+ *
+ * @since 1.0
+ */
+public class NumericEntityUnescaper extends CharSequenceTranslator {
+
+    public static enum OPTION { semiColonRequired, semiColonOptional, errorIfNoSemiColon }
+
+    // TODO?: Create an OptionsSet class to hide some of the conditional logic below
+    private final EnumSet<OPTION> options;
+
+    /**
+     * Create a UnicodeUnescaper.
+     *
+     * The constructor takes a list of options, only one type of which is currently 
+     * available (whether to allow, error or ignore the semi-colon on the end of a 
+     * numeric entity to being missing).
+     *
+     * For example, to support numeric entities without a ';':
+     *    new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional)
+     * and to throw an IllegalArgumentException when they're missing:
+     *    new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon)
+     *
+     * Note that the default behaviour is to ignore them. 
+     *
+     * @param options to apply to this unescaper
+     */
+    public NumericEntityUnescaper(final OPTION... options) {
+        if(options.length > 0) {
+            this.options = EnumSet.copyOf(Arrays.asList(options));
+        } else {
+            this.options = EnumSet.copyOf(Arrays.asList(new OPTION[] { OPTION.semiColonRequired }));
+        }
+    }
+
+    /**
+     * Whether the passed in option is currently set.
+     *
+     * @param option to check state of
+     * @return whether the option is set
+     */
+    public boolean isSet(final OPTION option) { 
+        return options == null ? false : options.contains(option);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        final int seqEnd = input.length();
+        // Uses -2 to ensure there is something after the &#
+        if(input.charAt(index) == '&' && index < seqEnd - 2 && input.charAt(index + 1) == '#') {
+            int start = index + 2;
+            boolean isHex = false;
+
+            final char firstChar = input.charAt(start);
+            if(firstChar == 'x' || firstChar == 'X') {
+                start++;
+                isHex = true;
+
+                // Check there's more than just an x after the &#
+                if(start == seqEnd) {
+                    return 0;
+                }
+            }
+
+            int end = start;
+            // Note that this supports character codes without a ; on the end
+            while(end < seqEnd && ( input.charAt(end) >= '0' && input.charAt(end) <= '9' ||
+                                    input.charAt(end) >= 'a' && input.charAt(end) <= 'f' ||
+                                    input.charAt(end) >= 'A' && input.charAt(end) <= 'F' ) )
+            {
+                end++;
+            }
+
+            final boolean semiNext = end != seqEnd && input.charAt(end) == ';';
+
+            if(!semiNext) {
+                if(isSet(OPTION.semiColonRequired)) {
+                    return 0;
+                } else
+                if(isSet(OPTION.errorIfNoSemiColon)) {
+                    throw new IllegalArgumentException("Semi-colon required at end of numeric entity");
+                }
+            }
+
+            int entityValue;
+            try {
+                if(isHex) {
+                    entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 16);
+                } else {
+                    entityValue = Integer.parseInt(input.subSequence(start, end).toString(), 10);
+                }
+            } catch(final NumberFormatException nfe) {
+                return 0;
+            }
+
+            if(entityValue > 0xFFFF) {
+                final char[] chrs = Character.toChars(entityValue);
+                out.write(chrs[0]);
+                out.write(chrs[1]);
+            } else {
+                out.write(entityValue);
+            }
+
+            return 2 + end - start + (isHex ? 1 : 0) + (semiNext ? 1 : 0);
+        }
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java b/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
new file mode 100644
index 0000000..e49cdd5
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/OctalUnescaper.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Translate escaped octal Strings back to their octal values.
+ *
+ * For example, "\45" should go back to being the specific value (a %).
+ *
+ * Note that this currently only supports the viable range of octal for Java; namely 
+ * 1 to 377. This is because parsing Java is the main use case.
+ *
+ * @since 1.0
+ */
+public class OctalUnescaper extends CharSequenceTranslator {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        final int remaining = input.length() - index - 1; // how many characters left, ignoring the first \
+        final StringBuilder builder = new StringBuilder();
+        if(input.charAt(index) == '\\' && remaining > 0 && isOctalDigit(input.charAt(index + 1)) ) {
+            final int next = index + 1;
+            final int next2 = index + 2;
+            final int next3 = index + 3;
+
+            // we know this is good as we checked it in the if block above
+            builder.append(input.charAt(next));
+
+            if(remaining > 1 && isOctalDigit(input.charAt(next2))) {
+                builder.append(input.charAt(next2));
+                if(remaining > 2 && isZeroToThree(input.charAt(next)) && isOctalDigit(input.charAt(next3))) {
+                    builder.append(input.charAt(next3));
+                }
+            }
+
+            out.write( Integer.parseInt(builder.toString(), 8) );
+            return 1 + builder.length();
+        }
+        return 0;
+    }
+
+    /**
+     * Checks if the given char is an octal digit. Octal digits are the character representations of the digits 0 to 7.
+     * @param ch the char to check
+     * @return true if the given char is the character representation of one of the digits from 0 to 7
+     */
+    private boolean isOctalDigit(final char ch) {
+        return ch >= '0' && ch <= '7';
+    }
+
+    /**
+     * Checks if the given char is the character representation of one of the digit from 0 to 3.
+     * @param ch the char to check
+     * @return true if the given char is the character representation of one of the digits from 0 to 3
+     */
+    private boolean isZeroToThree(final char ch) {
+        return ch >= '0' && ch <= '3';
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java b/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
new file mode 100644
index 0000000..7af0579
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/SingleLookupTranslator.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Translates a value using a lookup table.
+ * But doesn't translate if that value is already translated.
+ *
+ * @since 1.0
+ */
+public class SingleLookupTranslator extends CharSequenceTranslator {
+
+    private final Map<String, String> lookupMap;
+    private final HashSet<Character> prefixSet;
+    private final int shortest;
+    private final int longest;
+    private final int shortestValue;
+    private final int longestValue;
+
+    /**
+     * Define the look tables to be used in translation.
+     * <p>
+     * Note that, as of Lang 3.1, the key to the lookup table is converted to a
+     * java.lang.String. This is because we need the key to support hashCode and
+     * equals(Object), allowing it to be the key for a HashMap. See LANG-882.
+     * <p>
+     * Also note that, multiple lookup tables should be passed to this translator
+     * instead of passing multiple instances of this translator to the
+     * AggregateTranslator. Because, this translator only checks the values of the
+     * lookup table passed to this instance while deciding whether a value is
+     * already translated or not.
+     *
+     * @param inputMaps, an array of Map&lt;CharSequence, CharSequence&gt;.
+     */
+    public SingleLookupTranslator(Map<CharSequence, CharSequence>... inputMaps) {
+        Map<CharSequence, CharSequence> lookup = new HashMap<>();
+        for (Map<CharSequence, CharSequence> input : inputMaps) {
+            Iterator<Map.Entry<CharSequence, CharSequence>> it = input.entrySet().iterator();
+            while (it.hasNext()) {
+                Map.Entry<CharSequence, CharSequence> pair = it.next();
+                lookup.put(pair.getKey(), pair.getValue());
+            }
+        }
+        lookupMap = new HashMap<String, String>();
+        prefixSet = new HashSet<Character>();
+        int _shortest = Integer.MAX_VALUE;
+        int _longest = 0;
+        int _shortestValue = Integer.MAX_VALUE;
+        int _longestValue = 0;
+        if (lookup != null) {
+            Iterator<Map.Entry<CharSequence, CharSequence>> it = lookup.entrySet().iterator();
+            while (it.hasNext()) {
+                Map.Entry<CharSequence, CharSequence> pair = it.next();
+                this.lookupMap.put(pair.getKey().toString(), pair.getValue().toString());
+                this.prefixSet.add(pair.getKey().charAt(0));
+                final int sz = pair.getKey().length();
+                if (sz < _shortest) {
+                    _shortest = sz;
+                }
+                if (sz > _longest) {
+                    _longest = sz;
+                }
+                final int sizeOfValue = lookup.get(pair.getKey()).length();
+                if (sizeOfValue < _shortestValue) {
+                    _shortestValue = sizeOfValue;
+                }
+                if (sizeOfValue > _longestValue) {
+                    _longestValue = sizeOfValue;
+                }
+            }
+        }
+        shortest = _shortest;
+        longest = _longest;
+        shortestValue = _shortestValue;
+        longestValue = _longestValue;
+    }
+
+    /**
+     * Translate a set of codepoints, represented by an int index into a CharSequence,
+     * into another set of codepoints. The number of codepoints consumed must be returned,
+     * and the only IOExceptions thrown must be from interacting with the Writer so that
+     * the top level API may reliably ignore StringWriter IOExceptions.
+     *
+     * @param input CharSequence that is being translated
+     * @param index int representing the current point of translation
+     * @param out   Writer to translate the text to
+     * @return int count of codepoints consumed
+     * @throws IOException if and only if the Writer produces an IOException
+     */
+    @Override
+    public int translate(CharSequence input, int index, Writer out) throws IOException {
+        // check if already translated
+        int maxValue = longestValue;
+        if (index + maxValue > input.length()) {
+            maxValue = input.length() - index;
+        }
+        // implement greedy algorithm to check all the possible 'value' matches
+        // for which we need to skip translation.
+        for (int i = maxValue; i >= shortestValue; i--) {
+            final CharSequence subSeq = input.subSequence(index, index + i);
+            // If the sub-string is already translated, return without translating.
+            if (lookupMap.containsValue(subSeq.toString())) {
+                return 0;
+            }
+        }
+
+        // check if translation exists for the input at position index
+        if (prefixSet.contains(input.charAt(index))) {
+            int max = longest;
+            if (index + longest > input.length()) {
+                max = input.length() - index;
+            }
+            // implement greedy algorithm by trying maximum match first
+            for (int i = max; i >= shortest; i--) {
+                final CharSequence subSeq = input.subSequence(index, index + i);
+                final String result = lookupMap.get(subSeq.toString());
+
+                if (result != null) {
+                    out.write(result);
+                    return i;
+                }
+            }
+        }
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java b/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
new file mode 100644
index 0000000..721e727
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/SinglePassTranslator.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Abstract translator for processing whole input in single pass.
+ * Handles initial index checking and counting of returned code points.
+ */
+abstract class SinglePassTranslator extends CharSequenceTranslator {
+
+    @Override
+    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        if (index != 0) {
+            throw new IllegalArgumentException(getClassName() + ".translate(final CharSequence input, final int " +
+                    "index, final Writer out) can not handle a non-zero index.");
+        }
+
+        translateWhole(input, out);
+
+        return Character.codePointCount(input, index, input.length());
+    }
+
+    private String getClassName() {
+        final Class<? extends SinglePassTranslator> clazz = this.getClass();
+        return clazz.isAnonymousClass() ?  clazz.getName() : clazz.getSimpleName();
+    }
+
+    /**
+     * Translate whole set of code points passed in input.
+     *
+     * @param input CharSequence that is being translated
+     * @param out Writer to translate the text to
+     * @return total count of codepoints in input
+     * @throws IOException if and only if the Writer produces an IOException
+     */
+    abstract void translateWhole(final CharSequence input, final Writer out) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java b/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
new file mode 100644
index 0000000..04b24e2
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeEscaper.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Translates codepoints to their Unicode escaped value.
+ *
+ * @since 1.0
+ */
+public class UnicodeEscaper extends CodePointTranslator {
+
+    private final int below;
+    private final int above;
+    private final boolean between;
+
+    /**
+     * <p>Constructs a <code>UnicodeEscaper</code> for all characters. </p>
+     */
+    public UnicodeEscaper(){
+        this(0, Integer.MAX_VALUE, true);
+    }
+
+    /**
+     * <p>Constructs a <code>UnicodeEscaper</code> for the specified range. This is
+     * the underlying method for the other constructors/builders. The <code>below</code>
+     * and <code>above</code> boundaries are inclusive when <code>between</code> is
+     * <code>true</code> and exclusive when it is <code>false</code>. </p>
+     *
+     * @param below int value representing the lowest codepoint boundary
+     * @param above int value representing the highest codepoint boundary
+     * @param between whether to escape between the boundaries or outside them
+     */
+    protected UnicodeEscaper(final int below, final int above, final boolean between) {
+        this.below = below;
+        this.above = above;
+        this.between = between;
+    }
+
+    /**
+     * <p>Constructs a <code>UnicodeEscaper</code> below the specified value (exclusive). </p>
+     *
+     * @param codepoint below which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static UnicodeEscaper below(final int codepoint) {
+        return outsideOf(codepoint, Integer.MAX_VALUE);
+    }
+
+    /**
+     * <p>Constructs a <code>UnicodeEscaper</code> above the specified value (exclusive). </p>
+     *
+     * @param codepoint above which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static UnicodeEscaper above(final int codepoint) {
+        return outsideOf(0, codepoint);
+    }
+
+    /**
+     * <p>Constructs a <code>UnicodeEscaper</code> outside of the specified values (exclusive). </p>
+     *
+     * @param codepointLow below which to escape
+     * @param codepointHigh above which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static UnicodeEscaper outsideOf(final int codepointLow, final int codepointHigh) {
+        return new UnicodeEscaper(codepointLow, codepointHigh, false);
+    }
+
+    /**
+     * <p>Constructs a <code>UnicodeEscaper</code> between the specified values (inclusive). </p>
+     *
+     * @param codepointLow above which to escape
+     * @param codepointHigh below which to escape
+     * @return the newly created {@code UnicodeEscaper} instance
+     */
+    public static UnicodeEscaper between(final int codepointLow, final int codepointHigh) {
+        return new UnicodeEscaper(codepointLow, codepointHigh, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean translate(final int codepoint, final Writer out) throws IOException {
+        if (between) {
+            if (codepoint < below || codepoint > above) {
+                return false;
+            }
+        } else {
+            if (codepoint >= below && codepoint <= above) {
+                return false;
+            }
+        }
+
+        // TODO: Handle potential + sign per various Unicode escape implementations
+        if (codepoint > 0xffff) {
+            out.write(toUtf16Escape(codepoint));
+        } else {
+          out.write("\\u");
+          out.write(HEX_DIGITS[(codepoint >> 12) & 15]);
+          out.write(HEX_DIGITS[(codepoint >> 8) & 15]);
+          out.write(HEX_DIGITS[(codepoint >> 4) & 15]);
+          out.write(HEX_DIGITS[(codepoint) & 15]);
+        }
+        return true;
+    }
+
+    /**
+     * Converts the given codepoint to a hex string of the form {@code "\\uXXXX"}
+     * 
+     * @param codepoint
+     *            a Unicode code point
+     * @return the hex string for the given codepoint
+     *
+     */
+    protected String toUtf16Escape(final int codepoint) {
+        return "\\u" + hex(codepoint);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java b/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
new file mode 100644
index 0000000..3a91d6c
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeUnescaper.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Translates escaped Unicode values of the form \\u+\d\d\d\d back to 
+ * Unicode. It supports multiple 'u' characters and will work with or 
+ * without the +.
+ *
+ * @since 1.0
+ */
+public class UnicodeUnescaper extends CharSequenceTranslator {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
+        if (input.charAt(index) == '\\' && index + 1 < input.length() && input.charAt(index + 1) == 'u') {
+            // consume optional additional 'u' chars
+            int i = 2;
+            while (index + i < input.length() && input.charAt(index + i) == 'u') {
+                i++;
+            }
+
+            if (index + i < input.length() && input.charAt(index + i) == '+') {
+                i++;
+            }
+
+            if (index + i + 4 <= input.length()) {
+                // Get 4 hex digits
+                final CharSequence unicode = input.subSequence(index + i, index + i + 4);
+
+                try {
+                    final int value = Integer.parseInt(unicode.toString(), 16);
+                    out.write((char) value);
+                } catch (final NumberFormatException nfe) {
+                    throw new IllegalArgumentException("Unable to parse unicode value: " + unicode, nfe);
+                }
+                return i + 4;
+            }
+            throw new IllegalArgumentException("Less than 4 hex digits in unicode value: '" + input.subSequence(index, input.length())
+                    + "' due to end of CharSequence");
+        }
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java b/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
new file mode 100644
index 0000000..ca90b89
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemover.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Helper subclass to CharSequenceTranslator to remove unpaired surrogates.
+ *
+ * @since 1.0
+ */
+public class UnicodeUnpairedSurrogateRemover extends CodePointTranslator {
+    /**
+     * Implementation of translate that throws out unpaired surrogates. 
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean translate(final int codepoint, final Writer out) throws IOException {
+        if (codepoint >= Character.MIN_SURROGATE && codepoint <= Character.MAX_SURROGATE) {
+            // It's a surrogate. Write nothing and say we've translated.
+            return true;
+        }
+        // It's not a surrogate. Don't translate it.
+        return false;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/translate/package-info.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/translate/package-info.java b/src/main/java/org/apache/commons/text/translate/package-info.java
new file mode 100644
index 0000000..5ccb000
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/translate/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * <p> An API for creating text translation routines from a set of smaller building blocks. Initially created to make it
+ * possible for the user to customize the rules in the StringEscapeUtils class.</p>
+ * <p>These classes are immutable, and therefore thread-safe.</p>
+ *
+ * @since 1.0
+ */
+package org.apache.commons.text.translate;

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/AlphabetConverterTest.java b/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
new file mode 100644
index 0000000..d235c0e
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+/**
+ * Unit tests for {@link AlphabetConverter}.
+ */
+public class AlphabetConverterTest {
+
+    private static Character[] lower_case_english = {' ','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
+    private static Character[] english_and_numbers = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',' ' };
+    private static Character[] lower_case_english_and_numbers = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',' ' };
+    private static Character[] numbers = {'0','1','2','3','4','5','6','7','8','9'};
+    private static Character[] binary = {'0','1'};
+    private static Character[] hebrew = {'_', ' ', '\u05e7','\u05e8','\u05d0','\u05d8','\u05d5','\u05df','\u05dd','\u05e4','\u05e9','\u05d3','\u05d2','\u05db','\u05e2','\u05d9','\u05d7','\u05dc','\u05da','\u05e3','\u05d6','\u05e1','\u05d1','\u05d4','\u05e0','\u05de','\u05e6','\u05ea','\u05e5'};
+    private static Character[] empty = {};
+
+    private static Integer[] unicode = {32,35395,35397,36302,36291,35203,35201,35215,35219,35268,97,98,99,100,101,102,103,104,105,106,107,108,109,110,1001,1002,1003,1004,1005};
+    private static Integer[] lower_case_english_codepoints = {32,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};
+    private static Integer[] doNotEncodePoints = {32,97,98,99}; // space, a, b, c
+    
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+    
+    @Test
+    public void encodeFailureTest() throws UnsupportedEncodingException {
+        thrown.expect(UnsupportedEncodingException.class);
+        thrown.expectMessage("Couldn't find encoding for '3'");
+        test(binary, numbers, empty, "3");
+    }
+
+    @Test
+    public void binaryTest() throws UnsupportedEncodingException {
+        test(binary, numbers, empty, "0", "1", "10", "11");
+        test(numbers, binary, empty, "12345", "0");
+        test(lower_case_english, binary, empty, "abc", "a");
+    }
+
+    @Test
+    public void hebrewTest() throws UnsupportedEncodingException {
+        test(hebrew, binary, empty, "\u05d0", "\u05e2", "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
+        test(hebrew, numbers, empty, "\u05d0", "\u05e2", "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
+        test(numbers, hebrew, empty, "123456789", "1", "5");
+        test(lower_case_english, hebrew, empty, "this is a test");
+    }
+
+    @Test
+    public void doNotEncodeTest() throws UnsupportedEncodingException {
+        test(english_and_numbers, lower_case_english_and_numbers, lower_case_english, "1", "456", "abc", "ABC", "this will not be converted but THIS WILL");
+        test(english_and_numbers, lower_case_english_and_numbers, numbers, "1", "456", "abc", "ABC", "this will be converted but 12345 and this will be");
+    }
+
+    private AlphabetConverter createJavadocExample() {
+        final Character[] original = {'a','b','c','d'};
+        final Character[] encoding = {'0','1','d'};
+        final Character[] doNotEncode = {'d'};
+        
+        return AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode);
+    }
+    
+    /*
+     * Test example in javadocs for consistency
+     */
+    @Test
+    public void javadocExampleTest() throws UnsupportedEncodingException {
+        final AlphabetConverter ac = createJavadocExample();
+        
+        Assert.assertEquals("00", ac.encode("a"));
+        Assert.assertEquals("01", ac.encode("b"));
+        Assert.assertEquals("0d", ac.encode("c"));
+        Assert.assertEquals("d", ac.encode("d"));
+        Assert.assertEquals("00010dd", ac.encode("abcd"));
+    }
+
+    @Test
+    public void unexpectedEndwhileDecodingTest() throws UnsupportedEncodingException {
+        final String toDecode = "00d01d0";
+        
+        thrown.expect(UnsupportedEncodingException.class);
+        thrown.expectMessage("Unexpected end of string while decoding " + toDecode);
+
+        final AlphabetConverter ac = createJavadocExample();
+        ac.decode(toDecode);
+    }
+
+    @Test
+    public void unexpectedStringWhileDecodingTest() throws UnsupportedEncodingException {
+        final String toDecode = "00XX";
+        
+        thrown.expect(UnsupportedEncodingException.class);
+        thrown.expectMessage("Unexpected string without decoding (XX) in " + toDecode);
+
+        final AlphabetConverter ac = createJavadocExample();
+        ac.decode(toDecode);
+    }
+
+    /*
+     * Test constructor from code points
+     */
+    @Test
+    public void unicodeTest() throws UnsupportedEncodingException {
+        final AlphabetConverter ac = AlphabetConverter.createConverter(unicode, lower_case_english_codepoints, doNotEncodePoints);
+        
+        Assert.assertEquals(2, ac.getEncodedCharLength());
+        
+        final String original = "\u8a43\u8a45 \u8dce ab \u8dc3 c \u8983";
+        final String encoded = ac.encode(original);
+        final String decoded = ac.decode(encoded);
+        
+        Assert.assertEquals("Encoded '" + original + "' into '" + encoded + "', but decoded into '" + decoded + "'", original, decoded);
+    }
+
+    @Test
+    public void noEncodingLettersTest() {
+        thrown.expect(IllegalArgumentException.class);
+        thrown.expectMessage("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 0");
+
+        AlphabetConverter.createConverterFromChars(english_and_numbers, numbers, numbers);
+    }
+
+    @Test
+    public void onlyOneEncodingLettersTest() {
+        thrown.expect(IllegalArgumentException.class);
+        thrown.expectMessage("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 1");
+
+        final Character[] numbersPlusUnderscore = Arrays.copyOf(numbers, numbers.length + 1);
+        numbersPlusUnderscore[numbersPlusUnderscore.length -1] = '_';
+
+        AlphabetConverter.createConverterFromChars(english_and_numbers, numbersPlusUnderscore, numbers);
+    }
+
+    @Test
+    public void missingDoNotEncodeLettersFromEncodingTest() {
+        thrown.expect(IllegalArgumentException.class);
+        thrown.expectMessage("Can not use 'do not encode' list because encoding alphabet does not contain");
+
+        AlphabetConverter.createConverterFromChars(english_and_numbers, lower_case_english, numbers);
+    }
+
+    @Test
+    public void missingDoNotEncodeLettersFromOriginalTest() {
+        thrown.expect(IllegalArgumentException.class);
+        thrown.expectMessage("Can not use 'do not encode' list because original alphabet does not contain");
+
+        AlphabetConverter.createConverterFromChars(lower_case_english, english_and_numbers, numbers);
+    }
+
+    private void test(final Character[] originalChars, final Character[] encodingChars, final Character[] doNotEncodeChars, final String... strings) throws UnsupportedEncodingException {
+        
+        final AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originalChars, encodingChars, doNotEncodeChars);
+        
+        final AlphabetConverter reconstructedAlphabetConverter = AlphabetConverter.createConverterFromMap(ac.getOriginalToEncoded());
+        
+        Assert.assertEquals(ac, reconstructedAlphabetConverter);
+        Assert.assertEquals(ac.hashCode(), reconstructedAlphabetConverter.hashCode());
+        Assert.assertEquals(ac.toString(), reconstructedAlphabetConverter.toString());
+        Assert.assertEquals(null, ac.encode(null)); // test null conversions
+        Assert.assertEquals("", ac.encode("")); // test empty conversion
+
+        // test all the trial strings
+        for (final String s : strings) {
+            final String encoded = ac.encode(s);
+
+            // test that only encoding chars are used
+            final List<Character> originalEncodingChars = Arrays.asList(encodingChars);
+            for (int i = 0; i < encoded.length(); i++) {
+                Assert.assertTrue(originalEncodingChars.contains(encoded.charAt(i)));
+            }
+
+            final String decoded = ac.decode(encoded);
+
+            // test that only the original alphabet is used after decoding
+            final List<Character> originalCharsList = Arrays.asList(originalChars);
+            for (int i = 0; i < decoded.length(); i++) {
+                Assert.assertTrue(originalCharsList.contains(decoded.charAt(i)));
+            }
+            
+            Assert.assertEquals("Encoded '" + s + "' into '" + encoded + "', but decoded into '" + decoded + "'", s, decoded);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
new file mode 100644
index 0000000..a22b466
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests for {@link CharacterPredicates}.
+ */
+public class CharacterPredicatesTest {
+
+    @Test
+    public void testLetters() throws Exception {
+        assertTrue(CharacterPredicates.LETTERS.test('a'));
+        assertTrue(CharacterPredicates.LETTERS.test('Z'));
+
+        assertFalse(CharacterPredicates.LETTERS.test('1'));
+        assertFalse(CharacterPredicates.LETTERS.test('?'));
+        assertFalse(CharacterPredicates.LETTERS.test('@'));
+    }
+
+    @Test
+    public void testDigits() {
+        assertTrue(CharacterPredicates.DIGITS.test('0'));
+        assertTrue(CharacterPredicates.DIGITS.test('9'));
+
+        assertFalse(CharacterPredicates.DIGITS.test('-'));
+        assertFalse(CharacterPredicates.DIGITS.test('.'));
+        assertFalse(CharacterPredicates.DIGITS.test('L'));
+    }
+}
\ No newline at end of file


[05/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java
new file mode 100644
index 0000000..8019599
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link LongestCommonSubsequence}.
+ */
+public class LongestCommonSubsequenceTest {
+
+    private static LongestCommonSubsequence subject;
+
+    @BeforeClass
+    public static void setup() {
+        subject = new LongestCommonSubsequence();
+    }
+
+    @Test
+    public void testLongestCommonSubsequenceApply() {
+        assertEquals(Integer.valueOf(0), subject.apply("", ""));
+        assertEquals(Integer.valueOf(0), subject.apply("left", ""));
+        assertEquals(Integer.valueOf(0), subject.apply("", "right"));
+        assertEquals(Integer.valueOf(3), subject.apply("frog", "fog"));
+        assertEquals(Integer.valueOf(0), subject.apply("fly", "ant"));
+        assertEquals(Integer.valueOf(1), subject.apply("elephant", "hippo"));
+        assertEquals(Integer.valueOf(8), subject.apply("ABC Corporation", "ABC Corp"));
+        assertEquals(Integer.valueOf(20), subject.apply("D N H Enterprises Inc", "D & H Enterprises, Inc."));
+        assertEquals(Integer.valueOf(24), subject.apply("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"));
+        assertEquals(Integer.valueOf(11), subject.apply("PENNSYLVANIA", "PENNCISYLVNIA"));
+        assertEquals(Integer.valueOf(1), subject.apply("left", "right"));
+        assertEquals(Integer.valueOf(4), subject.apply("leettteft", "ritttght"));
+        assertEquals(Integer.valueOf(15), subject.apply("the same string", "the same string"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceApplyNullNull() throws Exception {
+        subject.apply(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceApplyStringNull() throws Exception {
+        subject.apply(" ", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceApplyNullString() throws Exception {
+        subject.apply(null, "right");
+    }
+
+    @Test
+    public void testLongestCommonSubsequence() {
+        assertEquals("", subject.logestCommonSubsequence("", ""));
+        assertEquals("", subject.logestCommonSubsequence("left", ""));
+        assertEquals("", subject.logestCommonSubsequence("", "right"));
+        assertEquals("fog", subject.logestCommonSubsequence("frog", "fog"));
+        assertEquals("", subject.logestCommonSubsequence("fly", "ant"));
+        assertEquals("h", subject.logestCommonSubsequence("elephant", "hippo"));
+        assertEquals("ABC Corp", subject.logestCommonSubsequence("ABC Corporation", "ABC Corp"));
+        assertEquals("D  H Enterprises Inc", subject.logestCommonSubsequence("D N H Enterprises Inc", "D & H Enterprises, Inc."));
+        assertEquals("My Gym Childrens Fitness", subject.logestCommonSubsequence("My Gym Children's Fitness Center", "My Gym. Childrens Fitness"));
+        assertEquals("PENNSYLVNIA", subject.logestCommonSubsequence("PENNSYLVANIA", "PENNCISYLVNIA"));
+        assertEquals("t", subject.logestCommonSubsequence("left", "right"));
+        assertEquals("tttt", subject.logestCommonSubsequence("leettteft", "ritttght"));
+        assertEquals("the same string", subject.logestCommonSubsequence("the same string", "the same string"));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceNullNull() throws Exception {
+        subject.logestCommonSubsequence(null, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceStringNull() throws Exception {
+        subject.logestCommonSubsequence(" ", null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGettingLongestCommonSubsequenceNullString() throws Exception {
+        subject.logestCommonSubsequence(null, "right");
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/ParameterizedEditDistanceFromTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/ParameterizedEditDistanceFromTest.java b/src/test/java/org/apache/commons/text/similarity/ParameterizedEditDistanceFromTest.java
new file mode 100644
index 0000000..0201ca0
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/ParameterizedEditDistanceFromTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Unit tests for {@link EditDistanceFrom}.
+ *
+ * @param <R> The {@link EditDistance} return type.
+ */
+@RunWith(Parameterized.class)
+public class ParameterizedEditDistanceFromTest<R> {
+
+    private final EditDistance<R> editDistance;
+    private final CharSequence left;
+    private final CharSequence right;
+    private final R distance;
+
+    public ParameterizedEditDistanceFromTest(
+        final EditDistance<R> editDistance,
+        final CharSequence left, final CharSequence right,
+        final R distance) {
+
+        this.editDistance = editDistance;
+        this.left = left;
+        this.right = right;
+        this.distance = distance;
+    }
+
+    @Parameters
+    public static Iterable<Object[]> parameters() {
+        return Arrays.asList( new Object[][] {
+
+            { new HammingDistance(), "Sam I am.", "Ham I am.", 1 },
+            { new HammingDistance(), "Japtheth, Ham, Shem", "Japtheth, HAM, Shem", 2 },
+            { new HammingDistance(), "Hamming", "Hamming", 0 },
+
+            { new LevenshteinDistance(), "Apache", "a patchy", 4 },
+            { new LevenshteinDistance(), "go", "no go", 3 },
+            { new LevenshteinDistance(), "go", "go", 0 },
+
+            { new LevenshteinDistance(4), "Apache", "a patchy", 4 },
+            { new LevenshteinDistance(4), "go", "no go", 3 },
+            { new LevenshteinDistance(0), "go", "go", 0 },
+
+            {
+                new EditDistance<Boolean>() {
+                    @Override
+                    public Boolean apply(final CharSequence left, final CharSequence right) {
+                        return left == right || (left != null && left.equals(right));
+                    }
+                },
+                "Bob's your uncle.",
+                "Every good boy does fine.",
+                false
+            }
+
+        } );
+    }
+
+    @Test
+    public void test() {
+        final EditDistanceFrom<R> editDistanceFrom = new EditDistanceFrom<>(editDistance, left);
+        assertThat(editDistanceFrom.apply(right), equalTo(distance));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/ParameterizedLevenshteinDistanceTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/ParameterizedLevenshteinDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/ParameterizedLevenshteinDistanceTest.java
new file mode 100644
index 0000000..0ef18d0
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/ParameterizedLevenshteinDistanceTest.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Unit tests for {@link LevenshteinDistance}.
+ */
+@RunWith(Parameterized.class)
+public class ParameterizedLevenshteinDistanceTest {
+
+    private final Integer distance;
+    private final CharSequence left;
+    private final CharSequence right;
+    private final Integer threshold;
+
+    public ParameterizedLevenshteinDistanceTest(
+        final Integer threshold,
+        final CharSequence left, final CharSequence right,
+        final Integer distance) {
+
+        this.threshold = threshold;
+        this.left = left;
+        this.right = right;
+        this.distance = distance;
+    }
+
+    @Parameters
+    public static Iterable<Object[]> parameters() {
+        return Arrays.asList( new Object[][] {
+
+            /* empty strings */
+            { 0, "", "", 0 },
+            { 8, "aaapppp", "", 7 },
+            { 7, "aaapppp", "", 7 },
+            { 6, "aaapppp", "", -1 },
+
+            /* unequal strings, zero threshold */
+            { 0, "b", "a", -1 },
+            { 0, "a", "b", -1 },
+
+            /* equal strings */
+            { 0, "aa", "aa", 0 },
+            { 2, "aa", "aa", 0 },
+
+            /* same length */
+            { 2, "aaa", "bbb", -1 },
+            { 3, "aaa", "bbb", 3 },
+
+            /* big stripe */
+            { 10, "aaaaaa", "b", 6 },
+
+            /* distance less than threshold */
+            { 8, "aaapppp", "b", 7 },
+            { 4, "a", "bbb", 3 },
+
+            /* distance equal to threshold */
+            { 7, "aaapppp", "b", 7 },
+            { 3, "a", "bbb", 3 },
+
+            /* distance greater than threshold */
+            { 2, "a", "bbb", -1 },
+            { 2, "bbb", "a", -1 },
+            { 6, "aaapppp", "b", -1 },
+
+            /* stripe runs off array, strings not similar */
+            { 1, "a", "bbb", -1 },
+            { 1, "bbb", "a", -1 },
+
+            /* stripe runs off array, strings are similar */
+            { 1, "12345", "1234567", -1 },
+            { 1, "1234567", "12345", -1 },
+
+           /* old getLevenshteinDistance test cases */
+            { 1, "frog", "fog", 1 },
+            { 3, "fly", "ant", 3 },
+            { 7, "elephant", "hippo", 7 },
+            { 6, "elephant", "hippo", -1 },
+            { 7, "hippo", "elephant", 7 },
+            { 6, "hippo", "elephant", -1 },
+            { 8, "hippo", "zzzzzzzz", 8 },
+            { 8, "zzzzzzzz", "hippo", 8 },
+            { 1, "hello", "hallo", 1 },
+
+            { Integer.MAX_VALUE, "frog", "fog", 1 },
+            { Integer.MAX_VALUE, "fly", "ant", 3 },
+            { Integer.MAX_VALUE, "elephant", "hippo", 7 },
+            { Integer.MAX_VALUE, "hippo", "elephant", 7 },
+            { Integer.MAX_VALUE, "hippo", "zzzzzzzz", 8 },
+            { Integer.MAX_VALUE, "zzzzzzzz", "hippo", 8 },
+            { Integer.MAX_VALUE, "hello", "hallo", 1 }
+
+        } );
+    }
+
+    @Test
+    public void test() {
+        final LevenshteinDistance metric = new LevenshteinDistance(threshold);
+        assertThat(metric.apply(left, right), equalTo(distance));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/ParameterizedSimilarityScoreFromTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/ParameterizedSimilarityScoreFromTest.java b/src/test/java/org/apache/commons/text/similarity/ParameterizedSimilarityScoreFromTest.java
new file mode 100644
index 0000000..654ae4e
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/ParameterizedSimilarityScoreFromTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit tests for {@link SimilarityScoreFrom}.
+ *
+ * @param <R> The {@link SimilarityScore} return type.
+ */
+@RunWith(Parameterized.class)
+public class ParameterizedSimilarityScoreFromTest<R> {
+
+    private final SimilarityScore<R> similarityScore;
+    private final CharSequence left;
+    private final CharSequence right;
+    private final R distance;
+
+    public ParameterizedSimilarityScoreFromTest(
+            final SimilarityScore<R> similarityScore,
+            final CharSequence left, final CharSequence right,
+            final R distance) {
+
+        this.similarityScore = similarityScore;
+        this.left = left;
+        this.right = right;
+        this.distance = distance;
+    }
+
+    @Parameters
+    public static Iterable<Object[]> parameters() {
+        return Arrays.asList( new Object[][] {
+
+                { new JaroWinklerDistance(), "elephant", "hippo", 0.44 },
+                { new JaroWinklerDistance(), "hippo", "elephant",  0.44 },
+                { new JaroWinklerDistance(), "hippo", "zzzzzzzz", 0.0 },
+
+                {
+                        new SimilarityScore<Boolean>() {
+                            @Override
+                            public Boolean apply(final CharSequence left, final CharSequence right) {
+                                return left == right || (left != null && left.equals(right));
+                            }
+                        },
+                        "Bob's your uncle.",
+                        "Every good boy does fine.",
+                        false
+                }
+
+        } );
+    }
+
+    @Test
+    public void test() {
+        final SimilarityScoreFrom<R> similarityScoreFrom = new SimilarityScoreFrom<>(similarityScore, left);
+        assertThat(similarityScoreFrom.apply(right), equalTo(distance));
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/similarity/StringMetricFromTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/similarity/StringMetricFromTest.java b/src/test/java/org/apache/commons/text/similarity/StringMetricFromTest.java
new file mode 100644
index 0000000..2b6e7a8
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/similarity/StringMetricFromTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.similarity;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link EditDistanceFrom}.
+ */
+public class StringMetricFromTest {
+
+    @Test
+    public void testEquivalence() {
+        final EditDistance<Integer> metric = new LevenshteinDistance();
+        final String left = "Apache";
+        final String right = "a patchy";
+        final Integer distance = 4;
+        final EditDistanceFrom<Integer> metricFrom = new EditDistanceFrom<>(metric, left);
+
+        assertThat(metricFrom.apply(right), equalTo(distance));
+        assertThat(metricFrom.apply(right), equalTo(metric.apply(left, right)));
+    }
+
+    @Test
+    public void testJavadocExample() {
+        final EditDistance<Integer> metric = new LevenshteinDistance();
+        final String target = "Apache";
+        final EditDistanceFrom<Integer> metricFrom =
+            new EditDistanceFrom<>(metric, target);
+        String mostSimilar = null;
+        Integer shortestDistance = null;
+        
+        for (final String test : new String[] { "Appaloosa", "a patchy", "apple" }) {
+            final Integer distance = metricFrom.apply(test);
+            if (shortestDistance == null || distance < shortestDistance) {
+                shortestDistance = distance;
+                mostSimilar = test;
+            }
+        }
+        assertThat(mostSimilar, equalTo("a patchy"));
+        assertThat(shortestDistance, equalTo(4));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testMissingMetric() {
+        new EditDistanceFrom<Number>(null, "no go");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java
new file mode 100644
index 0000000..f1a4639
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link AggregateTranslator}.
+ */
+public class AggregateTranslatorTest {
+
+    @Test
+    public void testNullConstructor() throws Exception {
+        final String testString = "foo";
+        final AggregateTranslator subject = new AggregateTranslator((CharSequenceTranslator[]) null);
+        assertEquals(testString, subject.translate(testString));
+    }
+    
+    @Test
+    public void testNullVarargConstructor() throws Exception {
+        final String testString = "foo";
+        final AggregateTranslator subject = new AggregateTranslator((CharSequenceTranslator) null);
+        assertEquals(testString, subject.translate(testString));
+    }
+
+    @Test
+    public void testNonNull() throws IOException{
+        final Map<CharSequence, CharSequence> oneTwoMap = new HashMap<>();
+        oneTwoMap.put("one", "two");
+        final Map<CharSequence, CharSequence> threeFourMap = new HashMap<>();
+        threeFourMap.put("three", "four");
+        final CharSequenceTranslator translator1 = new LookupTranslator(oneTwoMap);
+        final CharSequenceTranslator translator2 = new LookupTranslator(threeFourMap);
+        final AggregateTranslator subject = new AggregateTranslator(translator1, translator2);
+        final StringWriter out1 = new StringWriter();
+        final int result1 = subject.translate(new StringBuffer("one"), 0, out1);
+        assertEquals("Incorrect codepoint consumption", 3, result1);
+        assertEquals("Incorrect value", "two", out1.toString());
+        final StringWriter out2 = new StringWriter();
+        final int result2 = subject.translate(new StringBuffer("three"), 0, out2);
+        assertEquals("Incorrect codepoint consumption", 5, result2);
+        assertEquals("Incorrect value", "four", out2.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java b/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java
new file mode 100644
index 0000000..6ab42a2
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link EntityArrays}.
+ */
+public class EntityArraysTest  {
+
+    @Test
+    public void testConstructorExists() {
+        new EntityArrays();
+    }
+
+    // LANG-659, LANG-658 - avoid duplicate entries
+    @Test
+    public void testForDuplicatedDeclaredMapKeys() throws Exception {
+        String packageDirectory = EntityArraysTest.class.getPackage().getName().replace(".", "/");
+        try (BufferedReader br = new BufferedReader(new FileReader("src/main/java/" + packageDirectory + "/EntityArrays.java"))) {
+            String line;
+            int mapDeclarationCounter = 0;
+            while ((line = br.readLine()) != null) {
+                //Start with map declaration and count put lines
+                if (line.contains("new HashMap<>();")) {
+                    mapDeclarationCounter = 0;
+                } else if (line.contains(".put(")) {
+                    mapDeclarationCounter++;
+                } else if (line.contains("Collections.unmodifiableMap(initialMap);")) {
+                    String mapVariableName = line.split("=")[0].trim();
+                    @SuppressWarnings("unchecked") // This is test code
+                    Map<String,String> mapValue = (Map<String, String>)EntityArrays.class.getDeclaredField(mapVariableName).get(EntityArrays.class);
+                    // Validate that we are not inserting into the same key twice in the map declaration. If this,
+                    // indeed was the case the keySet().size() would be smaller than the number of put() statements
+                    assertEquals(mapDeclarationCounter, mapValue.keySet().size());
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testForDuplicateDeclaredMapValuesISO8859Map() {
+        assertEquals(EntityArrays.ISO8859_1_ESCAPE.keySet().size(),
+                EntityArrays.ISO8859_1_UNESCAPE.keySet().size());
+    }
+
+    @Test
+    public void testISO8859Map() {
+        testEscapeVsUnescapeMaps(EntityArrays.ISO8859_1_ESCAPE, EntityArrays.ISO8859_1_UNESCAPE);
+    }
+
+    @Test
+    public void testForDuplicateDeclaredMapValuesHtml40ExtendedMap() {
+        assertEquals(EntityArrays.HTML40_EXTENDED_ESCAPE.keySet().size(),
+                EntityArrays.HTML40_EXTENDED_UNESCAPE.keySet().size());
+    }
+
+    @Test
+    public void testHtml40ExtendedMap() {
+        testEscapeVsUnescapeMaps(EntityArrays.HTML40_EXTENDED_ESCAPE, EntityArrays.HTML40_EXTENDED_UNESCAPE);
+    }
+
+    @Test
+    public void testForDuplicateDeclaredMapValuesAposMap() {
+        assertEquals(EntityArrays.APOS_ESCAPE.keySet().size(),
+                EntityArrays.APOS_UNESCAPE.keySet().size());
+    }
+
+    @Test
+    public void testAposMap() {
+        testEscapeVsUnescapeMaps(EntityArrays.APOS_ESCAPE, EntityArrays.APOS_UNESCAPE);
+    }
+
+    @Test
+    public void testForDuplicateDeclaredMapValuesBasicMap() {
+        assertEquals(EntityArrays.BASIC_ESCAPE.keySet().size(),
+                EntityArrays.BASIC_UNESCAPE.keySet().size());
+    }
+
+    @Test
+    public void testBasicMap() {
+        testEscapeVsUnescapeMaps(EntityArrays.BASIC_ESCAPE, EntityArrays.BASIC_UNESCAPE);
+    }
+
+    @Test
+    public void testForDuplicateDeclaredMapValuesJavaCtrlCharsMap() {
+        assertEquals(EntityArrays.JAVA_CTRL_CHARS_ESCAPE.keySet().size(),
+                EntityArrays.JAVA_CTRL_CHARS_UNESCAPE.keySet().size());
+    }
+
+    @Test
+    public void testJavaCntrlCharsMap() {
+        testEscapeVsUnescapeMaps(EntityArrays.JAVA_CTRL_CHARS_ESCAPE, EntityArrays.JAVA_CTRL_CHARS_UNESCAPE);
+    }
+
+    private void testEscapeVsUnescapeMaps(final Map<CharSequence, CharSequence> escapeMap,
+                                          final Map<CharSequence, CharSequence> unescapeMap) {
+        for (final CharSequence escapeKey : escapeMap.keySet()) {
+            for (final CharSequence unescapeKey : unescapeMap.keySet()) {
+                if (escapeKey == unescapeMap.get(unescapeKey)) {
+                    assertEquals(escapeMap.get(escapeKey), unescapeKey);
+                }
+            }
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/JavaUnicodeEscaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/JavaUnicodeEscaperTest.java b/src/test/java/org/apache/commons/text/translate/JavaUnicodeEscaperTest.java
new file mode 100644
index 0000000..f2d4bea
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/JavaUnicodeEscaperTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import java.io.UnsupportedEncodingException;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link JavaUnicodeEscaper}.
+ */
+public class JavaUnicodeEscaperTest {
+
+    @Test
+    public void testBelow() {
+        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.below('F');
+
+        final String input = "ADFGZ";
+        final String result = jue.translate(input);
+        assertEquals("Failed to escape Unicode characters via the below method", "\\u0041\\u0044FGZ", result);
+    }
+
+    @Test
+    public void testBetween() {
+        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.between('F', 'L');
+
+        final String input = "ADFGZ";
+        final String result = jue.translate(input);
+        assertEquals("Failed to escape Unicode characters via the between method", "AD\\u0046\\u0047Z", result);
+    }
+
+    @Test
+    public void testAbove() {
+        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.above('F');
+
+        final String input = "ADFGZ";
+        final String result = jue.translate(input);
+        assertEquals("Failed to escape Unicode characters via the above method", "ADF\\u0047\\u005A", result);
+    }
+
+    @Test
+    public void testToUtf16Escape() throws UnsupportedEncodingException {
+        final JavaUnicodeEscaper jue = JavaUnicodeEscaper.below('F');
+        // According to https://en.wikipedia.org/wiki/UTF-16#Code_points_U.2B10000..U.2B10FFFF,
+        // Character ?,	U+24B62,	Binary Code Point 0010 0100 1011 0110 0010,	Binary UTF-167 1101 1000 0101 0010 1101 1111 0110 0010, UTF-16 Hex Code Units D852 DF62
+        final String encoding = jue.toUtf16Escape(Integer.parseInt("024B62", 16));
+        assertEquals("\\uD852\\uDF62",encoding);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java
new file mode 100644
index 0000000..ebf7af5
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link LookupTranslator}.
+ */
+public class LookupTranslatorTest  {
+
+    @Test
+    public void testBasicLookup() throws IOException {
+        final Map<CharSequence, CharSequence> translatorMap = new HashMap<>();
+        translatorMap.put("one", "two");
+        final LookupTranslator lt = new LookupTranslator(translatorMap);
+        final StringWriter out = new StringWriter();
+        final int result = lt.translate("one", 0, out);
+        assertEquals("Incorrect codepoint consumption", 3, result);
+        assertEquals("Incorrect value", "two", out.toString());
+    }
+
+    // Tests: https://issues.apache.org/jira/browse/LANG-882
+    @Test
+    public void testLang882() throws IOException {
+        final Map<CharSequence, CharSequence> translatorMap = new HashMap<>();
+        translatorMap.put(new StringBuffer("one"), new StringBuffer("two"));
+        final LookupTranslator lt = new LookupTranslator(translatorMap);
+        final StringWriter out = new StringWriter();
+        final int result = lt.translate(new StringBuffer("one"), 0, out);
+        assertEquals("Incorrect codepoint consumption", 3, result);
+        assertEquals("Incorrect value", "two", out.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java b/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java
new file mode 100644
index 0000000..efd3ddd
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link NumericEntityEscaper}.
+ */
+public class NumericEntityEscaperTest  {
+
+    @Test
+    public void testBelow() {
+        final NumericEntityEscaper nee = NumericEntityEscaper.below('F');
+
+        final String input = "ADFGZ";
+        final String result = nee.translate(input);
+        assertEquals("Failed to escape numeric entities via the below method", "&#65;&#68;FGZ", result);
+    }
+
+    @Test
+    public void testBetween() {
+        final NumericEntityEscaper nee = NumericEntityEscaper.between('F', 'L');
+
+        final String input = "ADFGZ";
+        final String result = nee.translate(input);
+        assertEquals("Failed to escape numeric entities via the between method", "AD&#70;&#71;Z", result);
+    }
+
+    @Test
+    public void testAbove() {
+        final NumericEntityEscaper nee = NumericEntityEscaper.above('F');
+
+        final String input = "ADFGZ";
+        final String result = nee.translate(input);
+        assertEquals("Failed to escape numeric entities via the above method", "ADF&#71;&#90;", result);
+    }
+
+    // See LANG-617
+    @Test
+    public void testSupplementary() {
+        final NumericEntityEscaper nee = new NumericEntityEscaper();
+        final String input = "\uD803\uDC22";
+        final String expected = "&#68642;";
+
+        final String result = nee.translate(input);
+        assertEquals("Failed to escape numeric entities supplementary characters", expected, result);
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java b/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java
new file mode 100644
index 0000000..f62386e
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit tests for {@link NumericEntityUnescaper}.
+ */
+public class NumericEntityUnescaperTest  {
+
+    @Test
+    public void testSupplementaryUnescaping() {
+        final NumericEntityUnescaper neu = new NumericEntityUnescaper();
+        final String input = "&#68642;";
+        final String expected = "\uD803\uDC22";
+
+        final String result = neu.translate(input);
+        assertEquals("Failed to unescape numeric entities supplementary characters", expected, result);
+    }
+
+    @Test
+    public void testOutOfBounds() {
+        final NumericEntityUnescaper neu = new NumericEntityUnescaper();
+
+        assertEquals("Failed to ignore when last character is &", "Test &", neu.translate("Test &"));
+        assertEquals("Failed to ignore when last character is &", "Test &#", neu.translate("Test &#"));
+        assertEquals("Failed to ignore when last character is &", "Test &#x", neu.translate("Test &#x"));
+        assertEquals("Failed to ignore when last character is &", "Test &#X", neu.translate("Test &#X"));
+    }
+
+    @Test
+    public void testUnfinishedEntity() {
+        // parse it
+        NumericEntityUnescaper neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.semiColonOptional);
+        String input = "Test &#x30 not test";
+        String expected = "Test \u0030 not test";
+
+        String result = neu.translate(input);
+        assertEquals("Failed to support unfinished entities (i.e. missing semi-colon)", expected, result);
+
+        // ignore it
+        neu = new NumericEntityUnescaper();
+        input = "Test &#x30 not test";
+        expected = input;
+
+        result = neu.translate(input);
+        assertEquals("Failed to ignore unfinished entities (i.e. missing semi-colon)", expected, result);
+
+        // fail it
+        neu = new NumericEntityUnescaper(NumericEntityUnescaper.OPTION.errorIfNoSemiColon);
+        input = "Test &#x30 not test";
+
+        try {
+            result = neu.translate(input);
+            fail("IllegalArgumentException expected");
+        } catch(final IllegalArgumentException iae) {
+            // expected
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java b/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java
new file mode 100644
index 0000000..6b02dc8
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link OctalUnescaper}.
+ */
+public class OctalUnescaperTest {
+
+    @Test
+    public void testBetween() {
+        final OctalUnescaper oue = new OctalUnescaper();   //.between("1", "377");
+
+        String input = "\\45";
+        String result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\45", result);
+
+        input = "\\377";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\377", result);
+
+        input = "\\377 and";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\377 and", result);
+
+        input = "\\378 and";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\37" + "8 and", result);
+
+        input = "\\378";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\37" + "8", result);
+
+        input = "\\1";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\1", result);
+
+        input = "\\036";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\036", result);
+
+        input = "\\0365";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\036" + "5", result);
+
+        input = "\\003";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\003", result);
+
+        input = "\\0003";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\000" + "3", result);
+
+        input = "\\279";
+        result = oue.translate(input);
+        assertEquals("Failed to unescape octal characters via the between method", "\279", result);
+
+        input = "\\999";
+        result = oue.translate(input);
+        assertEquals("Failed to ignore an out of range octal character via the between method", "\\999", result);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java
new file mode 100644
index 0000000..d36d6e2
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit test for {@link SinglePassTranslator}
+ */
+public class SinglePassTranslatorTest {
+
+    private final SinglePassTranslator dummyTranslator = new SinglePassTranslator() {
+        @Override
+        void translateWhole(final CharSequence input, final Writer out) throws IOException {
+        }
+    };
+
+    private StringWriter out;
+
+    @Before
+    public void before() {
+         out = new StringWriter();
+    }
+
+    @Test
+    public void codePointsAreReturned() throws Exception {
+        assertEquals(0, dummyTranslator.translate("", 0, out));
+        assertEquals(3, dummyTranslator.translate("abc", 0, out));
+        assertEquals(7, dummyTranslator.translate("abcdefg", 0, out));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void indexIsValidated() throws Exception {
+        dummyTranslator.translate("abc", 1, out);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java b/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java
new file mode 100644
index 0000000..8f35802
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link UnicodeEscaper}.
+ */
+public class UnicodeEscaperTest  {
+
+    @Test
+    public void testBelow() {
+        final UnicodeEscaper ue = UnicodeEscaper.below('F');
+
+        final String input = "ADFGZ";
+        final String result = ue.translate(input);
+        assertEquals("Failed to escape Unicode characters via the below method", "\\u0041\\u0044FGZ", result);
+    }
+
+    @Test
+    public void testBetween() {
+        final UnicodeEscaper ue = UnicodeEscaper.between('F', 'L');
+
+        final String input = "ADFGZ";
+        final String result = ue.translate(input);
+        assertEquals("Failed to escape Unicode characters via the between method", "AD\\u0046\\u0047Z", result);
+    }
+
+    @Test
+    public void testAbove() {
+        final UnicodeEscaper ue = UnicodeEscaper.above('F');
+
+        final String input = "ADFGZ";
+        final String result = ue.translate(input);
+        assertEquals("Failed to escape Unicode characters via the above method", "ADF\\u0047\\u005A", result);
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/UnicodeUnescaperTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/UnicodeUnescaperTest.java b/src/test/java/org/apache/commons/text/translate/UnicodeUnescaperTest.java
new file mode 100644
index 0000000..4be0c98
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/UnicodeUnescaperTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Unit tests for {@link UnicodeEscaper}.
+ */
+public class UnicodeUnescaperTest {
+
+    // Requested in LANG-507
+    @Test
+    public void testUPlus() {
+        final UnicodeUnescaper uu = new UnicodeUnescaper();
+
+        final String input = "\\u+0047";
+        assertEquals("Failed to unescape Unicode characters with 'u+' notation", "G", uu.translate(input));
+    }
+
+    @Test
+    public void testUuuuu() {
+        final UnicodeUnescaper uu = new UnicodeUnescaper();
+
+        final String input = "\\uuuuuuuu0047";
+        final String result = uu.translate(input);
+        assertEquals("Failed to unescape Unicode characters with many 'u' characters", "G", result);
+    }
+
+    @Test
+    public void testLessThanFour() {
+        final UnicodeUnescaper uu = new UnicodeUnescaper();
+
+        final String input = "\\0047\\u006";
+        try {
+            uu.translate(input);
+            fail("A lack of digits in a Unicode escape sequence failed to throw an exception");
+        } catch(final IllegalArgumentException iae) {
+            // expected
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java b/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java
new file mode 100644
index 0000000..6f67e11
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text.translate;
+
+import org.junit.Test;
+
+import java.io.CharArrayWriter;
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit tests for {@link UnicodeUnpairedSurrogateRemover}.
+ */
+public class UnicodeUnpairedSurrogateRemoverTest {
+    final UnicodeUnpairedSurrogateRemover subject = new UnicodeUnpairedSurrogateRemover();
+    final CharArrayWriter writer = new CharArrayWriter(); // nothing is ever written to it
+    
+    @Test
+    public void testValidCharacters() throws IOException {
+        assertEquals(false, subject.translate(0xd7ff, writer));
+        assertEquals(false, subject.translate(0xe000, writer));
+        assertEquals(0, writer.size());
+    }
+    
+    @Test
+    public void testInvalidCharacters() throws IOException {
+        assertEquals(true, subject.translate(0xd800, writer));
+        assertEquals(true, subject.translate(0xdfff, writer));
+        assertEquals(0, writer.size());
+    }
+}
+


[04/50] [abbrv] [text] Update to 1.0-SNAPSHOT in version

Posted by ch...@apache.org.
Update to 1.0-SNAPSHOT in version


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/348aa51c
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/348aa51c
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/348aa51c

Branch: refs/heads/release
Commit: 348aa51c1c9e427845b5063874ec4131c7d74182
Parents: 80ec859
Author: Rob Tompkins <ch...@apache.org>
Authored: Thu Feb 9 08:20:27 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Thu Feb 9 08:20:27 2017 -0500

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/348aa51c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 7a7bdc2..dc2bc80 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <artifactId>commons-text</artifactId>
-  <version>1.0-beta-1</version>
+  <version>1.0-SNAPSHOT</version>
   <name>Apache Commons Text</name>
 
   <inceptionYear>2014</inceptionYear>


[40/50] [abbrv] [text] Merge branch 'TEXT-65' of github.com:chtompki/commons-text

Posted by ch...@apache.org.
Merge branch 'TEXT-65' of github.com:chtompki/commons-text


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/40061c70
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/40061c70
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/40061c70

Branch: refs/heads/release
Commit: 40061c701fa78c0808556ab98d6f68ccbe6728e6
Parents: 931fc75 8934741
Author: Rob Tompkins <ch...@apache.org>
Authored: Fri Feb 17 08:45:53 2017 -0500
Committer: Rob Tompkins <ch...@apache.org>
Committed: Fri Feb 17 08:45:53 2017 -0500

----------------------------------------------------------------------
 checkstyle-suppressions.xml                     | 27 ++++++++++-
 src/changes/changes.xml                         |  3 +-
 .../java/org/apache/commons/text/StrLookup.java |  1 +
 .../org/apache/commons/text/StrMatcher.java     |  8 +--
 .../org/apache/commons/text/StrSubstitutor.java | 47 +++++++++++-------
 .../org/apache/commons/text/StrTokenizer.java   | 44 ++++++++++-------
 .../apache/commons/text/StringEscapeUtils.java  |  1 -
 .../text/translate/AggregateTranslator.java     | 17 ++++---
 .../text/translate/CharSequenceTranslator.java  | 32 +++++++-----
 .../text/translate/CodePointTranslator.java     | 14 +++---
 .../commons/text/translate/CsvTranslators.java  | 10 +++-
 .../commons/text/translate/EntityArrays.java    |  4 +-
 .../text/translate/JavaUnicodeEscaper.java      | 14 +++---
 .../text/translate/LookupTranslator.java        |  8 ++-
 .../text/translate/NumericEntityEscaper.java    |  5 +-
 .../text/translate/NumericEntityUnescaper.java  | 51 ++++++++++----------
 .../commons/text/translate/OctalUnescaper.java  | 14 +++---
 .../text/translate/SingleLookupTranslator.java  |  8 ++-
 .../text/translate/SinglePassTranslator.java    | 10 ++--
 .../commons/text/translate/UnicodeEscaper.java  | 13 +++--
 .../text/translate/UnicodeUnescaper.java        | 11 +++--
 .../UnicodeUnpairedSurrogateRemover.java        |  2 +-
 22 files changed, 214 insertions(+), 130 deletions(-)
----------------------------------------------------------------------



[49/50] [abbrv] [text] Merge branch 'fix-locale-issues'

Posted by ch...@apache.org.
Merge branch 'fix-locale-issues'

This closes #35 and fixes TEXT-64


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/61a0be4e
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/61a0be4e
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/61a0be4e

Branch: refs/heads/release
Commit: 61a0be4ee614ea4a5f922e4502d6b761d97ee7ef
Parents: dc10b4c 3a64140
Author: Bruno P. Kinoshita <br...@yahoo.com.br>
Authored: Thu Mar 2 14:45:17 2017 +1300
Committer: Bruno P. Kinoshita <br...@yahoo.com.br>
Committed: Thu Mar 2 14:45:17 2017 +1300

----------------------------------------------------------------------
 .../java/org/apache/commons/text/ExtendedMessageFormat.java     | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------



[25/50] [abbrv] [text] chore: update packages back to org.apache.commons.text.*

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/AlphabetConverter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/AlphabetConverter.java b/src/main/java/org/apache/commons/text/beta/AlphabetConverter.java
deleted file mode 100644
index 3080fe5..0000000
--- a/src/main/java/org/apache/commons/text/beta/AlphabetConverter.java
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
-
-/**
- * <p>
- * Convert from one alphabet to another, with the possibility of leaving certain
- * characters unencoded.
- * </p>
- *
- * <p>
- * The target and do not encode languages must be in the Unicode BMP, but the
- * source language does not.
- * </p>
- *
- * <p>
- * The encoding will all be of a fixed length, except for the 'do not encode'
- * chars, which will be of length 1
- * </p>
- *
- * <h3>Sample usage</h3>
- *
- * <pre>
- * Character[] originals; // a, b, c, d
- * Character[] encoding; // 0, 1, d
- * Character[] doNotEncode; // d
- *
- * AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originals,
- * encoding, doNotEncode);
- *
- * ac.encode("a"); // 00
- * ac.encode("b"); // 01
- * ac.encode("c"); // 0d
- * ac.encode("d"); // d
- * ac.encode("abcd"); // 00010dd
- * </pre>
- *
- * <p>
- * #ThreadSafe# AlphabetConverter class methods are threadsafe as they do not
- * change internal state.
- * </p>
- *
- * @since 1.0
- *
- */
-public final class AlphabetConverter {
-
-    /**
-     * Original string to be encoded.
-     */
-    private final Map<Integer, String> originalToEncoded;
-    /**
-     * Encoding alphabet.
-     */
-    private final Map<String, String> encodedToOriginal;
-    /**
-     * Length of the encoded letter.
-     */
-    private final int encodedLetterLength;
-    /**
-     * Arrow constant, used for converting the object into a string.
-     */
-    private static final String ARROW = " -> ";
-    /**
-     * Line separator, used for converting the object into a string.
-     */
-    private static final String LINE_SEPARATOR =
-            System.getProperty("line.separator");
-
-    /**
-     * Hidden constructor for alphabet converter. Used by static helper methods.
-     *
-     * @param originalToEncoded original string to be encoded
-     * @param encodedToOriginal encoding alphabet
-     * @param encodedLetterLength length of the encoded letter
-     */
-    private AlphabetConverter(final Map<Integer, String> originalToEncoded,
-                              final Map<String, String> encodedToOriginal,
-                              final int encodedLetterLength) {
-
-        this.originalToEncoded = originalToEncoded;
-        this.encodedToOriginal = encodedToOriginal;
-        this.encodedLetterLength = encodedLetterLength;
-    }
-
-    /**
-     * Encode a given string.
-     *
-     * @param original the string to be encoded
-     * @return the encoded string, {@code null} if the given string is null
-     * @throws UnsupportedEncodingException if chars that are not supported are
-     *                                      encountered
-     */
-    public String encode(final String original)
-            throws UnsupportedEncodingException {
-        if (original == null) {
-            return null;
-        }
-
-        final StringBuilder sb = new StringBuilder();
-
-        for (int i = 0; i < original.length();) {
-            final int codepoint = original.codePointAt(i);
-
-            final String nextLetter = originalToEncoded.get(codepoint);
-
-            if (nextLetter == null) {
-                throw new UnsupportedEncodingException(
-                        "Couldn't find encoding for '"
-                                + codePointToString(codepoint)
-                                + "' in "
-                                + original
-                );
-            }
-
-            sb.append(nextLetter);
-
-            i += Character.charCount(codepoint);
-        }
-
-        return sb.toString();
-    }
-
-    /**
-     * Decode a given string.
-     *
-     * @param encoded a string that has been encoded using this
-     *                AlphabetConverter
-     * @return the decoded string, {@code null} if the given string is null
-     * @throws UnsupportedEncodingException if unexpected characters that
-     *                                      cannot be handled are encountered
-     */
-    public String decode(final String encoded)
-            throws UnsupportedEncodingException {
-        if (encoded == null) {
-            return null;
-        }
-
-        final StringBuilder result = new StringBuilder();
-
-        for (int j = 0; j < encoded.length();) {
-            final Integer i = encoded.codePointAt(j);
-            final String s = codePointToString(i);
-
-            if (s.equals(originalToEncoded.get(i))) {
-                result.append(s);
-                j++; // because we do not encode in Unicode extended the
-                     // length of each encoded char is 1
-            } else {
-                if (j + encodedLetterLength > encoded.length()) {
-                    throw new UnsupportedEncodingException("Unexpected end "
-                            + "of string while decoding " + encoded);
-                }
-                final String nextGroup = encoded.substring(j,
-                        j + encodedLetterLength);
-                final String next = encodedToOriginal.get(nextGroup);
-                if (next == null) {
-                    throw new UnsupportedEncodingException(
-                            "Unexpected string without decoding ("
-                                    + nextGroup + ") in " + encoded);
-                }
-                result.append(next);
-                j += encodedLetterLength;
-            }
-        }
-
-        return result.toString();
-    }
-
-    /**
-     * Get the length of characters in the encoded alphabet that are necessary
-     * for each character in the original
-     * alphabet.
-     *
-     * @return the length of the encoded char
-     */
-    public int getEncodedCharLength() {
-        return encodedLetterLength;
-    }
-
-    /**
-     * Get the mapping from integer code point of source language to encoded
-     * string. Use to reconstruct converter from
-     * serialized map.
-     *
-     * @return the original map
-     */
-    public Map<Integer, String> getOriginalToEncoded() {
-        return Collections.unmodifiableMap(originalToEncoded);
-    }
-
-    /**
-     * Recursive method used when creating encoder/decoder.
-     *
-     * @param level at which point it should add a single encoding
-     * @param currentEncoding current encoding
-     * @param encoding letters encoding
-     * @param originals original values
-     * @param doNotEncodeMap map of values that should not be encoded
-     */
-    @SuppressWarnings("PMD")
-    private void addSingleEncoding(final int level,
-                                   final String currentEncoding,
-                                   final Collection<Integer> encoding,
-                                   final Iterator<Integer> originals,
-                                   final Map<Integer, String> doNotEncodeMap) {
-
-        if (level > 0) {
-            for (final int encodingLetter : encoding) {
-                if (originals.hasNext()) {
-
-                    // this skips the doNotEncode chars if they are in the
-                    // leftmost place
-                    if (level != encodedLetterLength
-                            || !doNotEncodeMap.containsKey(encodingLetter)) {
-                        addSingleEncoding(level - 1,
-                                currentEncoding
-                                        + codePointToString(encodingLetter),
-                                encoding,
-                                originals,
-                                doNotEncodeMap
-                        );
-                    }
-                } else {
-                    return; // done encoding all the original alphabet
-                }
-            }
-        } else {
-            Integer next = originals.next();
-
-            while (doNotEncodeMap.containsKey(next)) {
-                final String originalLetterAsString = codePointToString(next);
-
-                originalToEncoded.put(next, originalLetterAsString);
-                encodedToOriginal.put(originalLetterAsString,
-                        originalLetterAsString);
-
-                if (!originals.hasNext()) {
-                    return;
-                }
-
-                next = originals.next();
-            }
-
-            final String originalLetterAsString = codePointToString(next);
-
-            originalToEncoded.put(next, currentEncoding);
-            encodedToOriginal.put(currentEncoding, originalLetterAsString);
-        }
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder();
-
-        for (final Entry<Integer, String> entry
-                : originalToEncoded.entrySet()) {
-            sb.append(codePointToString(entry.getKey()))
-                    .append(ARROW)
-                    .append(entry.getValue()).append(LINE_SEPARATOR);
-        }
-
-        return sb.toString();
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (obj == this) {
-            return true;
-        }
-        if (!(obj instanceof AlphabetConverter)) {
-            return false;
-        }
-        final AlphabetConverter other = (AlphabetConverter) obj;
-        return originalToEncoded.equals(other.originalToEncoded)
-                && encodedToOriginal.equals(other.encodedToOriginal)
-                && encodedLetterLength == other.encodedLetterLength;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(originalToEncoded,
-                encodedToOriginal,
-                encodedLetterLength);
-    }
-
-    // -- static methods
-
-    /**
-     * Create a new converter from a map.
-     *
-     * @param originalToEncoded a map returned from getOriginalToEncoded()
-     * @return the reconstructed AlphabetConverter
-     * @see AlphabetConverter#getOriginalToEncoded()
-     */
-    public static AlphabetConverter createConverterFromMap(
-            final Map<Integer, String> originalToEncoded) {
-        final Map<Integer, String> unmodifiableOriginalToEncoded =
-                Collections.unmodifiableMap(originalToEncoded);
-        final Map<String, String> encodedToOriginal = new LinkedHashMap<>();
-        final Map<Integer, String> doNotEncodeMap = new HashMap<>();
-
-        int encodedLetterLength = 1;
-
-        for (final Entry<Integer, String> e
-                : unmodifiableOriginalToEncoded.entrySet()) {
-            final String originalAsString = codePointToString(e.getKey());
-            encodedToOriginal.put(e.getValue(), originalAsString);
-
-            if (e.getValue().equals(originalAsString)) {
-                doNotEncodeMap.put(e.getKey(), e.getValue());
-            }
-
-            if (e.getValue().length() > encodedLetterLength) {
-                encodedLetterLength = e.getValue().length();
-            }
-        }
-
-        return new AlphabetConverter(unmodifiableOriginalToEncoded,
-                encodedToOriginal,
-                encodedLetterLength);
-    }
-
-    /**
-     * Create an alphabet converter, for converting from the original alphabet,
-     * to the encoded alphabet, while leaving the characters in
-     * <em>doNotEncode</em> as they are (if possible).
-     *
-     * <p>Duplicate letters in either original or encoding will be ignored.</p>
-     *
-     * @param original an array of chars representing the original alphabet
-     * @param encoding an array of chars representing the alphabet to be used
-     *                 for encoding
-     * @param doNotEncode an array of chars to be encoded using the original
-     *                    alphabet - every char here must appear in
-     *                    both the previous params
-     * @return the AlphabetConverter
-     * @throws IllegalArgumentException if an AlphabetConverter cannot be
-     *                                  constructed
-     */
-    public static AlphabetConverter createConverterFromChars(
-            final Character[] original,
-            final Character[] encoding,
-            final Character[] doNotEncode) {
-        return AlphabetConverter.createConverter(
-                convertCharsToIntegers(original),
-                convertCharsToIntegers(encoding),
-                convertCharsToIntegers(doNotEncode));
-    }
-
-    /**
-     * Convert characters to integers.
-     *
-     * @param chars array of characters
-     * @return an equivalent array of integers
-     */
-    private static Integer[] convertCharsToIntegers(final Character[] chars) {
-        if (chars == null || chars.length == 0) {
-            return new Integer[0];
-        }
-        final Integer[] integers = new Integer[chars.length];
-        for (int i = 0; i < chars.length; i++) {
-            integers[i] = (int) chars[i];
-        }
-        return integers;
-    }
-
-    /**
-     * Create an alphabet converter, for converting from the original alphabet,
-     * to the encoded alphabet, while leaving
-     * the characters in <em>doNotEncode</em> as they are (if possible).
-     *
-     * <p>Duplicate letters in either original or encoding will be ignored.</p>
-     *
-     * @param original an array of ints representing the original alphabet in
-     *                 codepoints
-     * @param encoding an array of ints representing the alphabet to be used for
-     *                 encoding, in codepoints
-     * @param doNotEncode an array of ints representing the chars to be encoded
-     *                    using the original alphabet - every char
-     *                    here must appear in both the previous params
-     * @return the AlphabetConverter
-     * @throws IllegalArgumentException if an AlphabetConverter cannot be
-     *                                   constructed
-     */
-    public static AlphabetConverter createConverter(
-            final Integer[] original,
-            final Integer[] encoding,
-            final Integer[] doNotEncode) {
-        final Set<Integer> originalCopy = new LinkedHashSet<>(Arrays.<Integer> asList(original));
-        final Set<Integer> encodingCopy = new LinkedHashSet<>(Arrays.<Integer> asList(encoding));
-        final Set<Integer> doNotEncodeCopy = new LinkedHashSet<>(Arrays.<Integer> asList(doNotEncode));
-
-        final Map<Integer, String> originalToEncoded = new LinkedHashMap<>();
-        final Map<String, String> encodedToOriginal = new LinkedHashMap<>();
-        final Map<Integer, String> doNotEncodeMap = new HashMap<>();
-
-        int encodedLetterLength;
-
-        for (final int i : doNotEncodeCopy) {
-            if (!originalCopy.contains(i)) {
-                throw new IllegalArgumentException(
-                        "Can not use 'do not encode' list because original "
-                                + "alphabet does not contain '"
-                                + codePointToString(i) + "'");
-            }
-
-            if (!encodingCopy.contains(i)) {
-                throw new IllegalArgumentException(
-                        "Can not use 'do not encode' list because encoding alphabet does not contain '"
-                                + codePointToString(i) + "'");
-            }
-
-            doNotEncodeMap.put(i, codePointToString(i));
-        }
-
-        if (encodingCopy.size() >= originalCopy.size()) {
-            encodedLetterLength = 1;
-
-            final Iterator<Integer> it = encodingCopy.iterator();
-
-            for (final int originalLetter : originalCopy) {
-                final String originalLetterAsString =
-                        codePointToString(originalLetter);
-
-                if (doNotEncodeMap.containsKey(originalLetter)) {
-                    originalToEncoded.put(originalLetter,
-                            originalLetterAsString);
-                    encodedToOriginal.put(originalLetterAsString,
-                            originalLetterAsString);
-                } else {
-                    Integer next = it.next();
-
-                    while (doNotEncodeCopy.contains(next)) {
-                        next = it.next();
-                    }
-
-                    final String encodedLetter = codePointToString(next);
-
-                    originalToEncoded.put(originalLetter, encodedLetter);
-                    encodedToOriginal.put(encodedLetter,
-                            originalLetterAsString);
-                }
-            }
-
-            return new AlphabetConverter(originalToEncoded,
-                    encodedToOriginal,
-                    encodedLetterLength);
-
-        } else if (encodingCopy.size() - doNotEncodeCopy.size() < 2) {
-            throw new IllegalArgumentException(
-                    "Must have at least two encoding characters (excluding "
-                            + "those in the 'do not encode' list), but has "
-                            + (encodingCopy.size() - doNotEncodeCopy.size()));
-        } else {
-            // we start with one which is our minimum, and because we do the
-            // first division outside the loop
-            int lettersSoFar = 1;
-
-            // the first division takes into account that the doNotEncode
-            // letters can't be in the leftmost place
-            int lettersLeft = (originalCopy.size() - doNotEncodeCopy.size())
-                    / (encodingCopy.size() - doNotEncodeCopy.size());
-
-            while (lettersLeft / encodingCopy.size() >= 1) {
-                lettersLeft = lettersLeft / encodingCopy.size();
-                lettersSoFar++;
-            }
-
-            encodedLetterLength = lettersSoFar + 1;
-
-            final AlphabetConverter ac =
-                    new AlphabetConverter(originalToEncoded,
-                            encodedToOriginal,
-                            encodedLetterLength);
-
-            ac.addSingleEncoding(encodedLetterLength,
-                    "",
-                    encodingCopy,
-                    originalCopy.iterator(),
-                    doNotEncodeMap);
-
-            return ac;
-        }
-    }
-
-    /**
-     * Create new String that contains just the given code point.
-     *
-     * @param i code point
-     * @return a new string with the new code point
-     * @see "http://www.oracle.com/us/technologies/java/supplementary-142654.html"
-     */
-    private static String codePointToString(final int i) {
-        if (Character.charCount(i) == 1) {
-            return String.valueOf((char) i);
-        }
-        return new String(Character.toChars(i));
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/Builder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/Builder.java b/src/main/java/org/apache/commons/text/beta/Builder.java
deleted file mode 100644
index 59879cd..0000000
--- a/src/main/java/org/apache/commons/text/beta/Builder.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-/**
- * <p>
- * The Builder interface is designed to designate a class as a <em>builder</em>
- * object in the Builder design pattern. Builders are capable of creating and
- * configuring objects or results that normally take multiple steps to construct
- * or are very complex to derive.
- * </p>
- *
- * <p>
- * The builder interface defines a single method, {@link #build()}, that
- * classes must implement. The result of this method should be the final
- * configured object or result after all building operations are performed.
- * </p>
- *
- * <p>
- * It is a recommended practice that the methods supplied to configure the
- * object or result being built return a reference to {@code this} so that
- * method calls can be chained together.
- * </p>
- *
- * <p>
- * Example Builder:
- * <pre><code>
- * class FontBuilder implements Builder&lt;Font&gt; {
- *     private Font font;
- *
- *     public FontBuilder(String fontName) {
- *         this.font = new Font(fontName, Font.PLAIN, 12);
- *     }
- *
- *     public FontBuilder bold() {
- *         this.font = this.font.deriveFont(Font.BOLD);
- *         return this; // Reference returned so calls can be chained
- *     }
- *
- *     public FontBuilder size(float pointSize) {
- *         this.font = this.font.deriveFont(pointSize);
- *         return this; // Reference returned so calls can be chained
- *     }
- *
- *     // Other Font construction methods
- *
- *     public Font build() {
- *         return this.font;
- *     }
- * }
- * </code></pre>
- *
- * Example Builder Usage:
- * <pre><code>
- * Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
- *                                                              .size(14.0f)
- *                                                              .build();
- * </code></pre>
- *
- *
- * @param <T> the type of object that the builder will construct or compute.
- * @since 1.0
- *
- */
-public interface Builder<T> {
-
-    /**
-     * Returns a reference to the object being constructed or result being
-     * calculated by the builder.
-     *
-     * @return the object constructed or result calculated by the builder.
-     */
-    T build();
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/CharacterPredicate.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/CharacterPredicate.java b/src/main/java/org/apache/commons/text/beta/CharacterPredicate.java
deleted file mode 100644
index 60a7c47..0000000
--- a/src/main/java/org/apache/commons/text/beta/CharacterPredicate.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-/**
- * A predicate for selecting code points. Implementations of this interface must
- * be thread safe.
- *
- * @since 1.0
- */
-public interface CharacterPredicate {
-
-    /**
-     * Tests the code point with this predicate.
-     *
-     * @param codePoint
-     *            the code point to test
-     * @return {@code true} if the code point matches the predicate,
-     *         {@code false} otherwise
-     * @since 1.0
-     */
-    boolean test(int codePoint);
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/CharacterPredicates.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/CharacterPredicates.java b/src/main/java/org/apache/commons/text/beta/CharacterPredicates.java
deleted file mode 100644
index 3bd4aca..0000000
--- a/src/main/java/org/apache/commons/text/beta/CharacterPredicates.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-/**
- * <p>
- * Commonly used implementations of {@link CharacterPredicate}. Per the interface
- * requirements, all implementations are thread safe.
- * </p>
- *
- * @since 1.0
- */
-public enum CharacterPredicates implements CharacterPredicate {
-
-    /**
-     * Tests code points against {@link Character#isLetter(int)}.
-     *
-     * @since 1.0
-     */
-    LETTERS {
-        @Override
-        public boolean test(int codePoint) {
-            return Character.isLetter(codePoint);
-        }
-    },
-
-    /**
-     * Tests code points against {@link Character#isDigit(int)}.
-     *
-     * @since 1.0
-     */
-    DIGITS {
-        @Override
-        public boolean test(int codePoint) {
-            return Character.isDigit(codePoint);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/CompositeFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/CompositeFormat.java b/src/main/java/org/apache/commons/text/beta/CompositeFormat.java
deleted file mode 100644
index fd29442..0000000
--- a/src/main/java/org/apache/commons/text/beta/CompositeFormat.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.text.FieldPosition;
-import java.text.Format;
-import java.text.ParseException;
-import java.text.ParsePosition;
-
-/**
- * Formats using one formatter and parses using a different formatter. An
- * example of use for this would be a webapp where data is taken in one way and
- * stored in a database another way.
- *
- * @since 1.0
- */
-public class CompositeFormat extends Format {
-
-    /**
-     * Required for serialization support.
-     *
-     * @see java.io.Serializable
-     */
-    private static final long serialVersionUID = -4329119827877627683L;
-
-    /** The parser to use. */
-    private final Format parser;
-    /** The formatter to use. */
-    private final Format formatter;
-
-    /**
-     * Create a format that points its parseObject method to one implementation
-     * and its format method to another.
-     *
-     * @param parser implementation
-     * @param formatter implementation
-     */
-    public CompositeFormat(final Format parser, final Format formatter) {
-        this.parser = parser;
-        this.formatter = formatter;
-    }
-
-    /**
-     * Uses the formatter Format instance.
-     *
-     * @param obj the object to format
-     * @param toAppendTo the {@link StringBuffer} to append to
-     * @param pos the FieldPosition to use (or ignore).
-     * @return <code>toAppendTo</code>
-     * @see Format#format(Object, StringBuffer, FieldPosition)
-     */
-    @Override // Therefore has to use StringBuffer
-    public StringBuffer format(final Object obj, final StringBuffer toAppendTo,
-            final FieldPosition pos) {
-        return formatter.format(obj, toAppendTo, pos);
-    }
-
-    /**
-     * Uses the parser Format instance.
-     *
-     * @param source the String source
-     * @param pos the ParsePosition containing the position to parse from, will
-     *            be updated according to parsing success (index) or failure
-     *            (error index)
-     * @return the parsed Object
-     * @see Format#parseObject(String, ParsePosition)
-     */
-    @Override
-    public Object parseObject(final String source, final ParsePosition pos) {
-        return parser.parseObject(source, pos);
-    }
-
-    /**
-     * Provides access to the parser Format implementation.
-     *
-     * @return parser Format implementation
-     */
-    public Format getParser() {
-        return this.parser;
-    }
-
-    /**
-     * Provides access to the parser Format implementation.
-     *
-     * @return formatter Format implementation
-     */
-    public Format getFormatter() {
-        return this.formatter;
-    }
-
-    /**
-     * Utility method to parse and then reformat a String.
-     *
-     * @param input String to reformat
-     * @return A reformatted String
-     * @throws ParseException thrown by parseObject(String) call
-     */
-    public String reformat(final String input) throws ParseException {
-        return format(parseObject(input));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/ExtendedMessageFormat.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/ExtendedMessageFormat.java b/src/main/java/org/apache/commons/text/beta/ExtendedMessageFormat.java
deleted file mode 100644
index 0d1eaba..0000000
--- a/src/main/java/org/apache/commons/text/beta/ExtendedMessageFormat.java
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.text.Format;
-import java.text.MessageFormat;
-import java.text.ParsePosition;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Extends <code>java.text.MessageFormat</code> to allow pluggable/additional formatting
- * options for embedded format elements.  Client code should specify a registry
- * of <code>FormatFactory</code> instances associated with <code>String</code>
- * format names.  This registry will be consulted when the format elements are
- * parsed from the message pattern.  In this way custom patterns can be specified,
- * and the formats supported by <code>java.text.MessageFormat</code> can be overridden
- * at the format and/or format style level (see MessageFormat).  A "format element"
- * embedded in the message pattern is specified (<b>()?</b> signifies optionality):<br>
- * <code>{</code><i>argument-number</i><b>(</b><code>,</code><i>format-name</i><b>
- * (</b><code>,</code><i>format-style</i><b>)?)?</b><code>}</code>
- *
- * <p>
- * <i>format-name</i> and <i>format-style</i> values are trimmed of surrounding whitespace
- * in the manner of <code>java.text.MessageFormat</code>.  If <i>format-name</i> denotes
- * <code>FormatFactory formatFactoryInstance</code> in <code>registry</code>, a <code>Format</code>
- * matching <i>format-name</i> and <i>format-style</i> is requested from
- * <code>formatFactoryInstance</code>.  If this is successful, the <code>Format</code>
- * found is used for this format element.
- * </p>
- *
- * <p><b>NOTICE:</b> The various subformat mutator methods are considered unnecessary; they exist on the parent
- * class to allow the type of customization which it is the job of this class to provide in
- * a configurable fashion.  These methods have thus been disabled and will throw
- * <code>UnsupportedOperationException</code> if called.
- * </p>
- *
- * <p>Limitations inherited from <code>java.text.MessageFormat</code>:</p>
- * <ul>
- * <li>When using "choice" subformats, support for nested formatting instructions is limited
- *     to that provided by the base class.</li>
- * <li>Thread-safety of <code>Format</code>s, including <code>MessageFormat</code> and thus
- *     <code>ExtendedMessageFormat</code>, is not guaranteed.</li>
- * </ul>
- *
- * @since 1.0
- */
-public class ExtendedMessageFormat extends MessageFormat {
-
-    /**
-     * Serializable Object.
-     */
-    private static final long serialVersionUID = -2362048321261811743L;
-
-    /**
-     * Our initial seed value for calculating hashes.
-     */
-    private static final int HASH_SEED = 31;
-
-    /**
-     * The empty string.
-     */
-    private static final String DUMMY_PATTERN = "";
-
-    /**
-     * A comma.
-     */
-    private static final char START_FMT = ',';
-
-    /**
-     * A right side squigly brace.
-     */
-    private static final char END_FE = '}';
-
-    /**
-     * A left side squigly brace.
-     */
-    private static final char START_FE = '{';
-
-    /**
-     * A properly escaped character representing a single quote.
-     */
-    private static final char QUOTE = '\'';
-
-    /**
-     * To pattern string.
-     */
-    private String toPattern;
-
-    /**
-     * Our registry of FormatFactory's.
-     */
-    private final Map<String, ? extends FormatFactory> registry;
-
-    /**
-     * Create a new ExtendedMessageFormat for the default locale.
-     *
-     * @param pattern  the pattern to use, not null
-     * @throws IllegalArgumentException in case of a bad pattern.
-     */
-    public ExtendedMessageFormat(final String pattern) {
-        this(pattern, Locale.getDefault());
-    }
-
-    /**
-     * Create a new ExtendedMessageFormat.
-     *
-     * @param pattern  the pattern to use, not null
-     * @param locale  the locale to use, not null
-     * @throws IllegalArgumentException in case of a bad pattern.
-     */
-    public ExtendedMessageFormat(final String pattern, final Locale locale) {
-        this(pattern, locale, null);
-    }
-
-    /**
-     * Create a new ExtendedMessageFormat for the default locale.
-     *
-     * @param pattern  the pattern to use, not null
-     * @param registry  the registry of format factories, may be null
-     * @throws IllegalArgumentException in case of a bad pattern.
-     */
-    public ExtendedMessageFormat(final String pattern,
-                                 final Map<String, ? extends FormatFactory> registry) {
-        this(pattern, Locale.getDefault(), registry);
-    }
-
-    /**
-     * Create a new ExtendedMessageFormat.
-     *
-     * @param pattern  the pattern to use, not null
-     * @param locale  the locale to use, not null
-     * @param registry  the registry of format factories, may be null
-     * @throws IllegalArgumentException in case of a bad pattern.
-     */
-    public ExtendedMessageFormat(final String pattern,
-                                 final Locale locale,
-                                 final Map<String, ? extends FormatFactory> registry) {
-        super(DUMMY_PATTERN);
-        setLocale(locale);
-        this.registry = registry;
-        applyPattern(pattern);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public String toPattern() {
-        return toPattern;
-    }
-
-    /**
-     * Apply the specified pattern.
-     *
-     * @param pattern String
-     */
-    @Override
-    public final void applyPattern(final String pattern) {
-        if (registry == null) {
-            super.applyPattern(pattern);
-            toPattern = super.toPattern();
-            return;
-        }
-        final ArrayList<Format> foundFormats = new ArrayList<>();
-        final ArrayList<String> foundDescriptions = new ArrayList<>();
-        final StringBuilder stripCustom = new StringBuilder(pattern.length());
-
-        final ParsePosition pos = new ParsePosition(0);
-        final char[] c = pattern.toCharArray();
-        int fmtCount = 0;
-        while (pos.getIndex() < pattern.length()) {
-            switch (c[pos.getIndex()]) {
-            case QUOTE:
-                appendQuotedString(pattern, pos, stripCustom);
-                break;
-            case START_FE:
-                fmtCount++;
-                seekNonWs(pattern, pos);
-                final int start = pos.getIndex();
-                final int index = readArgumentIndex(pattern, next(pos));
-                stripCustom.append(START_FE).append(index);
-                seekNonWs(pattern, pos);
-                Format format = null;
-                String formatDescription = null;
-                if (c[pos.getIndex()] == START_FMT) {
-                    formatDescription = parseFormatDescription(pattern,
-                            next(pos));
-                    format = getFormat(formatDescription);
-                    if (format == null) {
-                        stripCustom.append(START_FMT).append(formatDescription);
-                    }
-                }
-                foundFormats.add(format);
-                foundDescriptions.add(format == null ? null : formatDescription);
-                if (foundFormats.size() != fmtCount) {
-                    throw new IllegalArgumentException("The validated expression is false");
-                }
-                if (foundDescriptions.size() != fmtCount) {
-                    throw new IllegalArgumentException("The validated expression is false");
-                }
-                if (c[pos.getIndex()] != END_FE) {
-                    throw new IllegalArgumentException(
-                            "Unreadable format element at position " + start);
-                }
-                //$FALL-THROUGH$
-            default:
-                stripCustom.append(c[pos.getIndex()]);
-                next(pos);
-            }
-        }
-        super.applyPattern(stripCustom.toString());
-        toPattern = insertFormats(super.toPattern(), foundDescriptions);
-        if (containsElements(foundFormats)) {
-            final Format[] origFormats = getFormats();
-            // only loop over what we know we have, as MessageFormat on Java 1.3
-            // seems to provide an extra format element:
-            int i = 0;
-            for (final Iterator<Format> it = foundFormats.iterator(); it.hasNext(); i++) {
-                final Format f = it.next();
-                if (f != null) {
-                    origFormats[i] = f;
-                }
-            }
-            super.setFormats(origFormats);
-        }
-    }
-
-    /**
-     * Throws UnsupportedOperationException - see class Javadoc for details.
-     *
-     * @param formatElementIndex format element index
-     * @param newFormat the new format
-     * @throws UnsupportedOperationException always thrown since this isn't
-     *                                       supported by ExtendMessageFormat
-     */
-    @Override
-    public void setFormat(final int formatElementIndex, final Format newFormat) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws UnsupportedOperationException - see class Javadoc for details.
-     *
-     * @param argumentIndex argument index
-     * @param newFormat the new format
-     * @throws UnsupportedOperationException always thrown since this isn't
-     *                                       supported by ExtendMessageFormat
-     */
-    @Override
-    public void setFormatByArgumentIndex(final int argumentIndex,
-                                         final Format newFormat) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws UnsupportedOperationException - see class Javadoc for details.
-     *
-     * @param newFormats new formats
-     * @throws UnsupportedOperationException always thrown since this isn't
-     *                                       supported by ExtendMessageFormat
-     */
-    @Override
-    public void setFormats(final Format[] newFormats) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Throws UnsupportedOperationException - see class Javadoc for details.
-     *
-     * @param newFormats new formats
-     * @throws UnsupportedOperationException always thrown since this isn't
-     *                                       supported by ExtendMessageFormat
-     */
-    @Override
-    public void setFormatsByArgumentIndex(final Format[] newFormats) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Check if this extended message format is equal to another object.
-     *
-     * @param obj the object to compare to
-     * @return true if this object equals the other, otherwise false
-     */
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!super.equals(obj)) {
-            return false;
-        }
-        if (!Objects.equals(getClass(), obj.getClass())) {
-          return false;
-        }
-        final ExtendedMessageFormat rhs = (ExtendedMessageFormat) obj;
-        if (!Objects.equals(toPattern, rhs.toPattern)) {
-            return false;
-        }
-        if (!Objects.equals(registry, rhs.registry)) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        int result = super.hashCode();
-        result = HASH_SEED * result + Objects.hashCode(registry);
-        result = HASH_SEED * result + Objects.hashCode(toPattern);
-        return result;
-    }
-
-    /**
-     * Get a custom format from a format description.
-     *
-     * @param desc String
-     * @return Format
-     */
-    private Format getFormat(final String desc) {
-        if (registry != null) {
-            String name = desc;
-            String args = null;
-            final int i = desc.indexOf(START_FMT);
-            if (i > 0) {
-                name = desc.substring(0, i).trim();
-                args = desc.substring(i + 1).trim();
-            }
-            final FormatFactory factory = registry.get(name);
-            if (factory != null) {
-                return factory.getFormat(name, args, getLocale());
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Read the argument index from the current format element.
-     *
-     * @param pattern pattern to parse
-     * @param pos current parse position
-     * @return argument index
-     */
-    private int readArgumentIndex(final String pattern, final ParsePosition pos) {
-        final int start = pos.getIndex();
-        seekNonWs(pattern, pos);
-        final StringBuilder result = new StringBuilder();
-        boolean error = false;
-        for (; !error && pos.getIndex() < pattern.length(); next(pos)) {
-            char c = pattern.charAt(pos.getIndex());
-            if (Character.isWhitespace(c)) {
-                seekNonWs(pattern, pos);
-                c = pattern.charAt(pos.getIndex());
-                if (c != START_FMT && c != END_FE) {
-                    error = true;
-                    continue;
-                }
-            }
-            if ((c == START_FMT || c == END_FE) && result.length() > 0) {
-                try {
-                    return Integer.parseInt(result.toString());
-                } catch (final NumberFormatException e) { // NOPMD
-                    // we've already ensured only digits, so unless something
-                    // outlandishly large was specified we should be okay.
-                }
-            }
-            error = !Character.isDigit(c);
-            result.append(c);
-        }
-        if (error) {
-            throw new IllegalArgumentException(
-                    "Invalid format argument index at position " + start + ": "
-                            + pattern.substring(start, pos.getIndex()));
-        }
-        throw new IllegalArgumentException(
-                "Unterminated format element at position " + start);
-    }
-
-    /**
-     * Parse the format component of a format element.
-     *
-     * @param pattern string to parse
-     * @param pos current parse position
-     * @return Format description String
-     */
-    private String parseFormatDescription(final String pattern, final ParsePosition pos) {
-        final int start = pos.getIndex();
-        seekNonWs(pattern, pos);
-        final int text = pos.getIndex();
-        int depth = 1;
-        for (; pos.getIndex() < pattern.length(); next(pos)) {
-            switch (pattern.charAt(pos.getIndex())) {
-            case START_FE:
-                depth++;
-                break;
-            case END_FE:
-                depth--;
-                if (depth == 0) {
-                    return pattern.substring(text, pos.getIndex());
-                }
-                break;
-            case QUOTE:
-                getQuotedString(pattern, pos);
-                break;
-            default:
-                break;
-            }
-        }
-        throw new IllegalArgumentException(
-                "Unterminated format element at position " + start);
-    }
-
-    /**
-     * Insert formats back into the pattern for toPattern() support.
-     *
-     * @param pattern source
-     * @param customPatterns The custom patterns to re-insert, if any
-     * @return full pattern
-     */
-    private String insertFormats(final String pattern, final ArrayList<String> customPatterns) {
-        if (!containsElements(customPatterns)) {
-            return pattern;
-        }
-        final StringBuilder sb = new StringBuilder(pattern.length() * 2);
-        final ParsePosition pos = new ParsePosition(0);
-        int fe = -1;
-        int depth = 0;
-        while (pos.getIndex() < pattern.length()) {
-            final char c = pattern.charAt(pos.getIndex());
-            switch (c) {
-            case QUOTE:
-                appendQuotedString(pattern, pos, sb);
-                break;
-            case START_FE:
-                depth++;
-                sb.append(START_FE).append(readArgumentIndex(pattern, next(pos)));
-                // do not look for custom patterns when they are embedded, e.g. in a choice
-                if (depth == 1) {
-                    fe++;
-                    final String customPattern = customPatterns.get(fe);
-                    if (customPattern != null) {
-                        sb.append(START_FMT).append(customPattern);
-                    }
-                }
-                break;
-            case END_FE:
-                depth--;
-                //$FALL-THROUGH$
-            default:
-                sb.append(c);
-                next(pos);
-            }
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Consume whitespace from the current parse position.
-     *
-     * @param pattern String to read
-     * @param pos current position
-     */
-    private void seekNonWs(final String pattern, final ParsePosition pos) {
-        int len = 0;
-        final char[] buffer = pattern.toCharArray();
-        do {
-            len = StrMatcher.splitMatcher().isMatch(buffer, pos.getIndex());
-            pos.setIndex(pos.getIndex() + len);
-        } while (len > 0 && pos.getIndex() < pattern.length());
-    }
-
-    /**
-     * Convenience method to advance parse position by 1.
-     *
-     * @param pos ParsePosition
-     * @return <code>pos</code>
-     */
-    private ParsePosition next(final ParsePosition pos) {
-        pos.setIndex(pos.getIndex() + 1);
-        return pos;
-    }
-
-    /**
-     * Consume a quoted string, adding it to <code>appendTo</code> if
-     * specified.
-     *
-     * @param pattern pattern to parse
-     * @param pos current parse position
-     * @param appendTo optional StringBuilder to append
-     * @return <code>appendTo</code>
-     */
-    private StringBuilder appendQuotedString(final String pattern, final ParsePosition pos,
-            final StringBuilder appendTo) {
-        assert pattern.toCharArray()[pos.getIndex()] == QUOTE
-                : "Quoted string must start with quote character";
-
-        // handle quote character at the beginning of the string
-        if (appendTo != null) {
-            appendTo.append(QUOTE);
-        }
-        next(pos);
-
-        final int start = pos.getIndex();
-        final char[] c = pattern.toCharArray();
-        final int lastHold = start;
-        for (int i = pos.getIndex(); i < pattern.length(); i++) {
-            switch (c[pos.getIndex()]) {
-            case QUOTE:
-                next(pos);
-                return appendTo == null ? null : appendTo.append(c, lastHold,
-                        pos.getIndex() - lastHold);
-            default:
-                next(pos);
-            }
-        }
-        throw new IllegalArgumentException(
-                "Unterminated quoted string at position " + start);
-    }
-
-    /**
-     * Consume quoted string only.
-     *
-     * @param pattern pattern to parse
-     * @param pos current parse position
-     */
-    private void getQuotedString(final String pattern, final ParsePosition pos) {
-        appendQuotedString(pattern, pos, null);
-    }
-
-    /**
-     * Learn whether the specified Collection contains non-null elements.
-     * @param coll to check
-     * @return <code>true</code> if some Object was found, <code>false</code> otherwise.
-     */
-    private boolean containsElements(final Collection<?> coll) {
-        if (coll == null || coll.isEmpty()) {
-            return false;
-        }
-        for (final Object name : coll) {
-            if (name != null) {
-                return true;
-            }
-        }
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/FormatFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/FormatFactory.java b/src/main/java/org/apache/commons/text/beta/FormatFactory.java
deleted file mode 100644
index 2a469e1..0000000
--- a/src/main/java/org/apache/commons/text/beta/FormatFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.text.Format;
-import java.util.Locale;
-
-/**
- * Format factory.
- *
- * @since 1.0
- */
-public interface FormatFactory {
-
-    /**
-     * Create or retrieve a format instance.
-     *
-     * @param name The format type name
-     * @param arguments Arguments used to create the format instance. This allows the
-     *                  <code>FormatFactory</code> to implement the "format style"
-     *                  concept from <code>java.text.MessageFormat</code>.
-     * @param locale The locale, may be null
-     * @return The format instance
-     */
-    Format getFormat(String name, String arguments, Locale locale);
-
-}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c7cf533d/src/main/java/org/apache/commons/text/beta/FormattableUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/beta/FormattableUtils.java b/src/main/java/org/apache/commons/text/beta/FormattableUtils.java
deleted file mode 100644
index 687f2a9..0000000
--- a/src/main/java/org/apache/commons/text/beta/FormattableUtils.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.text.beta;
-
-import java.util.Formattable;
-import java.util.Formatter;
-
-import static java.util.FormattableFlags.LEFT_JUSTIFY;
-
-/**
- * <p>Provides utilities for working with the {@code Formattable} interface.</p>
- *
- * <p>The {@link Formattable} interface provides basic control over formatting
- * when using a {@code Formatter}. It is primarily concerned with numeric precision
- * and padding, and is not designed to allow generalised alternate formats.</p>
- *
- * @since 1.0
- *
- */
-public class FormattableUtils {
-
-    /**
-     * A format that simply outputs the value as a string.
-     */
-    private static final String SIMPLEST_FORMAT = "%s";
-
-    /**
-     * <p>{@code FormattableUtils} instances should NOT be constructed in
-     * standard programming. Instead, the methods of the class should be invoked
-     * statically.</p>
-     *
-     * <p>This constructor is public to permit tools that require a JavaBean
-     * instance to operate.</p>
-     */
-    public FormattableUtils() {
-        super();
-    }
-
-    //-----------------------------------------------------------------------
-    /**
-     * Get the default formatted representation of the specified
-     * {@code Formattable}.
-     *
-     * @param formattable  the instance to convert to a string, not null
-     * @return the resulting string, not null
-     */
-    public static String toString(final Formattable formattable) {
-        return String.format(SIMPLEST_FORMAT, formattable);
-    }
-
-    /**
-     * Handles the common {@code Formattable} operations of truncate-pad-append,
-     * with no ellipsis on precision overflow, and padding width underflow with
-     * spaces.
-     *
-     * @param seq  the string to handle, not null
-     * @param formatter  the destination formatter, not null
-     * @param flags  the flags for formatting, see {@code Formattable}
-     * @param width  the width of the output, see {@code Formattable}
-     * @param precision  the precision of the output, see {@code Formattable}
-     * @return the {@code formatter} instance, not null
-     */
-    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
-            final int precision) {
-        return append(seq, formatter, flags, width, precision, ' ', null);
-    }
-
-    /**
-     * Handles the common {@link Formattable} operations of truncate-pad-append,
-     * with no ellipsis on precision overflow.
-     *
-     * @param seq  the string to handle, not null
-     * @param formatter  the destination formatter, not null
-     * @param flags  the flags for formatting, see {@code Formattable}
-     * @param width  the width of the output, see {@code Formattable}
-     * @param precision  the precision of the output, see {@code Formattable}
-     * @param padChar  the pad character to use
-     * @return the {@code formatter} instance, not null
-     */
-    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
-            final int precision, final char padChar) {
-        return append(seq, formatter, flags, width, precision, padChar, null);
-    }
-
-    /**
-     * Handles the common {@link Formattable} operations of truncate-pad-append,
-     * padding width underflow with spaces.
-     *
-     * @param seq  the string to handle, not null
-     * @param formatter  the destination formatter, not null
-     * @param flags  the flags for formatting, see {@code Formattable}
-     * @param width  the width of the output, see {@code Formattable}
-     * @param precision  the precision of the output, see {@code Formattable}
-     * @param ellipsis  the ellipsis to use when precision dictates truncation, null or
-     *  empty causes a hard truncation
-     * @return the {@code formatter} instance, not null
-     */
-    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
-            final int precision, final CharSequence ellipsis) {
-        return append(seq, formatter, flags, width, precision, ' ', ellipsis);
-    }
-
-    /**
-     * Handles the common {@link Formattable} operations of truncate-pad-append.
-     *
-     * @param seq  the string to handle, not null
-     * @param formatter  the destination formatter, not null
-     * @param flags  the flags for formatting, see {@code Formattable}
-     * @param width  the width of the output, see {@code Formattable}
-     * @param precision  the precision of the output, see {@code Formattable}
-     * @param padChar  the pad character to use
-     * @param ellipsis  the ellipsis to use when precision dictates truncation, null or
-     *  empty causes a hard truncation
-     * @return the {@code formatter} instance, not null
-     */
-    public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
-            final int precision, final char padChar, final CharSequence ellipsis) {
-        if (!(ellipsis == null || precision < 0 || ellipsis.length() <= precision)) {
-            throw new IllegalArgumentException(
-                    String.format("Specified ellipsis '%1$s' exceeds precision of %2$s",
-                            ellipsis,
-                            Integer.valueOf(precision)));
-        }
-        final StringBuilder buf = new StringBuilder(seq);
-        if (precision >= 0 && precision < seq.length()) {
-            final CharSequence _ellipsis;
-            if (ellipsis == null) {
-                _ellipsis = "";
-            } else {
-                _ellipsis = ellipsis;
-            }
-            buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString());
-        }
-        final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY;
-        for (int i = buf.length(); i < width; i++) {
-            buf.insert(leftJustify ? i : 0, padChar);
-        }
-        formatter.format(buf.toString());
-        return formatter;
-    }
-
-}