You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2020/06/26 21:55:20 UTC

[commons-text] branch master updated (4152250 -> 37a7cc2)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git.


    from 4152250  Add isMatch(CharSequence, int)
     new e46cd90  Sort members.
     new 93b8a08  No need to create a new size 0 char[] each time one is needed.
     new 37a7cc2  Tweak toString();

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/commons/text/StrBuilder.java   |    6 +-
 .../org/apache/commons/text/TextStringBuilder.java | 3933 ++++++++++----------
 .../text/matcher/AbstractStringMatcher.java        |   12 +-
 .../apache/commons/text/AlphabetConverterTest.java |    8 +-
 .../org/apache/commons/text/CaseUtilsTest.java     |    4 +-
 .../commons/text/CharacterPredicatesTest.java      |    4 +-
 .../commons/text/StrBuilderAppendInsertTest.java   |    7 +-
 .../org/apache/commons/text/StrBuilderTest.java    |    3 +-
 .../org/apache/commons/text/StrLookupTest.java     |    2 +-
 .../apache/commons/text/StrSubstitutorTest.java    |    2 +-
 .../org/apache/commons/text/StrTokenizerTest.java  |   11 +-
 .../apache/commons/text/StringEscapeUtilsTest.java |    2 +-
 .../apache/commons/text/StringTokenizerTest.java   |   12 +-
 .../text/TextStringBuilderAppendInsertTest.java    |    7 +-
 .../apache/commons/text/TextStringBuilderTest.java |    2 +-
 .../org/apache/commons/text/WordUtilsTest.java     |   23 +-
 .../commons/text/diff/StringsComparatorTest.java   |    4 +-
 .../lookup/ResourceBundleStringLookupTest.java     |    2 +-
 .../text/matcher/StringSubstitutorGetSetTest.java  |    2 +-
 .../text/similarity/CosineSimilarityTest.java      |    9 +-
 .../text/similarity/IntersectionResultTest.java    |    6 +-
 .../similarity/IntersectionSimilarityTest.java     |    4 +-
 .../text/similarity/LevenshteinDistanceTest.java   |    4 +-
 .../text/similarity/LevenshteinResultsTest.java    |    4 +-
 .../LongestCommonSubsequenceDistanceTest.java      |    6 +-
 .../similarity/LongestCommonSubsequenceTest.java   |    6 +-
 .../text/translate/AggregateTranslatorTest.java    |    4 +-
 .../text/translate/CodePointTranslatorTest.java    |    4 +-
 .../commons/text/translate/EntityArraysTest.java   |    4 +-
 .../text/translate/LookupTranslatorTest.java       |    6 +-
 .../text/translate/NumericEntityEscaperTest.java   |    4 +-
 .../text/translate/NumericEntityUnescaperTest.java |    4 +-
 .../commons/text/translate/OctalUnescaperTest.java |    4 +-
 .../text/translate/SinglePassTranslatorTest.java   |    8 +-
 .../commons/text/translate/UnicodeEscaperTest.java |    4 +-
 .../UnicodeUnpairedSurrogateRemoverTest.java       |    4 +-
 36 files changed, 2073 insertions(+), 2058 deletions(-)


[commons-text] 02/03: No need to create a new size 0 char[] each time one is needed.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git

commit 93b8a088a0ebbd2bdb80d05c6f87381976906763
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jun 26 17:02:28 2020 -0400

    No need to create a new size 0 char[] each time one is needed.
---
 .../java/org/apache/commons/text/StrBuilder.java   |  6 ++++--
 .../org/apache/commons/text/TextStringBuilder.java |  5 +++--
 .../apache/commons/text/AlphabetConverterTest.java |  8 ++++----
 .../org/apache/commons/text/CaseUtilsTest.java     |  4 ++--
 .../commons/text/CharacterPredicatesTest.java      |  4 ++--
 .../commons/text/StrBuilderAppendInsertTest.java   |  7 ++++---
 .../org/apache/commons/text/StrBuilderTest.java    |  3 ++-
 .../org/apache/commons/text/StrLookupTest.java     |  2 +-
 .../apache/commons/text/StrSubstitutorTest.java    |  2 +-
 .../org/apache/commons/text/StrTokenizerTest.java  | 11 ++++++-----
 .../apache/commons/text/StringEscapeUtilsTest.java |  2 +-
 .../apache/commons/text/StringTokenizerTest.java   | 12 ++++++-----
 .../text/TextStringBuilderAppendInsertTest.java    |  7 ++++---
 .../apache/commons/text/TextStringBuilderTest.java |  2 +-
 .../org/apache/commons/text/WordUtilsTest.java     | 23 +++++++++++-----------
 .../commons/text/diff/StringsComparatorTest.java   |  4 ++--
 .../lookup/ResourceBundleStringLookupTest.java     |  2 +-
 .../text/matcher/StringSubstitutorGetSetTest.java  |  2 +-
 .../text/similarity/CosineSimilarityTest.java      |  9 +++++----
 .../text/similarity/IntersectionResultTest.java    |  6 +++---
 .../similarity/IntersectionSimilarityTest.java     |  4 ++--
 .../text/similarity/LevenshteinDistanceTest.java   |  4 ++--
 .../text/similarity/LevenshteinResultsTest.java    |  4 ++--
 .../LongestCommonSubsequenceDistanceTest.java      |  6 +++---
 .../similarity/LongestCommonSubsequenceTest.java   |  6 +++---
 .../text/translate/AggregateTranslatorTest.java    |  4 ++--
 .../text/translate/CodePointTranslatorTest.java    |  4 ++--
 .../commons/text/translate/EntityArraysTest.java   |  4 ++--
 .../text/translate/LookupTranslatorTest.java       |  6 +++---
 .../text/translate/NumericEntityEscaperTest.java   |  4 ++--
 .../text/translate/NumericEntityUnescaperTest.java |  4 ++--
 .../commons/text/translate/OctalUnescaperTest.java |  4 ++--
 .../text/translate/SinglePassTranslatorTest.java   |  8 ++++----
 .../commons/text/translate/UnicodeEscaperTest.java |  4 ++--
 .../UnicodeUnpairedSurrogateRemoverTest.java       |  4 ++--
 35 files changed, 101 insertions(+), 90 deletions(-)

diff --git a/src/main/java/org/apache/commons/text/StrBuilder.java b/src/main/java/org/apache/commons/text/StrBuilder.java
index 1f483c3..1b741d2 100644
--- a/src/main/java/org/apache/commons/text/StrBuilder.java
+++ b/src/main/java/org/apache/commons/text/StrBuilder.java
@@ -25,6 +25,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 
+import org.apache.commons.lang3.ArrayUtils;
+
 /**
  * Builds a string from constituent parts providing a more flexible and powerful API
  * than StringBuffer.
@@ -351,7 +353,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable, Build
      */
     public char[] toCharArray() {
         if (size == 0) {
-            return new char[0];
+            return ArrayUtils.EMPTY_CHAR_ARRAY;
         }
         final char[] chars = new char[size];
         System.arraycopy(buffer, 0, chars, 0, size);
@@ -372,7 +374,7 @@ public class StrBuilder implements CharSequence, Appendable, Serializable, Build
         endIndex = validateRange(startIndex, endIndex);
         final int len = endIndex - startIndex;
         if (len == 0) {
-            return new char[0];
+            return ArrayUtils.EMPTY_CHAR_ARRAY;
         }
         final char[] chars = new char[len];
         System.arraycopy(buffer, startIndex, chars, 0, len);
diff --git a/src/main/java/org/apache/commons/text/TextStringBuilder.java b/src/main/java/org/apache/commons/text/TextStringBuilder.java
index 489e402..4ed6fd1 100644
--- a/src/main/java/org/apache/commons/text/TextStringBuilder.java
+++ b/src/main/java/org/apache/commons/text/TextStringBuilder.java
@@ -25,6 +25,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.text.matcher.StringMatcher;
 
 /**
@@ -3136,7 +3137,7 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
      */
     public char[] toCharArray() {
         if (size == 0) {
-            return new char[0];
+            return ArrayUtils.EMPTY_CHAR_ARRAY;
         }
         final char[] chars = new char[size];
         System.arraycopy(buffer, 0, chars, 0, size);
@@ -3158,7 +3159,7 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
         endIndex = validateRange(startIndex, endIndex);
         final int len = endIndex - startIndex;
         if (len == 0) {
-            return new char[0];
+            return ArrayUtils.EMPTY_CHAR_ARRAY;
         }
         final char[] chars = new char[len];
         System.arraycopy(buffer, startIndex, chars, 0, len);
diff --git a/src/test/java/org/apache/commons/text/AlphabetConverterTest.java b/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
index d4c0cb4..e88d5e1 100644
--- a/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
+++ b/src/test/java/org/apache/commons/text/AlphabetConverterTest.java
@@ -16,6 +16,10 @@
  */
 package org.apache.commons.text;
 
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
 import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -24,10 +28,6 @@ import java.util.Map;
 
 import org.junit.jupiter.api.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
 /**
  * Unit tests for {@link AlphabetConverter}.
  */
diff --git a/src/test/java/org/apache/commons/text/CaseUtilsTest.java b/src/test/java/org/apache/commons/text/CaseUtilsTest.java
index e882d6e..834b333 100644
--- a/src/test/java/org/apache/commons/text/CaseUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/CaseUtilsTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.commons.text;
 
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit tests for {@link CaseUtils} class.
diff --git a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
index 53879e4..a6ff815 100644
--- a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
+++ b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.commons.text;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Tests for {@link CharacterPredicates}.
  */
diff --git a/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
index 18178b1..f916f25 100644
--- a/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
+++ b/src/test/java/org/apache/commons/text/StrBuilderAppendInsertTest.java
@@ -27,6 +27,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -447,7 +448,7 @@ public class StrBuilderAppendInsertTest {
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new StrBuilder();
-        sb.append(new char[0]);
+        sb.append(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertThat(sb.toString()).isEqualTo("");
 
         sb.append(new char[]{'f', 'o', 'o'});
@@ -1326,7 +1327,7 @@ public class StrBuilderAppendInsertTest {
         sb.insert(0, (char[]) null);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
-        sb.insert(0, new char[0]);
+        sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
         sb.insert(0, new char[]{'f', 'o', 'o'});
@@ -1345,7 +1346,7 @@ public class StrBuilderAppendInsertTest {
         sb.insert(0, (char[]) null, 0, 0);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
-        sb.insert(0, new char[0], 0, 0);
+        sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY, 0, 0);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
         assertThrows(IndexOutOfBoundsException.class,
diff --git a/src/test/java/org/apache/commons/text/StrBuilderTest.java b/src/test/java/org/apache/commons/text/StrBuilderTest.java
index a5ae720..ca8aaa8 100644
--- a/src/test/java/org/apache/commons/text/StrBuilderTest.java
+++ b/src/test/java/org/apache/commons/text/StrBuilderTest.java
@@ -19,13 +19,13 @@ package org.apache.commons.text;
 
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.assertj.core.api.Assertions.fail;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.IOException;
@@ -37,6 +37,7 @@ import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.util.Arrays;
+
 import org.junit.jupiter.api.Test;
 
 /**
diff --git a/src/test/java/org/apache/commons/text/StrLookupTest.java b/src/test/java/org/apache/commons/text/StrLookupTest.java
index 1ebd0be..be0d0f5 100644
--- a/src/test/java/org/apache/commons/text/StrLookupTest.java
+++ b/src/test/java/org/apache/commons/text/StrLookupTest.java
@@ -16,9 +16,9 @@
  */
 package org.apache.commons.text;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/src/test/java/org/apache/commons/text/StrSubstitutorTest.java b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
index cde37d0..6ff8657 100644
--- a/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
+++ b/src/test/java/org/apache/commons/text/StrSubstitutorTest.java
@@ -18,11 +18,11 @@
 package org.apache.commons.text;
 
 import static org.assertj.core.api.Assertions.assertThatNullPointerException;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.HashMap;
diff --git a/src/test/java/org/apache/commons/text/StrTokenizerTest.java b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
index 72bb788..744e598 100644
--- a/src/test/java/org/apache/commons/text/StrTokenizerTest.java
+++ b/src/test/java/org/apache/commons/text/StrTokenizerTest.java
@@ -17,10 +17,10 @@
 
 package org.apache.commons.text;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Arrays;
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.NoSuchElementException;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -596,7 +597,7 @@ public class StrTokenizerTest {
         final StrTokenizer tok = new StrTokenizer();
         assertEquals(tok, tok.reset());
         assertEquals(tok, tok.reset(""));
-        assertEquals(tok, tok.reset(new char[0]));
+        assertEquals(tok, tok.reset(ArrayUtils.EMPTY_CHAR_ARRAY));
         assertEquals(tok, tok.setDelimiterChar(' '));
         assertEquals(tok, tok.setDelimiterString(" "));
         assertEquals(tok, tok.setDelimiterMatcher(null));
@@ -711,7 +712,7 @@ public class StrTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer(new char[0]);
+        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertFalse(tok.hasNext());
 
         tok = new StrTokenizer((char[]) null);
@@ -727,7 +728,7 @@ public class StrTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer(new char[0], ' ');
+        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ');
         assertFalse(tok.hasNext());
 
         tok = new StrTokenizer((char[]) null, ' ');
@@ -744,7 +745,7 @@ public class StrTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StrTokenizer(new char[0], ' ', '"');
+        tok = new StrTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"');
         assertFalse(tok.hasNext());
 
         tok = new StrTokenizer((char[]) null, ' ', '"');
diff --git a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
index 105406f..bf6b80a 100644
--- a/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/StringEscapeUtilsTest.java
@@ -18,11 +18,11 @@ package org.apache.commons.text;
 
 import static org.apache.commons.text.StringEscapeUtils.escapeXSI;
 import static org.apache.commons.text.StringEscapeUtils.unescapeXSI;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
diff --git a/src/test/java/org/apache/commons/text/StringTokenizerTest.java b/src/test/java/org/apache/commons/text/StringTokenizerTest.java
index 819ec89..675bf0d 100644
--- a/src/test/java/org/apache/commons/text/StringTokenizerTest.java
+++ b/src/test/java/org/apache/commons/text/StringTokenizerTest.java
@@ -20,13 +20,15 @@ package org.apache.commons.text;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.NoSuchElementException;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.text.matcher.StringMatcher;
 import org.apache.commons.text.matcher.StringMatcherFactory;
 import org.junit.jupiter.api.Test;
@@ -594,7 +596,7 @@ public class StringTokenizerTest {
         final StringTokenizer tok = new StringTokenizer();
         assertEquals(tok, tok.reset());
         assertEquals(tok, tok.reset(""));
-        assertEquals(tok, tok.reset(new char[0]));
+        assertEquals(tok, tok.reset(ArrayUtils.EMPTY_CHAR_ARRAY));
         assertEquals(tok, tok.setDelimiterChar(' '));
         assertEquals(tok, tok.setDelimiterString(" "));
         assertEquals(tok, tok.setDelimiterMatcher(null));
@@ -712,7 +714,7 @@ public class StringTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer(new char[0]);
+        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertFalse(tok.hasNext());
 
         tok = new StringTokenizer((char[]) null);
@@ -729,7 +731,7 @@ public class StringTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer(new char[0], ' ');
+        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ');
         assertFalse(tok.hasNext());
 
         tok = new StringTokenizer((char[]) null, ' ');
@@ -748,7 +750,7 @@ public class StringTokenizerTest {
         assertEquals("b", tok.next());
         assertFalse(tok.hasNext());
 
-        tok = new StringTokenizer(new char[0], ' ', '"');
+        tok = new StringTokenizer(ArrayUtils.EMPTY_CHAR_ARRAY, ' ', '"');
         assertFalse(tok.hasNext());
 
         tok = new StringTokenizer((char[]) null, ' ', '"');
diff --git a/src/test/java/org/apache/commons/text/TextStringBuilderAppendInsertTest.java b/src/test/java/org/apache/commons/text/TextStringBuilderAppendInsertTest.java
index 26870c5..ec96914 100644
--- a/src/test/java/org/apache/commons/text/TextStringBuilderAppendInsertTest.java
+++ b/src/test/java/org/apache/commons/text/TextStringBuilderAppendInsertTest.java
@@ -27,6 +27,7 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 
+import org.apache.commons.lang3.ArrayUtils;
 import org.junit.jupiter.api.Test;
 
 /**
@@ -472,7 +473,7 @@ public class TextStringBuilderAppendInsertTest {
         assertThat(sb.toString()).isEqualTo("NULL");
 
         sb = new TextStringBuilder();
-        sb.append(new char[0]);
+        sb.append(ArrayUtils.EMPTY_CHAR_ARRAY);
         assertThat(sb.toString()).isEqualTo("");
 
         sb.append(new char[]{'f', 'o', 'o'});
@@ -1351,7 +1352,7 @@ public class TextStringBuilderAppendInsertTest {
         sb.insert(0, (char[]) null);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
-        sb.insert(0, new char[0]);
+        sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
         sb.insert(0, new char[]{'f', 'o', 'o'});
@@ -1370,7 +1371,7 @@ public class TextStringBuilderAppendInsertTest {
         sb.insert(0, (char[]) null, 0, 0);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
-        sb.insert(0, new char[0], 0, 0);
+        sb.insert(0, ArrayUtils.EMPTY_CHAR_ARRAY, 0, 0);
         assertThat(sb.toString()).isEqualTo("barbaz");
 
         assertThrows(IndexOutOfBoundsException.class,
diff --git a/src/test/java/org/apache/commons/text/TextStringBuilderTest.java b/src/test/java/org/apache/commons/text/TextStringBuilderTest.java
index d659590..a41deaa 100644
--- a/src/test/java/org/apache/commons/text/TextStringBuilderTest.java
+++ b/src/test/java/org/apache/commons/text/TextStringBuilderTest.java
@@ -19,13 +19,13 @@ package org.apache.commons.text;
 
 import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import static org.assertj.core.api.Assertions.fail;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.IOException;
diff --git a/src/test/java/org/apache/commons/text/WordUtilsTest.java b/src/test/java/org/apache/commons/text/WordUtilsTest.java
index 03d8f6b..c37f826 100644
--- a/src/test/java/org/apache/commons/text/WordUtilsTest.java
+++ b/src/test/java/org/apache/commons/text/WordUtilsTest.java
@@ -16,14 +16,15 @@
  */
 package org.apache.commons.text;
 
-import org.apache.commons.lang3.StringUtils;
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit tests for {@link WordUtils} class.
@@ -197,8 +198,8 @@ public class WordUtilsTest {
     @Test
     public void testCapitalizeWithDelimiters_String() {
         assertThat(WordUtils.capitalize(null, null)).isNull();
-        assertThat(WordUtils.capitalize("", new char[0])).isEqualTo("");
-        assertThat(WordUtils.capitalize("  ", new char[0])).isEqualTo("  ");
+        assertThat(WordUtils.capitalize("", ArrayUtils.EMPTY_CHAR_ARRAY)).isEqualTo("");
+        assertThat(WordUtils.capitalize("  ", ArrayUtils.EMPTY_CHAR_ARRAY)).isEqualTo("  ");
 
         char[] chars = new char[] {'-', '+', ' ', '@'};
         assertThat(WordUtils.capitalize("I", chars)).isEqualTo("I");
@@ -240,8 +241,8 @@ public class WordUtilsTest {
     @Test
     public void testCapitalizeFullyWithDelimiters_String() {
         assertThat(WordUtils.capitalizeFully(null, null)).isNull();
-        assertThat(WordUtils.capitalizeFully("", new char[0])).isEqualTo("");
-        assertThat(WordUtils.capitalizeFully("  ", new char[0])).isEqualTo("  ");
+        assertThat(WordUtils.capitalizeFully("", ArrayUtils.EMPTY_CHAR_ARRAY)).isEqualTo("");
+        assertThat(WordUtils.capitalizeFully("  ", ArrayUtils.EMPTY_CHAR_ARRAY)).isEqualTo("  ");
 
         char[] chars = new char[] {'-', '+', ' ', '@'};
         assertThat(WordUtils.capitalizeFully("I", chars)).isEqualTo("I");
@@ -295,8 +296,8 @@ public class WordUtilsTest {
     @Test
     public void testUncapitalizeWithDelimiters_String() {
         assertThat(WordUtils.uncapitalize(null, null)).isNull();
-        assertThat(WordUtils.uncapitalize("", new char[0])).isEqualTo("");
-        assertThat(WordUtils.uncapitalize("  ", new char[0])).isEqualTo("  ");
+        assertThat(WordUtils.uncapitalize("", ArrayUtils.EMPTY_CHAR_ARRAY)).isEqualTo("");
+        assertThat(WordUtils.uncapitalize("  ", ArrayUtils.EMPTY_CHAR_ARRAY)).isEqualTo("  ");
 
         char[] chars = new char[] {'-', '+', ' ', '@'};
         assertThat(WordUtils.uncapitalize("I", chars)).isEqualTo("i");
@@ -343,7 +344,7 @@ public class WordUtilsTest {
         assertThat(WordUtils.initials("Kay O'Murphy", array)).isEqualTo("KO");
         assertThat(WordUtils.initials("i am here 123", array)).isEqualTo("iah1");
 
-        array = new char[0];
+        array = ArrayUtils.EMPTY_CHAR_ARRAY;
         assertThat(WordUtils.initials(null, array)).isNull();
         assertThat(WordUtils.initials("", array)).isEqualTo("");
         assertThat(WordUtils.initials("  ", array)).isEqualTo("");
diff --git a/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java b/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java
index 50916d7..ea771c1 100644
--- a/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java
+++ b/src/test/java/org/apache/commons/text/diff/StringsComparatorTest.java
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 package org.apache.commons.text.diff;
+import static org.assertj.core.api.Assertions.assertThat;
+
 import java.util.Arrays;
 import java.util.List;
 
@@ -22,8 +24,6 @@ import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 /**
  * Tests for the StringsComparator.
  */
diff --git a/src/test/java/org/apache/commons/text/lookup/ResourceBundleStringLookupTest.java b/src/test/java/org/apache/commons/text/lookup/ResourceBundleStringLookupTest.java
index 3977fbc..3c2d02c 100644
--- a/src/test/java/org/apache/commons/text/lookup/ResourceBundleStringLookupTest.java
+++ b/src/test/java/org/apache/commons/text/lookup/ResourceBundleStringLookupTest.java
@@ -17,8 +17,8 @@
 
 package org.apache.commons.text.lookup;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.ResourceBundle;
 
diff --git a/src/test/java/org/apache/commons/text/matcher/StringSubstitutorGetSetTest.java b/src/test/java/org/apache/commons/text/matcher/StringSubstitutorGetSetTest.java
index 244d6b5..2009bdf 100644
--- a/src/test/java/org/apache/commons/text/matcher/StringSubstitutorGetSetTest.java
+++ b/src/test/java/org/apache/commons/text/matcher/StringSubstitutorGetSetTest.java
@@ -17,9 +17,9 @@
 
 package org.apache.commons.text.matcher;
 
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.apache.commons.text.StringSubstitutor;
diff --git a/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java b/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java
index c229cb5..b7e0685 100644
--- a/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java
@@ -17,14 +17,15 @@
 
 package org.apache.commons.text.similarity;
 
-import org.junit.jupiter.api.Test;
-import java.util.HashMap;
-import java.util.Map;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.assertj.core.api.Assertions.within;
 
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
 
 public class CosineSimilarityTest {
 
diff --git a/src/test/java/org/apache/commons/text/similarity/IntersectionResultTest.java b/src/test/java/org/apache/commons/text/similarity/IntersectionResultTest.java
index c2477e0..7489f5e 100644
--- a/src/test/java/org/apache/commons/text/similarity/IntersectionResultTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/IntersectionResultTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.commons.text.similarity;
 
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
 import java.util.HashMap;
 import java.util.concurrent.ThreadLocalRandom;
 
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link IntersectionResult}.
  */
diff --git a/src/test/java/org/apache/commons/text/similarity/IntersectionSimilarityTest.java b/src/test/java/org/apache/commons/text/similarity/IntersectionSimilarityTest.java
index 8b4364c..c9f7049 100644
--- a/src/test/java/org/apache/commons/text/similarity/IntersectionSimilarityTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/IntersectionSimilarityTest.java
@@ -19,8 +19,6 @@ package org.apache.commons.text.similarity;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import org.junit.jupiter.api.Test;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -31,6 +29,8 @@ import java.util.Set;
 import java.util.function.Function;
 import java.util.regex.Pattern;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link IntersectionSimilarity}.
  */
diff --git a/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java
index 45ee27e..22446f4 100644
--- a/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/LevenshteinDistanceTest.java
@@ -16,11 +16,11 @@
  */
 package org.apache.commons.text.similarity;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link LevenshteinDistance}.
  */
diff --git a/src/test/java/org/apache/commons/text/similarity/LevenshteinResultsTest.java b/src/test/java/org/apache/commons/text/similarity/LevenshteinResultsTest.java
index 3c113c6..48363bb 100644
--- a/src/test/java/org/apache/commons/text/similarity/LevenshteinResultsTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/LevenshteinResultsTest.java
@@ -16,10 +16,10 @@
  */
 package org.apache.commons.text.similarity;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.junit.jupiter.api.Test;
+
 public class LevenshteinResultsTest {
 
     @Test
diff --git a/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java
index b0a8977..257b4fc 100644
--- a/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceDistanceTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.commons.text.similarity;
 
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link LongestCommonSubsequenceDistance}.
  */
diff --git a/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java
index 19b73a4..bd6824d 100644
--- a/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java
+++ b/src/test/java/org/apache/commons/text/similarity/LongestCommonSubsequenceTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.commons.text.similarity;
 
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link LongestCommonSubsequence}.
  */
diff --git a/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java
index fba9516..6bf8b20 100644
--- a/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java
+++ b/src/test/java/org/apache/commons/text/translate/AggregateTranslatorTest.java
@@ -16,14 +16,14 @@
  */
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.IOException;
 import java.io.StringWriter;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit tests for {@link AggregateTranslator}.
diff --git a/src/test/java/org/apache/commons/text/translate/CodePointTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/CodePointTranslatorTest.java
index ad513f7..e7fe55a 100644
--- a/src/test/java/org/apache/commons/text/translate/CodePointTranslatorTest.java
+++ b/src/test/java/org/apache/commons/text/translate/CodePointTranslatorTest.java
@@ -16,13 +16,13 @@
  */
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.IOException;
 import java.io.PipedReader;
 import java.io.PipedWriter;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
 
 public class CodePointTranslatorTest {
 
diff --git a/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java b/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java
index e4049f7..78d1d21 100644
--- a/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java
+++ b/src/test/java/org/apache/commons/text/translate/EntityArraysTest.java
@@ -17,13 +17,13 @@
 
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.BufferedReader;
 import java.io.FileReader;
 import java.util.Map;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit tests for {@link EntityArrays}.
diff --git a/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java
index 868ea40..8ca8e2f 100644
--- a/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java
+++ b/src/test/java/org/apache/commons/text/translate/LookupTranslatorTest.java
@@ -17,7 +17,8 @@
 
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 
 import java.io.IOException;
 import java.io.StringWriter;
@@ -25,8 +26,7 @@ import java.security.InvalidParameterException;
 import java.util.HashMap;
 import java.util.Map;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit tests for {@link LookupTranslator}.
diff --git a/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java b/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java
index 121136a..c3d0c5c 100644
--- a/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java
+++ b/src/test/java/org/apache/commons/text/translate/NumericEntityEscaperTest.java
@@ -17,10 +17,10 @@
 
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link NumericEntityEscaper}.
  */
diff --git a/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java b/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java
index 341cd63..a8bd26d 100644
--- a/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java
+++ b/src/test/java/org/apache/commons/text/translate/NumericEntityUnescaperTest.java
@@ -17,11 +17,11 @@
 
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link NumericEntityUnescaper}.
  */
diff --git a/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java b/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java
index 8e4462f..f9a3b4e 100644
--- a/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java
+++ b/src/test/java/org/apache/commons/text/translate/OctalUnescaperTest.java
@@ -17,10 +17,10 @@
 
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link OctalUnescaper}.
  */
diff --git a/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java b/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java
index 2f700c4..8b9bf02 100644
--- a/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java
+++ b/src/test/java/org/apache/commons/text/translate/SinglePassTranslatorTest.java
@@ -16,15 +16,15 @@
  */
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 
 import java.io.IOException;
 import java.io.StringWriter;
 import java.io.Writer;
 
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit test for {@link SinglePassTranslator}
diff --git a/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java b/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java
index 8f4bfe1..b8c75db 100644
--- a/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java
+++ b/src/test/java/org/apache/commons/text/translate/UnicodeEscaperTest.java
@@ -17,10 +17,10 @@
 
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
-
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.junit.jupiter.api.Test;
+
 /**
  * Unit tests for {@link UnicodeEscaper}.
  */
diff --git a/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java b/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java
index 3ba4a6d..6fdfdbc 100644
--- a/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java
+++ b/src/test/java/org/apache/commons/text/translate/UnicodeUnpairedSurrogateRemoverTest.java
@@ -16,12 +16,12 @@
  */
 package org.apache.commons.text.translate;
 
-import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.CharArrayWriter;
 import java.io.IOException;
 
-import static org.assertj.core.api.Assertions.assertThat;
+import org.junit.jupiter.api.Test;
 
 /**
  * Unit tests for {@link UnicodeUnpairedSurrogateRemover}.


[commons-text] 01/03: Sort members.

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git

commit e46cd90f9ab64ee942368357cd06fe9629f2dd9a
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jun 26 16:57:49 2020 -0400

    Sort members.
---
 .../org/apache/commons/text/TextStringBuilder.java | 3912 ++++++++++----------
 1 file changed, 1956 insertions(+), 1956 deletions(-)

diff --git a/src/main/java/org/apache/commons/text/TextStringBuilder.java b/src/main/java/org/apache/commons/text/TextStringBuilder.java
index 7798c9b..489e402 100644
--- a/src/main/java/org/apache/commons/text/TextStringBuilder.java
+++ b/src/main/java/org/apache/commons/text/TextStringBuilder.java
@@ -73,14 +73,180 @@ import org.apache.commons.text.matcher.StringMatcher;
 public class TextStringBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
 
     /**
-     * The size of the string {@code "false"}.
+     * Inner class to allow StrBuilder to operate as a reader.
      */
-    private static final int FALSE_STRING_SIZE = "false".length();
+    class StrBuilderReader extends Reader {
+        /** The last mark position. */
+        private int mark;
+        /** The current stream position. */
+        private int pos;
+
+        /**
+         * Default constructor.
+         */
+        StrBuilderReader() {
+            super();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void close() {
+            // do nothing
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void mark(final int readAheadLimit) {
+            mark = pos;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean markSupported() {
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int read() {
+            if (!ready()) {
+                return -1;
+            }
+            return TextStringBuilder.this.charAt(pos++);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public int read(final char[] b, final int off, int len) {
+            if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (len == 0) {
+                return 0;
+            }
+            if (pos >= TextStringBuilder.this.size()) {
+                return -1;
+            }
+            if (pos + len > size()) {
+                len = TextStringBuilder.this.size() - pos;
+            }
+            TextStringBuilder.this.getChars(pos, pos + len, b, off);
+            pos += len;
+            return len;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public boolean ready() {
+            return pos < TextStringBuilder.this.size();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void reset() {
+            pos = mark;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public long skip(long n) {
+            if (pos + n > TextStringBuilder.this.size()) {
+                n = TextStringBuilder.this.size() - pos;
+            }
+            if (n < 0) {
+                return 0;
+            }
+            pos += n;
+            return n;
+        }
+    }
 
     /**
-     * The size of the string {@code "true"}.
+     * Inner class to allow StrBuilder to operate as a writer.
      */
-    private static final int TRUE_STRING_SIZE = "true".length();
+    class StrBuilderWriter extends Writer {
+
+        /**
+         * Default constructor.
+         */
+        StrBuilderWriter() {
+            super();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void close() {
+            // do nothing
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void flush() {
+            // do nothing
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void write(final char[] cbuf) {
+            TextStringBuilder.this.append(cbuf);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void write(final char[] cbuf, final int off, final int len) {
+            TextStringBuilder.this.append(cbuf, off, len);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void write(final int c) {
+            TextStringBuilder.this.append((char) c);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void write(final String str) {
+            TextStringBuilder.this.append(str);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public void write(final String str, final int off, final int len) {
+            TextStringBuilder.this.append(str, off, len);
+        }
+    }
+
+    /**
+     * Inner class to allow StrBuilder to operate as a tokenizer.
+     */
+    class TextStringBuilderTokenizer extends StringTokenizer {
+
+        /**
+         * Default constructor.
+         */
+        TextStringBuilderTokenizer() {
+            super();
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public String getContent() {
+            final String str = super.getContent();
+            if (str == null) {
+                return TextStringBuilder.this.toString();
+            }
+            return str;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        protected List<String> tokenize(final char[] chars, final int offset, final int count) {
+            if (chars == null) {
+                return super.tokenize(TextStringBuilder.this.buffer, 0, TextStringBuilder.this.size());
+            }
+            return super.tokenize(chars, offset, count);
+        }
+    }
 
     /**
      * The extra capacity for new builders.
@@ -88,24 +254,34 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     static final int CAPACITY = 32;
 
     /**
+     * The size of the string {@code "false"}.
+     */
+    private static final int FALSE_STRING_SIZE = "false".length();
+
+    /**
      * Required for serialization support.
      *
      * @see java.io.Serializable
      */
     private static final long serialVersionUID = 1L;
 
+    /**
+     * The size of the string {@code "true"}.
+     */
+    private static final int TRUE_STRING_SIZE = "true".length();
+
     /** 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;
 
+    /** Current size of the buffer. */
+    private int size;
+
     /**
      * Constructor that creates an empty builder initial capacity 32 characters.
      */
@@ -144,486 +320,271 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * 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.
+     * Appends a boolean value to the string builder.
      *
-     * @param newLine
-     *            the new line text, null means use system default
+     * @param value
+     *            the value to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder setNewLineText(final String newLine) {
-        this.newLine = newLine;
+    public TextStringBuilder append(final boolean value) {
+        if (value) {
+            ensureCapacity(size + TRUE_STRING_SIZE);
+            buffer[size++] = 't';
+            buffer[size++] = 'r';
+            buffer[size++] = 'u';
+            buffer[size++] = 'e';
+        } else {
+            ensureCapacity(size + FALSE_STRING_SIZE);
+            buffer[size++] = 'f';
+            buffer[size++] = 'a';
+            buffer[size++] = 'l';
+            buffer[size++] = 's';
+            buffer[size++] = 'e';
+        }
         return this;
     }
 
     /**
-     * Gets the text to be appended when null is added.
+     * Appends a char value to the string builder.
      *
-     * @return The null text, null means no append
+     * @param ch
+     *            the value to append
+     * @return this, to enable chaining
      */
-    public String getNullText() {
-        return nullText;
+    @Override
+    public TextStringBuilder append(final char ch) {
+        final int len = length();
+        ensureCapacity(len + 1);
+        buffer[size++] = ch;
+        return this;
     }
 
     /**
-     * Sets the text to be appended when null is added.
+     * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
      *
-     * @param nullText
-     *            the null text, null means no append
+     * @param chars
+     *            the char array to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder setNullText(String nullText) {
-        if (nullText != null && nullText.isEmpty()) {
-            nullText = null;
+    public TextStringBuilder 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;
         }
-        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.
+     * 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 set to, must be zero or positive
+     *            the length to append, must be valid
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the length is negative
      */
-    public TextStringBuilder setLength(final int length) {
-        if (length < 0) {
-            throw new StringIndexOutOfBoundsException(length);
+    public TextStringBuilder append(final char[] chars, final int startIndex, final int length) {
+        if (chars == null) {
+            return appendNull();
         }
-        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';
-            }
+        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;
     }
 
     /**
-     * Gets the current size of the internal character array buffer.
+     * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
      *
-     * @return The capacity
+     * @param buf
+     *            the char buffer to append
+     * @return this, to enable chaining
      */
-    public int capacity() {
-        return buffer.length;
+    public TextStringBuilder 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;
     }
 
     /**
-     * Checks the capacity and ensures that it is at least the size specified.
+     * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
      *
-     * @param capacity
-     *            the capacity to ensure
+     * @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 TextStringBuilder ensureCapacity(final int capacity) {
-        if (capacity > buffer.length) {
-            final char[] old = buffer;
-            buffer = new char[capacity * 2];
-            System.arraycopy(old, 0, buffer, 0, size);
+    public TextStringBuilder 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;
     }
 
     /**
-     * Minimizes the capacity to the actual length of the string.
+     * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
      *
+     * @param seq
+     *            the CharSequence to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder minimizeCapacity() {
-        if (buffer.length > length()) {
-            final char[] old = buffer;
-            buffer = new char[length()];
-            System.arraycopy(old, 0, buffer, 0, size);
+    @Override
+    public TextStringBuilder append(final CharSequence seq) {
+        if (seq == null) {
+            return appendNull();
         }
-        return this;
+        if (seq instanceof TextStringBuilder) {
+            return append((TextStringBuilder) 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());
     }
 
     /**
-     * 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.
-     * </p>
+     * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
      *
-     * @return The length
+     * @param seq
+     *            the CharSequence to append
+     * @param startIndex
+     *            the start index, inclusive, must be valid
+     * @param endIndex
+     *            the end index, exclusive, must be valid
+     * @return this, to enable chaining
      */
-    public int size() {
-        return size;
+    @Override
+    public TextStringBuilder append(final CharSequence seq, final int startIndex, final int endIndex) {
+        if (seq == null) {
+            return appendNull();
+        }
+        if (endIndex <= 0) {
+            throw new StringIndexOutOfBoundsException("endIndex must be valid");
+        }
+        if (startIndex >= endIndex) {
+            throw new StringIndexOutOfBoundsException("endIndex must be greater than startIndex");
+        }
+        return append(seq.toString(), startIndex, endIndex - startIndex);
     }
 
     /**
-     * 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.
-     * </p>
+     * Appends a double value to the string builder using {@code String.valueOf}.
      *
-     * @return {@code true} if the size is {@code 0}.
+     * @param value
+     *            the value to append
+     * @return this, to enable chaining
      */
-    public boolean isEmpty() {
-        return size == 0;
+    public TextStringBuilder append(final double value) {
+        return append(String.valueOf(value));
     }
 
     /**
-     * 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()}
-     * followed by {@link #minimizeCapacity()}.
-     * </p>
-     * <p>
-     * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of
-     * Collections.
-     * </p>
+     * Appends a float value to the string builder using {@code String.valueOf}.
      *
+     * @param value
+     *            the value to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder clear() {
-        size = 0;
-        return this;
+    public TextStringBuilder append(final float value) {
+        return append(String.valueOf(value));
     }
 
     /**
-     * Gets the character at the specified index.
+     * Appends an int value to the string builder using {@code String.valueOf}.
      *
-     * @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
+     * @param value
+     *            the value to append
+     * @return this, to enable chaining
      */
-    @Override
-    public char charAt(final int index) {
-        if (index < 0 || index >= length()) {
-            throw new StringIndexOutOfBoundsException(index);
-        }
-        return buffer[index];
+    public TextStringBuilder append(final int value) {
+        return append(String.valueOf(value));
     }
 
     /**
-     * Sets the character at the specified index.
+     * Appends a long value to the string builder using {@code String.valueOf}.
      *
-     * @see #charAt(int)
-     * @see #deleteCharAt(int)
-     * @param index
-     *            the index to set
-     * @param ch
-     *            the new character
+     * @param value
+     *            the value to append
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the index is invalid
      */
-    public TextStringBuilder setCharAt(final int index, final char ch) {
-        if (index < 0 || index >= length()) {
-            throw new StringIndexOutOfBoundsException(index);
-        }
-        buffer[index] = ch;
-        return this;
+    public TextStringBuilder append(final long value) {
+        return append(String.valueOf(value));
     }
 
     /**
-     * Deletes the character at the specified index.
+     * Appends an object to this string builder. Appending null will call {@link #appendNull()}.
      *
-     * @see #charAt(int)
-     * @see #setCharAt(int, char)
-     * @param index
-     *            the index to delete
+     * @param obj
+     *            the object to append
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the index is invalid
      */
-    public TextStringBuilder deleteCharAt(final int index) {
-        if (index < 0 || index >= size) {
-            throw new StringIndexOutOfBoundsException(index);
+    public TextStringBuilder append(final Object obj) {
+        if (obj == null) {
+            return appendNull();
         }
-        deleteImpl(index, index + 1, 1);
-        return this;
+        if (obj instanceof CharSequence) {
+            return append((CharSequence) obj);
+        }
+        return append(obj.toString());
     }
 
     /**
-     * Copies the builder's character array into a new character array.
+     * Appends a string to this string builder. Appending null will call {@link #appendNull()}.
      *
-     * @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 CharBuffer} directly into underlying character buffer without
-     * making extra copies.
-     *
-     * @param charBuffer CharBuffer to read.
-     * @return The number of characters read.
-     * @throws IOException if an I/O error occurs.
-     *
-     * @see #appendTo(Appendable)
-     * @since 1.9
-     */
-    public int readFrom(final CharBuffer charBuffer) throws IOException {
-        final int oldSize = size;
-        final int remaining = charBuffer.remaining();
-        ensureCapacity(size + remaining);
-        charBuffer.get(buffer, size, remaining);
-        size += remaining;
-        return size - oldSize;
-    }
-
-    /**
-     * 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 {
-        if (readable instanceof Reader) {
-            return readFrom((Reader) readable);
-        } else if (readable instanceof CharBuffer) {
-            return readFrom((CharBuffer) readable);
-        } else {
-            final int oldSize = size;
-            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;
-        }
-    }
-
-    /**
-     * If possible, reads chars from the provided {@link Reader} directly into underlying character buffer without
-     * making extra copies.
-     *
-     * @param reader Reader to read.
-     * @return The number of characters read.
-     * @throws IOException if an I/O error occurs.
-     *
-     * @see #appendTo(Appendable)
-     * @since 1.9
-     */
-    public int readFrom(final Reader reader) throws IOException {
-        final int oldSize = size;
-        ensureCapacity(size + 1);
-        int read;
-        while ((read = reader.read(buffer, size, buffer.length - size)) != -1) {
-            size += read;
-            ensureCapacity(size + 1);
-        }
-        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 TextStringBuilder appendNewLine() {
-        if (newLine == null) {
-            append(System.lineSeparator());
-            return this;
-        }
-        return append(newLine);
-    }
-
-    /**
-     * Appends the text representing {@code null} to this string builder.
-     *
-     * @return this, to enable chaining
-     */
-    public TextStringBuilder 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 TextStringBuilder 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 TextStringBuilder append(final CharSequence seq) {
-        if (seq == null) {
-            return appendNull();
-        }
-        if (seq instanceof TextStringBuilder) {
-            return append((TextStringBuilder) 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 endIndex
-     *            the end index, exclusive, must be valid
-     * @return this, to enable chaining
-     */
-    @Override
-    public TextStringBuilder append(final CharSequence seq, final int startIndex, final int endIndex) {
-        if (seq == null) {
-            return appendNull();
-        }
-        if (endIndex <= 0) {
-            throw new StringIndexOutOfBoundsException("endIndex must be valid");
-        }
-        if (startIndex >= endIndex) {
-            throw new StringIndexOutOfBoundsException("endIndex must be greater than startIndex");
-        }
-        return append(seq.toString(), startIndex, endIndex - startIndex);
-    }
-
-    /**
-     * Appends a string to this string builder. Appending null will call {@link #appendNull()}.
-     *
-     * @param str
-     *            the string to append
-     * @return this, to enable chaining
+     * @param str
+     *            the string to append
+     * @return this, to enable chaining
      */
     public TextStringBuilder append(final String str) {
         if (str == null) {
@@ -684,63 +645,7 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * 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 TextStringBuilder 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 TextStringBuilder 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()}.
+     * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}.
      *
      * @param str
      *            the string buffer to append
@@ -893,155 +798,274 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
+     * 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 chars
-     *            the char array to append
+     * @param iterable
+     *            the iterable to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder 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;
+    public TextStringBuilder appendAll(final Iterable<?> iterable) {
+        if (iterable != null) {
+            for (final Object o : iterable) {
+                append(o);
+            }
         }
         return this;
     }
 
     /**
-     * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
+     * 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 chars
-     *            the char array to append
-     * @param startIndex
-     *            the start index, inclusive, must be valid
-     * @param length
-     *            the length to append, must be valid
+     * @param it
+     *            the iterator to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder 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;
+    public TextStringBuilder appendAll(final Iterator<?> it) {
+        if (it != null) {
+            while (it.hasNext()) {
+                append(it.next());
+            }
         }
         return this;
     }
 
     /**
-     * Appends a boolean value to the string builder.
+     * 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 value
-     *            the value to append
+     * @param <T>
+     *            the element type
+     * @param array
+     *            the array to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder append(final boolean value) {
-        if (value) {
-            ensureCapacity(size + TRUE_STRING_SIZE);
-            buffer[size++] = 't';
-            buffer[size++] = 'r';
-            buffer[size++] = 'u';
-            buffer[size++] = 'e';
-        } else {
-            ensureCapacity(size + FALSE_STRING_SIZE);
-            buffer[size++] = 'f';
-            buffer[size++] = 'a';
-            buffer[size++] = 'l';
-            buffer[size++] = 's';
-            buffer[size++] = 'e';
+    public <T> TextStringBuilder 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 @SuppressWarnings 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 a char value to the string builder.
+     * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the
+     * {@code int} value is used. If the formatted value is larger than the length, the left hand side is lost.
      *
-     * @param ch
+     * @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
      */
-    @Override
-    public TextStringBuilder append(final char ch) {
-        final int len = length();
-        ensureCapacity(len + 1);
-        buffer[size++] = ch;
-        return this;
+    public TextStringBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
+        return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
     }
 
     /**
-     * Appends an int value to the string builder using {@code String.valueOf}.
+     * Appends an object to the builder padding on the left to a fixed width. The {@code toString} 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 value
-     *            the value to append
+     * @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 TextStringBuilder append(final int value) {
-        return append(String.valueOf(value));
+    public TextStringBuilder 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 a long value to the string builder using {@code String.valueOf}.
+     * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the
+     * {@code int} 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 TextStringBuilder append(final long value) {
-        return append(String.valueOf(value));
+    public TextStringBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
+        return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
     }
 
     /**
-     * Appends a float value to the string builder using {@code String.valueOf}.
+     * Appends an object to the builder padding on the right to a fixed length. The {@code toString} 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 value
-     *            the value to append
+     * @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 TextStringBuilder append(final float value) {
-        return append(String.valueOf(value));
+    public TextStringBuilder 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 a double value to the string builder using {@code String.valueOf}.
+     * 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 TextStringBuilder append(final double value) {
-        return append(String.valueOf(value));
+    public TextStringBuilder appendln(final boolean value) {
+        return append(value).appendNewLine();
     }
 
-    // -----------------------------------------------------------------------
     /**
-     * Appends an object followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
+     * Appends a char value followed by a new line to the string builder.
      *
-     * @param obj
-     *            the object to append
+     * @param ch
+     *            the value to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendln(final Object obj) {
-        return append(obj).appendNewLine();
+    public TextStringBuilder appendln(final char ch) {
+        return append(ch).appendNewLine();
     }
 
     /**
-     * Appends a string followed by a new line to this string builder. Appending null will call {@link #appendNull()}.
-     *
+     * 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 TextStringBuilder 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 TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) {
+        return append(chars, startIndex, length).appendNewLine();
+    }
+
+    /**
+     * Appends a double value followed by a new line to the string builder using {@code String.valueOf}.
+     *
+     * @param value
+     *            the value to append
+     * @return this, to enable chaining
+     */
+    public TextStringBuilder appendln(final double value) {
+        return append(value).appendNewLine();
+    }
+
+    /**
+     * Appends a float value followed by a new line to the string builder using {@code String.valueOf}.
+     *
+     * @param value
+     *            the value to append
+     * @return this, to enable chaining
+     */
+    public TextStringBuilder appendln(final float value) {
+        return append(value).appendNewLine();
+    }
+
+    /**
+     * Appends an int value followed by a new line to the string builder using {@code String.valueOf}.
+     *
+     * @param value
+     *            the value to append
+     * @return this, to enable chaining
+     */
+    public TextStringBuilder 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}.
+     *
+     * @param value
+     *            the value to append
+     * @return this, to enable chaining
+     */
+    public TextStringBuilder appendln(final long value) {
+        return append(value).appendNewLine();
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * 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 TextStringBuilder 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
@@ -1093,46 +1117,46 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Appends a string builder followed by a new line to this string builder. Appending null will call
+     * 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 builder to append
+     *            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 TextStringBuilder appendln(final StringBuilder str) {
-        return append(str).appendNewLine();
+    public TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
+        return append(str, startIndex, length).appendNewLine();
     }
 
     /**
-     * Appends part of a string builder followed by a new line to this string builder. Appending null will call
+     * 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
-     * @param startIndex
-     *            the start index, inclusive, must be valid
-     * @param length
-     *            the length to append, must be valid
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
-        return append(str, startIndex, length).appendNewLine();
+    public TextStringBuilder appendln(final StringBuilder str) {
+        return append(str).appendNewLine();
     }
 
     /**
-     * Appends part of a string buffer followed by a new line to this string builder. Appending null will call
+     * 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
+     *            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 TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
+    public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
         return append(str, startIndex, length).appendNewLine();
     }
 
@@ -1165,177 +1189,250 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Appends a char array followed by a new line to the string builder. Appending null will call
-     * {@link #appendNull()}.
+     * 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.
      *
-     * @param chars
-     *            the char array to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendln(final char[] chars) {
-        return append(chars).appendNewLine();
+    public TextStringBuilder appendNewLine() {
+        if (newLine == null) {
+            append(System.lineSeparator());
+            return this;
+        }
+        return append(newLine);
     }
 
     /**
-     * Appends a char array followed by a new line to the string builder. Appending null will call
-     * {@link #appendNull()}.
+     * Appends the text representing {@code null} to this string builder.
      *
-     * @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 TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) {
-        return append(chars, startIndex, length).appendNewLine();
+    public TextStringBuilder appendNull() {
+        if (nullText == null) {
+            return this;
+        }
+        return append(nullText);
     }
 
     /**
-     * Appends a boolean value followed by a new line to the string builder.
+     * Appends the pad character to the builder the specified number of times.
      *
-     * @param value
-     *            the value to append
+     * @param length
+     *            the length to append, negative means no append
+     * @param padChar
+     *            the character to append
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendln(final boolean value) {
-        return append(value).appendNewLine();
+    public TextStringBuilder 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 a char value followed by a new line to the string builder.
+     * 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.
+     * </p>
      *
-     * @param ch
-     *            the value to append
-     * @return this, to enable chaining
-     */
-    public TextStringBuilder 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}.
+     * <pre>
+     * for (Iterator it = list.iterator(); it.hasNext();) {
+     *     appendSeparator(',');
+     *     append(it.next());
+     * }
+     * </pre>
      *
-     * @param value
-     *            the value to append
+     * <p>
+     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
+     * </p>
+     *
+     * @param separator
+     *            the separator to use
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendln(final int value) {
-        return append(value).appendNewLine();
+    public TextStringBuilder appendSeparator(final char separator) {
+        if (size() > 0) {
+            append(separator);
+        }
+        return this;
     }
 
     /**
-     * Appends a long value followed by a new line to the string builder using {@code String.valueOf}.
+     * 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
      *
-     * @param value
-     *            the value to append
+     * 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 TextStringBuilder appendln(final long value) {
-        return append(value).appendNewLine();
+    public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
+        if (size() > 0) {
+            append(standard);
+        } else {
+            append(defaultIfEmpty);
+        }
+        return this;
     }
 
     /**
-     * Appends a float value followed by a new line to the string builder using {@code String.valueOf}.
+     * 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>
      *
-     * @param value
-     *            the value to append
+     * <pre>
+     * for (int i = 0; i &lt; list.size(); i++) {
+     *     appendSeparator(",", i);
+     *     append(list.get(i));
+     * }
+     * </pre>
+     *
+     * <p>
+     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
+     * </p>
+     *
+     * @param separator
+     *            the separator to use
+     * @param loopIndex
+     *            the loop index
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendln(final float value) {
-        return append(value).appendNewLine();
+    public TextStringBuilder appendSeparator(final char separator, final int loopIndex) {
+        if (loopIndex > 0) {
+            append(separator);
+        }
+        return this;
     }
 
     /**
-     * Appends a double value followed by a new line to the string builder using {@code String.valueOf}.
+     * 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.
+     * </p>
      *
-     * @param value
-     *            the value to append
-     * @return this, to enable chaining
-     */
-    public TextStringBuilder 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)}.
+     * <pre>
+     * for (Iterator it = list.iterator(); it.hasNext();) {
+     *     appendSeparator(",");
+     *     append(it.next());
+     * }
+     * </pre>
      *
-     * @param <T>
-     *            the element type
-     * @param array
-     *            the array to append
+     * <p>
+     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
+     * </p>
+     *
+     * @param separator
+     *            the separator to use, null means no separator
      * @return this, to enable chaining
      */
-    public <T> TextStringBuilder 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 @SuppressWarnings 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;
+    public TextStringBuilder appendSeparator(final String separator) {
+        return appendSeparator(separator, null);
     }
 
     /**
-     * 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)}.
+     * 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>
      *
-     * @param iterable
-     *            the iterable to append
+     * <pre>
+     * for (int i = 0; i &lt; list.size(); i++) {
+     *     appendSeparator(",", i);
+     *     append(list.get(i));
+     * }
+     * </pre>
+     *
+     * <p>
+     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
+     * </p>
+     *
+     * @param separator
+     *            the separator to use, null means no separator
+     * @param loopIndex
+     *            the loop index
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendAll(final Iterable<?> iterable) {
-        if (iterable != null) {
-            for (final Object o : iterable) {
-                append(o);
-            }
+    public TextStringBuilder appendSeparator(final String separator, final int loopIndex) {
+        if (separator != null && loopIndex > 0) {
+            append(separator);
         }
         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)}.
+     * 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
      *
-     * @param it
-     *            the iterator to append
+     * 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
+     * </p>
+     *
+     * <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 TextStringBuilder appendAll(final Iterator<?> it) {
-        if (it != null) {
-            while (it.hasNext()) {
-                append(it.next());
-            }
+    public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
+        final String str = isEmpty() ? defaultIfEmpty : standard;
+        if (str != null) {
+            append(str);
         }
         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)}.
+     * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}.
+     * <p>
+     * This method tries to avoid doing any extra copies of contents.
+     * </p>
      *
-     * @param array
-     *            the array to append
-     * @param separator
-     *            the separator to use, null means no separator
-     * @return this, to enable chaining
+     * @param appendable
+     *            the appendable to append data to
+     * @throws IOException
+     *             if an I/O error occurs
+     *
+     * @see #readFrom(Readable)
      */
-    public TextStringBuilder 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]);
-            }
+    public void appendTo(final Appendable appendable) throws IOException {
+        if (appendable instanceof Writer) {
+            ((Writer) appendable).write(buffer, 0, size);
+        } else if (appendable instanceof StringBuilder) {
+            ((StringBuilder) appendable).append(buffer, 0, size);
+        } else if (appendable instanceof StringBuffer) {
+            ((StringBuffer) appendable).append(buffer, 0, size);
+        } else if (appendable instanceof CharBuffer) {
+            ((CharBuffer) appendable).put(buffer, 0, size);
+        } else {
+            appendable.append(this);
         }
-        return this;
     }
 
     /**
@@ -1386,520 +1483,358 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * 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.
-     * </p>
-     *
-     * <pre>
-     * for (Iterator it = list.iterator(); it.hasNext();) {
-     *     appendSeparator(",");
-     *     append(it.next());
-     * }
-     * </pre>
-     *
-     * <p>
-     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
-     * </p>
+     * 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 TextStringBuilder appendSeparator(final String separator) {
-        return appendSeparator(separator, null);
+    public TextStringBuilder 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 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)}.
+     * Gets the contents of this builder as a Reader.
      * <p>
-     * This method is for example useful for constructing queries
+     * This method allows the contents of the builder to be read using any standard method that expects a Reader.
+     * </p>
+     * <p>
+     * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read
+     * away.
+     * </p>
+     * <p>
+     * The internal character array is shared between the builder and the reader. This allows you to append to the
+     * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization
+     * occurs, so you must perform all operations with the builder and the reader in one thread.
+     * </p>
+     * <p>
+     * The returned reader supports marking, and ignores the flush method.
      * </p>
      *
-     * <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
+     * @return a reader that reads from this builder
      */
-    public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
-        final String str = isEmpty() ? defaultIfEmpty : standard;
-        if (str != null) {
-            append(str);
-        }
-        return this;
+    public Reader asReader() {
+        return new StrBuilderReader();
     }
 
     /**
-     * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}.
+     * Creates a tokenizer that can tokenize the contents of this builder.
      * <p>
-     * This method is useful for adding a separator each time around the loop except the first.
+     * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to
+     * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the
+     * tokenizer class, before retrieving the tokens.
+     * </p>
+     * <p>
+     * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within
+     * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be
+     * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example:
      * </p>
      *
      * <pre>
-     * for (Iterator it = list.iterator(); it.hasNext();) {
-     *     appendSeparator(',');
-     *     append(it.next());
-     * }
+     * StrBuilder b = new StrBuilder();
+     * b.append("a b ");
+     * StrTokenizer t = b.asTokenizer();
+     * String[] tokens1 = t.getTokenArray(); // returns a,b
+     * b.append("c d ");
+     * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
+     * t.reset(); // reset causes builder changes to be picked up
+     * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
      * </pre>
      *
      * <p>
-     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
+     * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to
+     * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes.
+     * </p>
+     * <p>
+     * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will
+     * break the link with the builder.
      * </p>
      *
-     * @param separator
-     *            the separator to use
-     * @return this, to enable chaining
+     * @return a tokenizer that is linked to this builder
      */
-    public TextStringBuilder appendSeparator(final char separator) {
-        if (size() > 0) {
-            append(separator);
-        }
-        return this;
+    public StringTokenizer asTokenizer() {
+        return new TextStringBuilderTokenizer();
     }
 
     /**
-     * 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)}.
+     * Gets this builder as a Writer that can be written to.
+     * <p>
+     * This method allows you to populate the contents of the builder using any standard method that takes a Writer.
+     * </p>
+     * <p>
+     * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is
+     * available at any time using the methods of the {@code StrBuilder}.
+     * </p>
+     * <p>
+     * The internal character array is shared between the builder and the writer. This allows you to intermix calls that
+     * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no
+     * synchronization occurs, so you must perform all operations with the builder and the writer in one thread.
+     * </p>
+     * <p>
+     * The returned writer ignores the close and flush methods.
+     * </p>
      *
-     * @param standard
-     *            the separator if builder is not empty
-     * @param defaultIfEmpty
-     *            the separator if builder is empty
-     * @return this, to enable chaining
+     * @return a writer that populates this builder
      */
-    public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
-        if (size() > 0) {
-            append(standard);
-        } else {
-            append(defaultIfEmpty);
-        }
-        return this;
+    public Writer asWriter() {
+        return new StrBuilderWriter();
     }
 
     /**
-     * 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>
+     * Implement the {@link Builder} interface.
      *
-     * <pre>
-     * for (int i = 0; i &lt; list.size(); i++) {
-     *     appendSeparator(",", i);
-     *     append(list.get(i));
-     * }
-     * </pre>
+     * @return The builder as a String
+     * @see #toString()
+     */
+    @Override
+    public String build() {
+        return toString();
+    }
+
+    /**
+     * Gets the current size of the internal character array buffer.
      *
-     * <p>
-     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
-     * </p>
+     * @return The capacity
+     */
+    public int capacity() {
+        return buffer.length;
+    }
+
+    /**
+     * Gets the character at the specified index.
      *
-     * @param separator
-     *            the separator to use, null means no separator
-     * @param loopIndex
-     *            the loop index
-     * @return this, to enable chaining
+     * @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
      */
-    public TextStringBuilder appendSeparator(final String separator, final int loopIndex) {
-        if (separator != null && loopIndex > 0) {
-            append(separator);
+    @Override
+    public char charAt(final int index) {
+        if (index < 0 || index >= length()) {
+            throw new StringIndexOutOfBoundsException(index);
         }
-        return this;
+        return buffer[index];
     }
 
     /**
-     * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using
-     * {@link #append(char)}.
+     * Clears the string builder (convenience Collections API style method).
      * <p>
-     * This method is useful for adding a separator each time around the loop except the first.
+     * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()}
+     * followed by {@link #minimizeCapacity()}.
      * </p>
-     *
-     * <pre>
-     * for (int i = 0; i &lt; list.size(); i++) {
-     *     appendSeparator(",", i);
-     *     append(list.get(i));
-     * }
-     * </pre>
-     *
      * <p>
-     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
+     * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of
+     * Collections.
      * </p>
      *
-     * @param separator
-     *            the separator to use
-     * @param loopIndex
-     *            the loop index
      * @return this, to enable chaining
      */
-    public TextStringBuilder appendSeparator(final char separator, final int loopIndex) {
-        if (loopIndex > 0) {
-            append(separator);
-        }
+    public TextStringBuilder clear() {
+        size = 0;
         return this;
     }
 
     /**
-     * Appends the pad character to the builder the specified number of times.
+     * Checks if the string builder contains the specified char.
      *
-     * @param length
-     *            the length to append, negative means no append
-     * @param padChar
-     *            the character to append
-     * @return this, to enable chaining
+     * @param ch
+     *            the character to find
+     * @return true if the builder contains the character
      */
-    public TextStringBuilder appendPadding(final int length, final char padChar) {
-        if (length >= 0) {
-            ensureCapacity(size + length);
-            for (int i = 0; i < length; i++) {
-                buffer[size++] = padChar;
+    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 this;
+        return false;
     }
 
     /**
-     * Appends an object to the builder padding on the left to a fixed width. The {@code toString} 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.
+     * Checks if the string builder contains the specified string.
      *
-     * @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
+     * @param str
+     *            the string to find
+     * @return true if the builder contains the string
      */
-    public TextStringBuilder 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;
+    public boolean contains(final String str) {
+        return indexOf(str, 0) >= 0;
     }
 
     /**
-     * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the
-     * {@code int} value is used. If the formatted value is larger than the length, the left hand side is lost.
+     * Checks if the string builder contains a string matched using the specified matcher.
+     * <p>
+     * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for
+     * the character 'a' followed by a number.
+     * </p>
      *
-     * @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
+     * @param matcher
+     *            the matcher to use, null returns -1
+     * @return true if the matcher finds a match in the builder
      */
-    public TextStringBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
-        return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
+    public boolean contains(final StringMatcher matcher) {
+        return indexOf(matcher, 0) >= 0;
     }
 
     /**
-     * Appends an object to the builder padding on the right to a fixed length. The {@code toString} 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.
+     * Deletes the characters between the two specified indices.
      *
-     * @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
+     * @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 TextStringBuilder 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;
+    public TextStringBuilder delete(final int startIndex, int endIndex) {
+        endIndex = validateRange(startIndex, endIndex);
+        final int len = endIndex - startIndex;
+        if (len > 0) {
+            deleteImpl(startIndex, endIndex, len);
         }
         return this;
     }
 
     /**
-     * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the
-     * {@code int} value is used. If the object is larger than the length, the right hand side is lost.
+     * Deletes the character wherever it occurs in the builder.
      *
-     * @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
+     * @param ch
+     *            the character to delete
      * @return this, to enable chaining
      */
-    public TextStringBuilder 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 TextStringBuilder 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 TextStringBuilder 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);
+    public TextStringBuilder 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;
     }
 
     /**
-     * Inserts the character array into this builder. Inserting null will use the stored null text value.
+     * Deletes the string wherever it occurs in the builder.
      *
-     * @param index
-     *            the index to add at, must be valid
-     * @param chars
-     *            the char array to insert
+     * @param str
+     *            the string to delete, null causes no action
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the index is invalid
      */
-    public TextStringBuilder insert(final int index, final char[] chars) {
-        validateIndex(index);
-        if (chars == null) {
-            return insert(index, nullText);
-        }
-        final int len = chars.length;
+    public TextStringBuilder deleteAll(final String str) {
+        final int len = str == null ? 0 : str.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;
+            int index = indexOf(str, 0);
+            while (index >= 0) {
+                deleteImpl(index, index + len, len);
+                index = indexOf(str, index);
+            }
         }
         return this;
     }
 
     /**
-     * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
+     * Deletes all parts of the builder that the matcher matches.
+     * <p>
+     * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all
+     * occurrences where the character 'a' is followed by a number.
      *
-     * @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
+     * @param matcher
+     *            the matcher to use to find the deletion, null causes no action
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if any index is invalid
      */
-    public TextStringBuilder 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;
+    public TextStringBuilder deleteAll(final StringMatcher matcher) {
+        return replace(matcher, null, 0, size, -1);
     }
 
     /**
-     * Inserts the value into this builder.
+     * Deletes the character at the specified index.
      *
+     * @see #charAt(int)
+     * @see #setCharAt(int, char)
      * @param index
-     *            the index to add at, must be valid
-     * @param value
-     *            the value to insert
+     *            the index to delete
      * @return this, to enable chaining
      * @throws IndexOutOfBoundsException
      *             if the index is invalid
      */
-    public TextStringBuilder insert(int index, final boolean value) {
-        validateIndex(index);
-        if (value) {
-            ensureCapacity(size + TRUE_STRING_SIZE);
-            System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index);
-            buffer[index++] = 't';
-            buffer[index++] = 'r';
-            buffer[index++] = 'u';
-            buffer[index] = 'e';
-            size += TRUE_STRING_SIZE;
-        } else {
-            ensureCapacity(size + FALSE_STRING_SIZE);
-            System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index);
-            buffer[index++] = 'f';
-            buffer[index++] = 'a';
-            buffer[index++] = 'l';
-            buffer[index++] = 's';
-            buffer[index] = 'e';
-            size += FALSE_STRING_SIZE;
+    public TextStringBuilder deleteCharAt(final int index) {
+        if (index < 0 || index >= size) {
+            throw new StringIndexOutOfBoundsException(index);
         }
+        deleteImpl(index, index + 1, 1);
         return this;
     }
 
     /**
-     * Inserts the value into this builder.
+     * Deletes the character wherever it occurs in the builder.
      *
-     * @param index
-     *            the index to add at, must be valid
-     * @param value
-     *            the value to insert
+     * @param ch
+     *            the character to delete
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the index is invalid
      */
-    public TextStringBuilder 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++;
+    public TextStringBuilder deleteFirst(final char ch) {
+        for (int i = 0; i < size; i++) {
+            if (buffer[i] == ch) {
+                deleteImpl(i, i + 1, 1);
+                break;
+            }
+        }
         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 TextStringBuilder 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 TextStringBuilder insert(final int index, final long value) {
-        return insert(index, String.valueOf(value));
-    }
-
-    /**
-     * Inserts the value into this builder.
+     * Deletes the string wherever it occurs in the builder.
      *
-     * @param index
-     *            the index to add at, must be valid
-     * @param value
-     *            the value to insert
+     * @param str
+     *            the string to delete, null causes no action
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the index is invalid
      */
-    public TextStringBuilder insert(final int index, final float value) {
-        return insert(index, String.valueOf(value));
+    public TextStringBuilder 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;
     }
 
     /**
-     * Inserts the value into this builder.
+     * Deletes the first match within the builder using the specified matcher.
+     * <p>
+     * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete
+     * where the character 'a' is followed by a number.
      *
-     * @param index
-     *            the index to add at, must be valid
-     * @param value
-     *            the value to insert
+     * @param matcher
+     *            the matcher to use to find the deletion, null causes no action
      * @return this, to enable chaining
-     * @throws IndexOutOfBoundsException
-     *             if the index is invalid
      */
-    public TextStringBuilder insert(final int index, final double value) {
-        return insert(index, String.valueOf(value));
+    public TextStringBuilder deleteFirst(final StringMatcher matcher) {
+        return replace(matcher, null, 0, size, 1);
     }
 
     /**
@@ -1920,766 +1855,560 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Deletes the characters between the two specified indices.
+     * Checks whether this builder ends with the specified string.
+     * <p>
+     * Note that this method handles null input quietly, unlike String.
+     * </p>
      *
-     * @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
+     * @param str
+     *            the string to search for, null returns false
+     * @return true if the builder ends with the string
      */
-    public TextStringBuilder delete(final int startIndex, int endIndex) {
-        endIndex = validateRange(startIndex, endIndex);
-        final int len = endIndex - startIndex;
-        if (len > 0) {
-            deleteImpl(startIndex, endIndex, len);
+    public boolean endsWith(final String str) {
+        if (str == null) {
+            return false;
         }
-        return this;
-    }
-
-    /**
-     * Deletes the character wherever it occurs in the builder.
-     *
-     * @param ch
-     *            the character to delete
-     * @return this, to enable chaining
-     */
-    public TextStringBuilder 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;
+        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 this;
+        return true;
     }
 
     /**
-     * Deletes the character wherever it occurs in the builder.
+     * Checks the capacity and ensures that it is at least the size specified.
      *
-     * @param ch
-     *            the character to delete
+     * @param capacity
+     *            the capacity to ensure
      * @return this, to enable chaining
      */
-    public TextStringBuilder deleteFirst(final char ch) {
-        for (int i = 0; i < size; i++) {
-            if (buffer[i] == ch) {
-                deleteImpl(i, i + 1, 1);
-                break;
-            }
+    public TextStringBuilder 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;
     }
 
     /**
-     * Deletes the string wherever it occurs in the builder.
+     * Checks the contents of this builder against another to see if they contain the same character content.
      *
-     * @param str
-     *            the string to delete, null causes no action
-     * @return this, to enable chaining
+     * @param obj
+     *            the object to check, null returns false
+     * @return true if the builders contain the same characters in the same order
      */
-    public TextStringBuilder 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;
+    @Override
+    public boolean equals(final Object obj) {
+        return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj);
     }
 
     /**
-     * Deletes the string wherever it occurs in the builder.
+     * Checks the contents of this builder against another to see if they contain the same character content.
      *
-     * @param str
-     *            the string to delete, null causes no action
-     * @return this, to enable chaining
+     * @param other
+     *            the object to check, null returns false
+     * @return true if the builders contain the same characters in the same order
      */
-    public TextStringBuilder 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);
+    public boolean equals(final TextStringBuilder other) {
+        if (this == other) {
+            return true;
+        }
+        if (other == null) {
+            return false;
+        }
+        if (this.size != other.size) {
+            return false;
+        }
+        final char[] thisBuf = this.buffer;
+        final char[] otherBuf = other.buffer;
+        for (int i = size - 1; i >= 0; i--) {
+            if (thisBuf[i] != otherBuf[i]) {
+                return false;
             }
         }
-        return this;
+        return true;
     }
 
     /**
-     * Deletes all parts of the builder that the matcher matches.
-     * <p>
-     * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all
-     * occurrences where the character 'a' is followed by a number.
+     * Checks the contents of this builder against another to see if they contain the same character content ignoring
+     * case.
      *
-     * @param matcher
-     *            the matcher to use to find the deletion, null causes no action
-     * @return this, to enable chaining
+     * @param other
+     *            the object to check, null returns false
+     * @return true if the builders contain the same characters in the same order
      */
-    public TextStringBuilder deleteAll(final StringMatcher matcher) {
-        return replace(matcher, null, 0, size, -1);
+    public boolean equalsIgnoreCase(final TextStringBuilder other) {
+        if (this == other) {
+            return true;
+        }
+        if (this.size != other.size) {
+            return false;
+        }
+        final char[] thisBuf = this.buffer;
+        final char[] otherBuf = other.buffer;
+        for (int i = size - 1; i >= 0; i--) {
+            final char c1 = thisBuf[i];
+            final char c2 = otherBuf[i];
+            if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
+                return false;
+            }
+        }
+        return true;
     }
 
     /**
-     * Deletes the first match within the builder using the specified matcher.
-     * <p>
-     * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete
-     * where the character 'a' is followed by a number.
+     * Copies the character array into the specified array.
      *
-     * @param matcher
-     *            the matcher to use to find the deletion, null causes no action
-     * @return this, to enable chaining
+     * @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 TextStringBuilder deleteFirst(final StringMatcher matcher) {
-        return replace(matcher, null, 0, size, 1);
+    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;
     }
 
     /**
-     * Internal method to delete a range without validation.
+     * Copies the character array into the specified array.
      *
      * @param startIndex
-     *            the start index, must be valid
+     *            first index to copy, inclusive, 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
+     *            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
      */
-    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;
+    public void getChars(final int startIndex, final int endIndex, final char[] destination,
+            final int destinationIndex) {
+        if (startIndex < 0) {
+            throw new StringIndexOutOfBoundsException(startIndex);
         }
-        if (insertLen > 0) {
-            insertStr.getChars(0, insertLen, buffer, 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);
     }
 
     /**
-     * Replaces a portion of the string builder with another string. The length of the inserted string does not have to
-     * match the removed length.
+     * Gets the text to be appended when a new line is added.
      *
-     * @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
+     * @return The new line text, null means use system default
      */
-    public TextStringBuilder 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;
+    public String getNewLineText() {
+        return newLine;
     }
 
     /**
-     * Replaces the search character with the replace character throughout the builder.
+     * Gets the text to be appended when null is added.
      *
-     * @param search
-     *            the search character
-     * @param replace
-     *            the replace character
-     * @return this, to enable chaining
+     * @return The null text, null means no append
      */
-    public TextStringBuilder 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;
+    public String getNullText() {
+        return nullText;
     }
 
     /**
-     * Replaces the first instance of the search character with the replace character in the builder.
+     * Gets a suitable hash code for this builder.
      *
-     * @param search
-     *            the search character
-     * @param replace
-     *            the replace character
-     * @return this, to enable chaining
+     * @return a hash code
      */
-    public TextStringBuilder 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;
-                }
-            }
+    @Override
+    public int hashCode() {
+        final char[] buf = buffer;
+        int hash = 0;
+        for (int i = size - 1; i >= 0; i--) {
+            hash = 31 * hash + buf[i];
         }
-        return this;
+        return hash;
     }
 
     /**
-     * Replaces the search string with the replace string throughout the builder.
+     * Searches the string builder to find the first reference to the specified char.
      *
-     * @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
+     * @param ch
+     *            the character to find
+     * @return The first index of the character, or -1 if not found
      */
-    public TextStringBuilder 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;
+    public int indexOf(final char ch) {
+        return indexOf(ch, 0);
     }
 
     /**
-     * Replaces the first instance of the search string with the replace string.
+     * Searches the string builder to find the first reference to the specified char.
      *
-     * @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
+     * @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 TextStringBuilder 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);
+    public int indexOf(final char ch, int startIndex) {
+        startIndex = Math.max(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 this;
+        return -1;
     }
 
     /**
-     * Replaces all matches within the builder with the replace string.
+     * Searches the string builder to find the first reference to the specified string.
      * <p>
-     * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all
-     * occurrences where the character 'a' is followed by a number.
-     * </p>
+     * Note that a null input string will return -1, whereas the JDK throws an exception.
      *
-     * @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
+     * @param str
+     *            the string to find, null returns -1
+     * @return The first index of the string, or -1 if not found
      */
-    public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) {
-        return replace(matcher, replaceStr, 0, size, -1);
+    public int indexOf(final String str) {
+        return indexOf(str, 0);
     }
 
     /**
-     * Replaces the first match within the builder with the replace string.
+     * Searches the string builder to find the first reference to the specified string starting searching from the given
+     * index.
      * <p>
-     * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace
-     * where the character 'a' is followed by a number.
+     * Note that a null input string will return -1, whereas the JDK throws an exception.
      * </p>
      *
-     * @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
+     * @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 TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) {
-        return replace(matcher, replaceStr, 0, size, 1);
+    public int indexOf(final String str, int startIndex) {
+        startIndex = Math.max(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;
     }
 
     /**
-     * Advanced search and replaces within the builder using a matcher.
+     * Searches the string builder using the matcher to find the first match.
      * <p>
-     * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all
-     * occurrences where the character 'a' is followed by a number.
+     * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
+     * character 'a' followed by a number.
      * </p>
      *
      * @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
+     *            the matcher to use, null returns -1
+     * @return The first index matched, or -1 if not found
      */
-    public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex,
-            int endIndex, final int replaceCount) {
-        endIndex = validateRange(startIndex, endIndex);
-        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
+    public int indexOf(final StringMatcher matcher) {
+        return indexOf(matcher, 0);
     }
 
     /**
-     * Replaces within the builder using a matcher.
+     * 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 behavior. For example you could write a matcher to delete all
-     * occurrences where the character 'a' is followed by a number.
+     * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
+     * character 'a' followed by a number.
      * </p>
      *
      * @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
+     *            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
      */
-    private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to,
-            int replaceCount) {
-        if (matcher == null || size == 0) {
-            return this;
+    public int indexOf(final StringMatcher matcher, int startIndex) {
+        startIndex = Math.max(0, startIndex);
+        if (matcher == null || startIndex >= size) {
+            return -1;
         }
-        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--;
-                }
+        final int len = size;
+        final char[] buf = buffer;
+        for (int i = startIndex; i < len; i++) {
+            if (matcher.isMatch(buf, i, startIndex, len) > 0) {
+                return i;
             }
         }
-        return this;
+        return -1;
     }
 
     /**
-     * Reverses the string builder placing each character in the opposite index.
+     * 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 TextStringBuilder 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;
+    public TextStringBuilder insert(int index, final boolean value) {
+        validateIndex(index);
+        if (value) {
+            ensureCapacity(size + TRUE_STRING_SIZE);
+            System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index);
+            buffer[index++] = 't';
+            buffer[index++] = 'r';
+            buffer[index++] = 'u';
+            buffer[index] = 'e';
+            size += TRUE_STRING_SIZE;
+        } else {
+            ensureCapacity(size + FALSE_STRING_SIZE);
+            System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index);
+            buffer[index++] = 'f';
+            buffer[index++] = 'a';
+            buffer[index++] = 'l';
+            buffer[index++] = 's';
+            buffer[index] = 'e';
+            size += FALSE_STRING_SIZE;
         }
         return this;
     }
 
     /**
-     * Trims the builder by removing characters less than or equal to a space from the beginning and end.
+     * 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 TextStringBuilder 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);
-        }
+    public TextStringBuilder 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;
     }
 
     /**
-     * Checks whether this builder starts with the specified string.
-     * <p>
-     * Note that this method handles null input quietly, unlike String.
-     * </p>
+     * Inserts the character array into this builder. Inserting null will use the stored null text value.
      *
-     * @param str
-     *            the string to search for, null returns false
-     * @return true if the builder starts with the string
+     * @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 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;
+    public TextStringBuilder insert(final int index, final char[] chars) {
+        validateIndex(index);
+        if (chars == null) {
+            return insert(index, nullText);
         }
-        for (int i = 0; i < len; i++) {
-            if (buffer[i] != str.charAt(i)) {
-                return false;
-            }
+        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 true;
+        return this;
     }
 
     /**
-     * Checks whether this builder ends with the specified string.
-     * <p>
-     * Note that this method handles null input quietly, unlike String.
-     * </p>
+     * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
      *
-     * @param str
-     *            the string to search for, null returns false
-     * @return true if the builder ends with the string
+     * @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 boolean endsWith(final String str) {
-        if (str == null) {
-            return false;
+    public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) {
+        validateIndex(index);
+        if (chars == null) {
+            return insert(index, nullText);
         }
-        final int len = str.length();
-        if (len == 0) {
-            return true;
+        if (offset < 0 || offset > chars.length) {
+            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
         }
-        if (len > size) {
-            return false;
+        if (length < 0 || offset + length > chars.length) {
+            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
         }
-        int pos = size - len;
-        for (int i = 0; i < len; i++, pos++) {
-            if (buffer[pos] != str.charAt(i)) {
-                return false;
-            }
+        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 true;
+        return this;
     }
 
     /**
-     * {@inheritDoc}
+     * 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
      */
-    @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);
+    public TextStringBuilder insert(final int index, final double value) {
+        return insert(index, String.valueOf(value));
     }
 
     /**
-     * Extracts a portion of this string builder as a string.
+     * Inserts the value into this builder.
      *
-     * @param start
-     *            the start index, inclusive, must be valid
-     * @return The new string
+     * @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 String substring(final int start) {
-        return substring(start, size);
+    public TextStringBuilder insert(final int index, final float value) {
+        return insert(index, String.valueOf(value));
     }
 
     /**
-     * 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.
-     * </p>
+     * Inserts the value into this builder.
      *
-     * @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
+     * @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 String substring(final int startIndex, int endIndex) {
-        endIndex = validateRange(startIndex, endIndex);
-        return new String(buffer, startIndex, endIndex - startIndex);
+    public TextStringBuilder insert(final int index, final int value) {
+        return insert(index, String.valueOf(value));
     }
 
     /**
-     * Extracts the leftmost characters from the string builder without throwing an exception.
-     * <p>
-     * This method extracts the left {@code length} 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.
-     * </p>
+     * Inserts the value into this builder.
      *
-     * @param length
-     *            the number of characters to extract, negative returns empty string
-     * @return The new string
+     * @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 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);
-        }
+    public TextStringBuilder insert(final int index, final long value) {
+        return insert(index, String.valueOf(value));
     }
 
     /**
-     * Extracts the rightmost characters from the string builder without throwing an exception.
-     * <p>
-     * This method extracts the right {@code length} 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.
-     * </p>
+     * Inserts the string representation of an object into this builder. Inserting null will use the stored null text
+     * value.
      *
-     * @param length
-     *            the number of characters to extract, negative returns empty string
-     * @return The new string
+     * @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 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);
+    public TextStringBuilder insert(final int index, final Object obj) {
+        if (obj == null) {
+            return insert(index, nullText);
         }
+        return insert(index, obj.toString());
     }
 
     /**
-     * Extracts some characters from the middle of the string builder without throwing an exception.
-     * <p>
-     * This method extracts {@code length} 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.
-     * </p>
+     * Inserts the string into this builder. Inserting null will use the stored null text value.
      *
      * @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
+     *            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 String midString(int index, final int length) {
-        if (index < 0) {
-            index = 0;
-        }
-        if (length <= 0 || index >= size) {
-            return "";
+    public TextStringBuilder insert(final int index, String str) {
+        validateIndex(index);
+        if (str == null) {
+            str = nullText;
         }
-        if (size <= index + length) {
-            return new String(buffer, index, size - index);
+        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 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 behavior. For example you could write a matcher to search for
-     * the character 'a' followed by a number.
-     * </p>
-     *
-     * @param matcher
-     *            the matcher to use, null returns -1
-     * @return true if the matcher finds a match in the builder
-     */
-    public boolean contains(final StringMatcher 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 = Math.max(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.
-     * </p>
-     *
-     * @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 = Math.max(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 behavior. For example you could write a matcher to find the
-     * character 'a' followed by a number.
-     * </p>
-     *
-     * @param matcher
-     *            the matcher to use, null returns -1
-     * @return The first index matched, or -1 if not found
-     */
-    public int indexOf(final StringMatcher matcher) {
-        return indexOf(matcher, 0);
+        return this;
     }
 
     /**
-     * Searches the string builder using the matcher to find the first match searching from the given index.
+     * Checks is the string builder is empty (convenience Collections API style method).
      * <p>
-     * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the
-     * character 'a' followed by a number.
+     * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
      * </p>
      *
-     * @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
+     * @return {@code true} if the size is {@code 0}.
      */
-    public int indexOf(final StringMatcher matcher, int startIndex) {
-        startIndex = Math.max(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) > 0) {
-                return i;
-            }
-        }
-        return -1;
+    public boolean isEmpty() {
+        return size == 0;
     }
 
     /**
@@ -2811,167 +2540,539 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Creates a tokenizer that can tokenize the contents of this builder.
-     * <p>
-     * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to
-     * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the
-     * tokenizer class, before retrieving the tokens.
-     * </p>
-     * <p>
-     * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within
-     * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be
-     * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example:
-     * </p>
-     *
-     * <pre>
-     * StrBuilder b = new StrBuilder();
-     * b.append("a b ");
-     * StrTokenizer t = b.asTokenizer();
-     * String[] tokens1 = t.getTokenArray(); // returns a,b
-     * b.append("c d ");
-     * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
-     * t.reset(); // reset causes builder changes to be picked up
-     * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
-     * </pre>
-     *
-     * <p>
-     * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to
-     * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes.
-     * </p>
+     * Extracts the leftmost characters from the string builder without throwing an exception.
      * <p>
-     * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will
-     * break the link with the builder.
+     * This method extracts the left {@code length} 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.
      * </p>
      *
-     * @return a tokenizer that is linked to this builder
+     * @param length
+     *            the number of characters to extract, negative returns empty string
+     * @return The new string
      */
-    public StringTokenizer asTokenizer() {
-        return new TextStringBuilderTokenizer();
+    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);
+        }
     }
-    // -----------------------------------------------------------------------
+
     /**
-     * Gets the contents of this builder as a Reader.
-     * <p>
-     * This method allows the contents of the builder to be read using any standard method that expects a Reader.
-     * </p>
-     * <p>
-     * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read
-     * away.
-     * </p>
-     * <p>
-     * The internal character array is shared between the builder and the reader. This allows you to append to the
-     * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization
-     * occurs, so you must perform all operations with the builder and the reader in one thread.
-     * </p>
-     * <p>
-     * The returned reader supports marking, and ignores the flush method.
-     * </p>
+     * Gets the length of the string builder.
      *
-     * @return a reader that reads from this builder
+     * @return The length
      */
-    public Reader asReader() {
-        return new StrBuilderReader();
+    @Override
+    public int length() {
+        return size;
     }
 
     /**
-     * Gets this builder as a Writer that can be written to.
-     * <p>
-     * This method allows you to populate the contents of the builder using any standard method that takes a Writer.
-     * </p>
+     * Extracts some characters from the middle of the string builder without throwing an exception.
      * <p>
-     * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is
-     * available at any time using the methods of the {@code StrBuilder}.
+     * This method extracts {@code length} 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.
      * </p>
+     *
+     * @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);
+    }
+
+    /**
+     * Minimizes the capacity to the actual length of the string.
+     *
+     * @return this, to enable chaining
+     */
+    public TextStringBuilder minimizeCapacity() {
+        if (buffer.length > length()) {
+            final char[] old = buffer;
+            buffer = new char[length()];
+            System.arraycopy(old, 0, buffer, 0, size);
+        }
+        return this;
+    }
+
+    /**
+     * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without
+     * making extra copies.
+     *
+     * @param charBuffer CharBuffer to read.
+     * @return The number of characters read.
+     * @throws IOException if an I/O error occurs.
+     *
+     * @see #appendTo(Appendable)
+     * @since 1.9
+     */
+    public int readFrom(final CharBuffer charBuffer) throws IOException {
+        final int oldSize = size;
+        final int remaining = charBuffer.remaining();
+        ensureCapacity(size + remaining);
+        charBuffer.get(buffer, size, remaining);
+        size += remaining;
+        return size - oldSize;
+    }
+
+    /**
+     * 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 {
+        if (readable instanceof Reader) {
+            return readFrom((Reader) readable);
+        } else if (readable instanceof CharBuffer) {
+            return readFrom((CharBuffer) readable);
+        } else {
+            final int oldSize = size;
+            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;
+        }
+    }
+
+    /**
+     * If possible, reads chars from the provided {@link Reader} directly into underlying character buffer without
+     * making extra copies.
+     *
+     * @param reader Reader to read.
+     * @return The number of characters read.
+     * @throws IOException if an I/O error occurs.
+     *
+     * @see #appendTo(Appendable)
+     * @since 1.9
+     */
+    public int readFrom(final Reader reader) throws IOException {
+        final int oldSize = size;
+        ensureCapacity(size + 1);
+        int read;
+        while ((read = reader.read(buffer, size, buffer.length - size)) != -1) {
+            size += read;
+            ensureCapacity(size + 1);
+        }
+        return size - oldSize;
+    }
+
+    /**
+     * 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 TextStringBuilder 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;
+    }
+
+    /**
+     * Advanced search and replaces within the builder using a matcher.
      * <p>
-     * The internal character array is shared between the builder and the writer. This allows you to intermix calls that
-     * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no
-     * synchronization occurs, so you must perform all operations with the builder and the writer in one thread.
+     * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all
+     * occurrences where the character 'a' is followed by a number.
+     * </p>
+     *
+     * @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 TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex,
+            int endIndex, final int replaceCount) {
+        endIndex = validateRange(startIndex, endIndex);
+        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
+    }
+
+    /**
+     * 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 TextStringBuilder 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 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 TextStringBuilder 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 all matches within the builder with the replace string.
+     * <p>
+     * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all
+     * occurrences where the character 'a' is followed by a number.
+     * </p>
+     *
+     * @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 TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) {
+        return replace(matcher, replaceStr, 0, size, -1);
+    }
+
+    /**
+     * 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 TextStringBuilder 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 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 TextStringBuilder 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 the first match within the builder with the replace string.
+     * <p>
+     * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace
+     * where the character 'a' is followed by a number.
      * </p>
+     *
+     * @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 TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) {
+        return replace(matcher, replaceStr, 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 within the builder using a matcher.
      * <p>
-     * The returned writer ignores the close and flush methods.
+     * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all
+     * occurrences where the character 'a' is followed by a number.
      * </p>
      *
-     * @return a writer that populates this builder
+     * @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 TextStringBuilder replaceImpl(final StringMatcher 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 Writer asWriter() {
-        return new StrBuilderWriter();
+    public TextStringBuilder 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;
     }
 
     /**
-     * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}.
+     * Extracts the rightmost characters from the string builder without throwing an exception.
      * <p>
-     * This method tries to avoid doing any extra copies of contents.
+     * This method extracts the right {@code length} 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.
      * </p>
      *
-     * @param appendable
-     *            the appendable to append data to
-     * @throws IOException
-     *             if an I/O error occurs
-     *
-     * @see #readFrom(Readable)
+     * @param length
+     *            the number of characters to extract, negative returns empty string
+     * @return The new string
      */
-    public void appendTo(final Appendable appendable) throws IOException {
-        if (appendable instanceof Writer) {
-            ((Writer) appendable).write(buffer, 0, size);
-        } else if (appendable instanceof StringBuilder) {
-            ((StringBuilder) appendable).append(buffer, 0, size);
-        } else if (appendable instanceof StringBuffer) {
-            ((StringBuffer) appendable).append(buffer, 0, size);
-        } else if (appendable instanceof CharBuffer) {
-            ((CharBuffer) appendable).put(buffer, 0, size);
+    public String rightString(final int length) {
+        if (length <= 0) {
+            return "";
+        } else if (length >= size) {
+            return new String(buffer, 0, size);
         } else {
-            appendable.append(this);
+            return new String(buffer, size - length, length);
         }
     }
 
     /**
-     * Checks the contents of this builder against another to see if they contain the same character content ignoring
-     * case.
+     * Sets the character at the specified index.
      *
-     * @param other
-     *            the object to check, null returns false
-     * @return true if the builders contain the same characters in the same order
+     * @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 boolean equalsIgnoreCase(final TextStringBuilder other) {
-        if (this == other) {
-            return true;
+    public TextStringBuilder setCharAt(final int index, final char ch) {
+        if (index < 0 || index >= length()) {
+            throw new StringIndexOutOfBoundsException(index);
         }
-        if (this.size != other.size) {
-            return false;
+        buffer[index] = ch;
+        return this;
+    }
+    /**
+     * 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 TextStringBuilder setLength(final int length) {
+        if (length < 0) {
+            throw new StringIndexOutOfBoundsException(length);
         }
-        final char[] thisBuf = this.buffer;
-        final char[] otherBuf = other.buffer;
-        for (int i = size - 1; i >= 0; i--) {
-            final char c1 = thisBuf[i];
-            final char c2 = otherBuf[i];
-            if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
-                return false;
+        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 true;
+        return this;
     }
 
     /**
-     * Checks the contents of this builder against another to see if they contain the same character content.
+     * Sets the text to be appended when a new line is added.
      *
-     * @param other
-     *            the object to check, null returns false
-     * @return true if the builders contain the same characters in the same order
+     * @param newLine
+     *            the new line text, null means use system default
+     * @return this, to enable chaining
      */
-    public boolean equals(final TextStringBuilder other) {
-        if (this == other) {
-            return true;
+    public TextStringBuilder setNewLineText(final String newLine) {
+        this.newLine = newLine;
+        return this;
+    }
+
+    /**
+     * 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 TextStringBuilder setNullText(String nullText) {
+        if (nullText != null && nullText.isEmpty()) {
+            nullText = null;
         }
-        if (other == null) {
+        this.nullText = nullText;
+        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.
+     * </p>
+     *
+     * @return The length
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Checks whether this builder starts with the specified string.
+     * <p>
+     * Note that this method handles null input quietly, unlike String.
+     * </p>
+     *
+     * @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;
         }
-        if (this.size != other.size) {
+        final int len = str.length();
+        if (len == 0) {
+            return true;
+        }
+        if (len > size) {
             return false;
         }
-        final char[] thisBuf = this.buffer;
-        final char[] otherBuf = other.buffer;
-        for (int i = size - 1; i >= 0; i--) {
-            if (thisBuf[i] != otherBuf[i]) {
+        for (int i = 0; i < len; i++) {
+            if (buffer[i] != str.charAt(i)) {
                 return false;
             }
         }
@@ -2979,30 +3080,89 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Checks the contents of this builder against another to see if they contain the same character content.
-     *
-     * @param obj
-     *            the object to check, null returns false
-     * @return true if the builders contain the same characters in the same order
+     * {@inheritDoc}
      */
     @Override
-    public boolean equals(final Object obj) {
-        return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj);
+    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);
     }
 
     /**
-     * Gets a suitable hash code for this builder.
+     * 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.
+     * </p>
+     *
+     * @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);
+    }
+
+    /**
+     * 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.
      *
-     * @return a hash code
+     * @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)
      */
-    @Override
-    public int hashCode() {
-        final char[] buf = buffer;
-        int hash = 0;
-        for (int i = size - 1; i >= 0; i--) {
-            hash = 31 * hash + buf[i];
+    public char[] toCharArray(final int startIndex, int endIndex) {
+        endIndex = validateRange(startIndex, endIndex);
+        final int len = endIndex - startIndex;
+        if (len == 0) {
+            return new char[0];
         }
-        return hash;
+        final char[] chars = new char[len];
+        System.arraycopy(buffer, startIndex, chars, 0, len);
+        return chars;
     }
 
     /**
@@ -3036,38 +3196,30 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Implement the {@link Builder} interface.
-     *
-     * @return The builder as a String
-     * @see #toString()
-     */
-    @Override
-    public String build() {
-        return toString();
-    }
-
-    /**
-     * Validates parameters defining a range of the builder.
+     * Trims the builder by removing characters less than or equal to a space from the beginning and end.
      *
-     * @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
+     * @return this, to enable chaining
      */
-    protected int validateRange(final int startIndex, int endIndex) {
-        if (startIndex < 0) {
-            throw new StringIndexOutOfBoundsException(startIndex);
+    public TextStringBuilder trim() {
+        if (size == 0) {
+            return this;
         }
-        if (endIndex > size) {
-            endIndex = size;
+        int len = size;
+        final char[] buf = buffer;
+        int pos = 0;
+        while (pos < len && buf[pos] <= ' ') {
+            pos++;
         }
-        if (startIndex > endIndex) {
-            throw new StringIndexOutOfBoundsException("end < start");
+        while (pos < len && buf[len - 1] <= ' ') {
+            len--;
         }
-        return endIndex;
+        if (len < size) {
+            delete(len, size);
+        }
+        if (pos > 0) {
+            delete(0, pos);
+        }
+        return this;
     }
 
     /**
@@ -3085,179 +3237,27 @@ public class TextStringBuilder implements CharSequence, Appendable, Serializable
     }
 
     /**
-     * Inner class to allow StrBuilder to operate as a tokenizer.
-     */
-    class TextStringBuilderTokenizer extends StringTokenizer {
-
-        /**
-         * Default constructor.
-         */
-        TextStringBuilderTokenizer() {
-            super();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        protected List<String> tokenize(final char[] chars, final int offset, final int count) {
-            if (chars == null) {
-                return super.tokenize(TextStringBuilder.this.buffer, 0, TextStringBuilder.this.size());
-            }
-            return super.tokenize(chars, offset, count);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public String getContent() {
-            final String str = super.getContent();
-            if (str == null) {
-                return TextStringBuilder.this.toString();
-            }
-            return str;
-        }
-    }
-
-    /**
-     * Inner class to allow StrBuilder to operate as a reader.
-     */
-    class StrBuilderReader extends Reader {
-        /** The current stream position. */
-        private int pos;
-        /** The last mark position. */
-        private int mark;
-
-        /**
-         * Default constructor.
-         */
-        StrBuilderReader() {
-            super();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void close() {
-            // do nothing
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int read() {
-            if (!ready()) {
-                return -1;
-            }
-            return TextStringBuilder.this.charAt(pos++);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public int read(final char[] b, final int off, int len) {
-            if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) {
-                throw new IndexOutOfBoundsException();
-            }
-            if (len == 0) {
-                return 0;
-            }
-            if (pos >= TextStringBuilder.this.size()) {
-                return -1;
-            }
-            if (pos + len > size()) {
-                len = TextStringBuilder.this.size() - pos;
-            }
-            TextStringBuilder.this.getChars(pos, pos + len, b, off);
-            pos += len;
-            return len;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public long skip(long n) {
-            if (pos + n > TextStringBuilder.this.size()) {
-                n = TextStringBuilder.this.size() - pos;
-            }
-            if (n < 0) {
-                return 0;
-            }
-            pos += n;
-            return n;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean ready() {
-            return pos < TextStringBuilder.this.size();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public boolean markSupported() {
-            return true;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void mark(final int readAheadLimit) {
-            mark = pos;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void reset() {
-            pos = mark;
-        }
-    }
-
-    /**
-     * Inner class to allow StrBuilder to operate as a writer.
+     * Validates parameters defining a range of the builder.
+     *
+     * @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
      */
-    class StrBuilderWriter extends Writer {
-
-        /**
-         * Default constructor.
-         */
-        StrBuilderWriter() {
-            super();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void close() {
-            // do nothing
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void flush() {
-            // do nothing
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void write(final int c) {
-            TextStringBuilder.this.append((char) c);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void write(final char[] cbuf) {
-            TextStringBuilder.this.append(cbuf);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void write(final char[] cbuf, final int off, final int len) {
-            TextStringBuilder.this.append(cbuf, off, len);
+    protected int validateRange(final int startIndex, int endIndex) {
+        if (startIndex < 0) {
+            throw new StringIndexOutOfBoundsException(startIndex);
         }
-
-        /** {@inheritDoc} */
-        @Override
-        public void write(final String str) {
-            TextStringBuilder.this.append(str);
+        if (endIndex > size) {
+            endIndex = size;
         }
-
-        /** {@inheritDoc} */
-        @Override
-        public void write(final String str, final int off, final int len) {
-            TextStringBuilder.this.append(str, off, len);
+        if (startIndex > endIndex) {
+            throw new StringIndexOutOfBoundsException("end < start");
         }
+        return endIndex;
     }
 
 }


[commons-text] 03/03: Tweak toString();

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-text.git

commit 37a7cc2a90707d009c4dc94e7433f924701f34ff
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jun 26 17:55:12 2020 -0400

    Tweak toString();
---
 .../apache/commons/text/matcher/AbstractStringMatcher.java   | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/commons/text/matcher/AbstractStringMatcher.java b/src/main/java/org/apache/commons/text/matcher/AbstractStringMatcher.java
index a9e62a4..ba25f07 100644
--- a/src/main/java/org/apache/commons/text/matcher/AbstractStringMatcher.java
+++ b/src/main/java/org/apache/commons/text/matcher/AbstractStringMatcher.java
@@ -203,17 +203,21 @@ abstract class AbstractStringMatcher implements StringMatcher {
      */
     static final class StringMatcher extends AbstractStringMatcher {
 
-        /** The string to match, as a character array. */
+        /** The string to match, as a character array, implementation treats as immutable. */
         private final char[] chars;
 
+        /** The string to match */
+        private final String string;
+
         /**
          * Constructs a matcher from a String.
          *
          * @param str the string to match, must not be null
          */
-        StringMatcher(final String str) {
+        StringMatcher(final String string) {
             super();
-            chars = str.toCharArray();
+            this.string = string;
+            this.chars = string.toCharArray();
         }
 
         /**
@@ -276,7 +280,7 @@ abstract class AbstractStringMatcher implements StringMatcher {
 
         @Override
         public String toString() {
-            return super.toString() + ' ' + Arrays.toString(chars);
+            return super.toString() + "[\"" + string + "\"]";
         }
 
     }