001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.text;
018
019import java.io.IOException;
020import java.io.Reader;
021import java.io.Serializable;
022import java.io.Writer;
023import java.nio.CharBuffer;
024import java.util.Arrays;
025import java.util.Iterator;
026import java.util.List;
027import java.util.Objects;
028
029import org.apache.commons.lang3.ArrayUtils;
030import org.apache.commons.lang3.CharUtils;
031import org.apache.commons.lang3.StringUtils;
032
033/**
034 * Builds a string from constituent parts providing a more flexible and powerful API than {@link StringBuffer} and {@link StringBuilder}.
035 * <p>
036 * The main differences from {@link StrBuilder} and {@link StringBuilder} are:
037 * </p>
038 * <ul>
039 * <li>Not synchronized</li>
040 * <li>Not final</li>
041 * <li>Subclasses have direct access to character array</li>
042 * <li>Additional methods
043 * <ul>
044 * <li>appendWithSeparators - adds an array of values, with a separator</li>
045 * <li>appendPadding - adds a length padding characters</li>
046 * <li>appendFixedLength - adds a fixed width field to the builder</li>
047 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li>
048 * <li>delete - delete char or string</li>
049 * <li>replace - search and replace for a char or string</li>
050 * <li>leftString/rightString/midString - substring without exceptions</li>
051 * <li>contains - whether the builder contains a char or string</li>
052 * <li>size/clear/isEmpty - collections style API methods</li>
053 * </ul>
054 * </li>
055 * <li>Views
056 * <ul>
057 * <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li>
058 * <li>asReader - uses the internal buffer as the source of a Reader</li>
059 * <li>asWriter - allows a Writer to write directly to the internal buffer</li>
060 * </ul>
061 * </li>
062 * </ul>
063 * <p>
064 * The aim has been to provide an API that mimics very closely what StringBuffer provides, but with additional methods. It should be noted that some edge cases,
065 * with invalid indices or null input, have been altered - see individual methods. The biggest of these changes is that by default, null will not output the
066 * text 'null'. This can be controlled by a property, {@link #setNullText(String)}.
067 * </p>
068 *
069 * @since 1.0
070 * @deprecated Deprecated as of 1.3, use {@link TextStringBuilder} instead. This class will be removed in 2.0.
071 */
072@Deprecated
073public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> {
074
075    /**
076     * Inner class to allow StrBuilder to operate as a reader.
077     */
078    final class StrBuilderReader extends Reader {
079
080        /** The current stream position. */
081        private int pos;
082
083        /** The last mark position. */
084        private int mark;
085
086        /**
087         * Default constructor.
088         */
089        StrBuilderReader() {
090        }
091
092        /** {@inheritDoc} */
093        @Override
094        public void close() {
095            // do nothing
096        }
097
098        /** {@inheritDoc} */
099        @Override
100        public void mark(final int readAheadLimit) {
101            mark = pos;
102        }
103
104        /** {@inheritDoc} */
105        @Override
106        public boolean markSupported() {
107            return true;
108        }
109
110        /** {@inheritDoc} */
111        @Override
112        public int read() {
113            if (!ready()) {
114                return -1;
115            }
116            return charAt(pos++);
117        }
118
119        /** {@inheritDoc} */
120        @Override
121        public int read(final char[] b, final int off, int len) {
122            if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) {
123                throw new IndexOutOfBoundsException();
124            }
125            if (len == 0) {
126                return 0;
127            }
128            if (pos >= size()) {
129                return -1;
130            }
131            if (pos + len > size()) {
132                len = size() - pos;
133            }
134            StrBuilder.this.getChars(pos, pos + len, b, off);
135            pos += len;
136            return len;
137        }
138
139        /** {@inheritDoc} */
140        @Override
141        public boolean ready() {
142            return pos < size();
143        }
144
145        /** {@inheritDoc} */
146        @Override
147        public void reset() {
148            pos = mark;
149        }
150
151        /** {@inheritDoc} */
152        @Override
153        public long skip(long n) {
154            if (pos + n > size()) {
155                n = size() - pos;
156            }
157            if (n < 0) {
158                return 0;
159            }
160            pos = Math.addExact(pos, Math.toIntExact(n));
161            return n;
162        }
163    }
164
165    /**
166     * Inner class to allow StrBuilder to operate as a tokenizer.
167     */
168    final class StrBuilderTokenizer extends StrTokenizer {
169
170        /**
171         * Default constructor.
172         */
173        StrBuilderTokenizer() {
174        }
175
176        /** {@inheritDoc} */
177        @Override
178        public String getContent() {
179            final String str = super.getContent();
180            if (str == null) {
181                return StrBuilder.this.toString();
182            }
183            return str;
184        }
185
186        /** {@inheritDoc} */
187        @Override
188        protected List<String> tokenize(final char[] chars, final int offset, final int count) {
189            if (chars == null) {
190                return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size());
191            }
192            return super.tokenize(chars, offset, count);
193        }
194    }
195
196    /**
197     * Inner class to allow StrBuilder to operate as a writer.
198     */
199    final class StrBuilderWriter extends Writer {
200
201        /**
202         * Default constructor.
203         */
204        StrBuilderWriter() {
205        }
206
207        /** {@inheritDoc} */
208        @Override
209        public void close() {
210            // do nothing
211        }
212
213        /** {@inheritDoc} */
214        @Override
215        public void flush() {
216            // do nothing
217        }
218
219        /** {@inheritDoc} */
220        @Override
221        public void write(final char[] cbuf) {
222            StrBuilder.this.append(cbuf);
223        }
224
225        /** {@inheritDoc} */
226        @Override
227        public void write(final char[] cbuf, final int off, final int len) {
228            StrBuilder.this.append(cbuf, off, len);
229        }
230
231        /** {@inheritDoc} */
232        @Override
233        public void write(final int c) {
234            StrBuilder.this.append((char) c);
235        }
236
237        /** {@inheritDoc} */
238        @Override
239        public void write(final String str) {
240            StrBuilder.this.append(str);
241        }
242
243        /** {@inheritDoc} */
244        @Override
245        public void write(final String str, final int off, final int len) {
246            StrBuilder.this.append(str, off, len);
247        }
248    }
249
250    /**
251     * The extra capacity for new builders.
252     */
253    static final int CAPACITY = 32;
254
255    /**
256     * Required for serialization support.
257     *
258     * @see java.io.Serializable
259     */
260    private static final long serialVersionUID = 7628716375283629643L;
261
262    /** Internal data storage. */
263    char[] buffer; // package-protected for test code use only
264
265    /** Current size of the buffer. */
266    private int size;
267
268    /**
269     * The new line, {@code null} means use the system default from {@link System#lineSeparator()}.
270     */
271    private String newLine;
272
273    /** The null text. */
274    private String nullText;
275
276    /**
277     * Constructs an empty builder initial capacity 32 characters.
278     */
279    public StrBuilder() {
280        this(CAPACITY);
281    }
282
283    /**
284     * Constructs an empty builder the specified initial capacity.
285     *
286     * @param initialCapacity the initial capacity, zero or less will be converted to 32
287     */
288    public StrBuilder(int initialCapacity) {
289        if (initialCapacity <= 0) {
290            initialCapacity = CAPACITY;
291        }
292        buffer = new char[initialCapacity];
293    }
294
295    /**
296     * Constructs a builder from the string, allocating 32 extra characters for growth.
297     *
298     * @param str the string to copy, null treated as blank string
299     */
300    public StrBuilder(final String str) {
301        if (str == null) {
302            buffer = new char[CAPACITY];
303        } else {
304            buffer = new char[str.length() + CAPACITY];
305            append(str);
306        }
307    }
308
309    /**
310     * Appends a boolean value to the string builder.
311     *
312     * @param value the value to append
313     * @return {@code this} instance.
314     */
315    public StrBuilder append(final boolean value) {
316        if (value) {
317            ensureCapacity(size + 4);
318            buffer[size++] = 't';
319            buffer[size++] = 'r';
320            buffer[size++] = 'u';
321        } else {
322            ensureCapacity(size + 5);
323            buffer[size++] = 'f';
324            buffer[size++] = 'a';
325            buffer[size++] = 'l';
326            buffer[size++] = 's';
327        }
328        buffer[size++] = 'e';
329        return this;
330    }
331
332    /**
333     * Appends a char value to the string builder.
334     *
335     * @param ch the value to append
336     * @return {@code this} instance.
337     */
338    @Override
339    public StrBuilder append(final char ch) {
340        final int len = length();
341        ensureCapacity(len + 1);
342        buffer[size++] = ch;
343        return this;
344    }
345
346    /**
347     * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
348     *
349     * @param chars the char array to append
350     * @return {@code this} instance.
351     */
352    public StrBuilder append(final char[] chars) {
353        if (chars == null) {
354            return appendNull();
355        }
356        final int strLen = chars.length;
357        if (strLen > 0) {
358            final int len = length();
359            ensureCapacity(len + strLen);
360            System.arraycopy(chars, 0, buffer, len, strLen);
361            size += strLen;
362        }
363        return this;
364    }
365
366    /**
367     * Appends a char array to the string builder. Appending null will call {@link #appendNull()}.
368     *
369     * @param chars      the char array to append
370     * @param startIndex the start index, inclusive, must be valid
371     * @param length     the length to append, must be valid
372     * @return {@code this} instance.
373     */
374    public StrBuilder append(final char[] chars, final int startIndex, final int length) {
375        if (chars == null) {
376            return appendNull();
377        }
378        if (startIndex < 0 || startIndex > chars.length) {
379            throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length);
380        }
381        if (length < 0 || startIndex + length > chars.length) {
382            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
383        }
384        if (length > 0) {
385            final int len = length();
386            ensureCapacity(len + length);
387            System.arraycopy(chars, startIndex, buffer, len, length);
388            size += length;
389        }
390        return this;
391    }
392
393    /**
394     * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
395     *
396     * @param buf the char buffer to append
397     * @return {@code this} instance.
398     */
399    public StrBuilder append(final CharBuffer buf) {
400        if (buf == null) {
401            return appendNull();
402        }
403        if (buf.hasArray()) {
404            final int length = buf.remaining();
405            final int len = length();
406            ensureCapacity(len + length);
407            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position(), buffer, len, length);
408            size += length;
409        } else {
410            append(buf.toString());
411        }
412        return this;
413    }
414
415    /**
416     * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}.
417     *
418     * @param buf        the char buffer to append
419     * @param startIndex the start index, inclusive, must be valid
420     * @param length     the length to append, must be valid
421     * @return {@code this} instance.
422     */
423    public StrBuilder append(final CharBuffer buf, final int startIndex, final int length) {
424        if (buf == null) {
425            return appendNull();
426        }
427        if (buf.hasArray()) {
428            final int totalLength = buf.remaining();
429            if (startIndex < 0 || startIndex > totalLength) {
430                throw new StringIndexOutOfBoundsException("startIndex must be valid");
431            }
432            if (length < 0 || startIndex + length > totalLength) {
433                throw new StringIndexOutOfBoundsException("length must be valid");
434            }
435            final int len = length();
436            ensureCapacity(len + length);
437            System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length);
438            size += length;
439        } else {
440            append(buf.toString(), startIndex, length);
441        }
442        return this;
443    }
444
445    /**
446     * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
447     *
448     * @param seq the CharSequence to append
449     * @return {@code this} instance.
450     */
451    @Override
452    public StrBuilder append(final CharSequence seq) {
453        if (seq == null) {
454            return appendNull();
455        }
456        if (seq instanceof StrBuilder) {
457            return append((StrBuilder) seq);
458        }
459        if (seq instanceof StringBuilder) {
460            return append((StringBuilder) seq);
461        }
462        if (seq instanceof StringBuffer) {
463            return append((StringBuffer) seq);
464        }
465        if (seq instanceof CharBuffer) {
466            return append((CharBuffer) seq);
467        }
468        return append(seq.toString());
469    }
470
471    /**
472     * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}.
473     *
474     * @param seq        the CharSequence to append
475     * @param startIndex the start index, inclusive, must be valid
476     * @param length     the length to append, must be valid
477     * @return {@code this} instance.
478     */
479    @Override
480    public StrBuilder append(final CharSequence seq, final int startIndex, final int length) {
481        if (seq == null) {
482            return appendNull();
483        }
484        return append(seq.toString(), startIndex, length);
485    }
486
487    /**
488     * Appends a double value to the string builder using {@code String.valueOf}.
489     *
490     * @param value the value to append
491     * @return {@code this} instance.
492     */
493    public StrBuilder append(final double value) {
494        return append(String.valueOf(value));
495    }
496
497    /**
498     * Appends a float value to the string builder using {@code String.valueOf}.
499     *
500     * @param value the value to append
501     * @return {@code this} instance.
502     */
503    public StrBuilder append(final float value) {
504        return append(String.valueOf(value));
505    }
506
507    /**
508     * Appends an int value to the string builder using {@code String.valueOf}.
509     *
510     * @param value the value to append
511     * @return {@code this} instance.
512     */
513    public StrBuilder append(final int value) {
514        return append(String.valueOf(value));
515    }
516
517    /**
518     * Appends a long value to the string builder using {@code String.valueOf}.
519     *
520     * @param value the value to append
521     * @return {@code this} instance.
522     */
523    public StrBuilder append(final long value) {
524        return append(String.valueOf(value));
525    }
526
527    /**
528     * Appends an object to this string builder. Appending null will call {@link #appendNull()}.
529     *
530     * @param obj the object to append
531     * @return {@code this} instance.
532     */
533    public StrBuilder append(final Object obj) {
534        if (obj == null) {
535            return appendNull();
536        }
537        if (obj instanceof CharSequence) {
538            return append((CharSequence) obj);
539        }
540        return append(obj.toString());
541    }
542
543    /**
544     * Appends another string builder to this string builder. Appending null will call {@link #appendNull()}.
545     *
546     * @param str the string builder to append
547     * @return {@code this} instance.
548     */
549    public StrBuilder append(final StrBuilder str) {
550        if (str == null) {
551            return appendNull();
552        }
553        final int strLen = str.length();
554        if (strLen > 0) {
555            final int len = length();
556            ensureCapacity(len + strLen);
557            System.arraycopy(str.buffer, 0, buffer, len, strLen);
558            size += strLen;
559        }
560        return this;
561    }
562
563    /**
564     * Appends part of a string builder to this string builder. Appending null will call {@link #appendNull()}.
565     *
566     * @param str        the string to append
567     * @param startIndex the start index, inclusive, must be valid
568     * @param length     the length to append, must be valid
569     * @return {@code this} instance.
570     */
571    public StrBuilder append(final StrBuilder str, final int startIndex, final int length) {
572        if (str == null) {
573            return appendNull();
574        }
575        if (startIndex < 0 || startIndex > str.length()) {
576            throw new StringIndexOutOfBoundsException("startIndex must be valid");
577        }
578        if (length < 0 || startIndex + length > str.length()) {
579            throw new StringIndexOutOfBoundsException("length must be valid");
580        }
581        if (length > 0) {
582            final int len = length();
583            ensureCapacity(len + length);
584            str.getChars(startIndex, startIndex + length, buffer, len);
585            size += length;
586        }
587        return this;
588    }
589
590    /**
591     * Appends a string to this string builder. Appending null will call {@link #appendNull()}.
592     *
593     * @param str the string to append
594     * @return {@code this} instance.
595     */
596    public StrBuilder append(final String str) {
597        if (str == null) {
598            return appendNull();
599        }
600        final int strLen = str.length();
601        if (strLen > 0) {
602            final int len = length();
603            ensureCapacity(len + strLen);
604            str.getChars(0, strLen, buffer, len);
605            size += strLen;
606        }
607        return this;
608    }
609
610    /**
611     * Appends part of a string to this string builder. Appending null will call {@link #appendNull()}.
612     *
613     * @param str        the string to append
614     * @param startIndex the start index, inclusive, must be valid
615     * @param length     the length to append, must be valid
616     * @return {@code this} instance.
617     */
618    public StrBuilder append(final String str, final int startIndex, final int length) {
619        if (str == null) {
620            return appendNull();
621        }
622        if (startIndex < 0 || startIndex > str.length()) {
623            throw new StringIndexOutOfBoundsException("startIndex must be valid");
624        }
625        if (length < 0 || startIndex + length > str.length()) {
626            throw new StringIndexOutOfBoundsException("length must be valid");
627        }
628        if (length > 0) {
629            final int len = length();
630            ensureCapacity(len + length);
631            str.getChars(startIndex, startIndex + length, buffer, len);
632            size += length;
633        }
634        return this;
635    }
636
637    /**
638     * Calls {@link String#format(String, Object...)} and appends the result.
639     *
640     * @param format the format string
641     * @param objs   the objects to use in the format string
642     * @return {@code this} to enable chaining
643     * @see String#format(String, Object...)
644     */
645    public StrBuilder append(final String format, final Object... objs) {
646        return append(String.format(format, objs));
647    }
648
649    /**
650     * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}.
651     *
652     * @param str the string buffer to append
653     * @return {@code this} instance.
654     */
655    public StrBuilder append(final StringBuffer str) {
656        if (str == null) {
657            return appendNull();
658        }
659        final int strLen = str.length();
660        if (strLen > 0) {
661            final int len = length();
662            ensureCapacity(len + strLen);
663            str.getChars(0, strLen, buffer, len);
664            size += strLen;
665        }
666        return this;
667    }
668
669    /**
670     * Appends part of a string buffer to this string builder. Appending null will call {@link #appendNull()}.
671     *
672     * @param str        the string to append
673     * @param startIndex the start index, inclusive, must be valid
674     * @param length     the length to append, must be valid
675     * @return {@code this} instance.
676     */
677    public StrBuilder append(final StringBuffer str, final int startIndex, final int length) {
678        if (str == null) {
679            return appendNull();
680        }
681        if (startIndex < 0 || startIndex > str.length()) {
682            throw new StringIndexOutOfBoundsException("startIndex must be valid");
683        }
684        if (length < 0 || startIndex + length > str.length()) {
685            throw new StringIndexOutOfBoundsException("length must be valid");
686        }
687        if (length > 0) {
688            final int len = length();
689            ensureCapacity(len + length);
690            str.getChars(startIndex, startIndex + length, buffer, len);
691            size += length;
692        }
693        return this;
694    }
695
696    /**
697     * Appends a StringBuilder to this string builder. Appending null will call {@link #appendNull()}.
698     *
699     * @param str the StringBuilder to append
700     * @return {@code this} instance.
701     */
702    public StrBuilder append(final StringBuilder str) {
703        if (str == null) {
704            return appendNull();
705        }
706        final int strLen = str.length();
707        if (strLen > 0) {
708            final int len = length();
709            ensureCapacity(len + strLen);
710            str.getChars(0, strLen, buffer, len);
711            size += strLen;
712        }
713        return this;
714    }
715
716    /**
717     * Appends part of a StringBuilder to this string builder. Appending null will call {@link #appendNull()}.
718     *
719     * @param str        the StringBuilder to append
720     * @param startIndex the start index, inclusive, must be valid
721     * @param length     the length to append, must be valid
722     * @return {@code this} instance.
723     */
724    public StrBuilder append(final StringBuilder str, final int startIndex, final int length) {
725        if (str == null) {
726            return appendNull();
727        }
728        if (startIndex < 0 || startIndex > str.length()) {
729            throw new StringIndexOutOfBoundsException("startIndex must be valid");
730        }
731        if (length < 0 || startIndex + length > str.length()) {
732            throw new StringIndexOutOfBoundsException("length must be valid");
733        }
734        if (length > 0) {
735            final int len = length();
736            ensureCapacity(len + length);
737            str.getChars(startIndex, startIndex + length, buffer, len);
738            size += length;
739        }
740        return this;
741    }
742
743    /**
744     * 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
745     * {@link #append(Object)}.
746     *
747     * @param iterable the iterable to append
748     * @return {@code this} instance.
749     */
750    public StrBuilder appendAll(final Iterable<?> iterable) {
751        if (iterable != null) {
752            iterable.forEach(this::append);
753        }
754        return this;
755    }
756
757    /**
758     * 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
759     * {@link #append(Object)}.
760     *
761     * @param it the iterator to append
762     * @return {@code this} instance.
763     */
764    public StrBuilder appendAll(final Iterator<?> it) {
765        if (it != null) {
766            while (it.hasNext()) {
767                append(it.next());
768            }
769        }
770        return this;
771    }
772
773    /**
774     * 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
775     * {@link #append(Object)}.
776     *
777     * @param <T>   the element type
778     * @param array the array to append
779     * @return {@code this} instance.
780     */
781    public <T> StrBuilder appendAll(@SuppressWarnings("unchecked") final T... array) {
782        /*
783         * @SuppressWarnings used to hide warning about vararg usage. We cannot use @SafeVarargs, since this method is not final. Using @SuppressWarnings is
784         * fine, because it isn't inherited by subclasses, so each subclass must vouch for itself whether its use of 'array' is safe.
785         */
786        if (array != null && array.length > 0) {
787            for (final Object element : array) {
788                append(element);
789            }
790        }
791        return this;
792    }
793
794    /**
795     * 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
796     * value is larger than the length, the left hand side is lost.
797     *
798     * @param value   the value to append
799     * @param width   the fixed field width, zero or negative has no effect
800     * @param padChar the pad character to use
801     * @return {@code this} instance.
802     */
803    public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) {
804        return appendFixedWidthPadLeft(String.valueOf(value), width, padChar);
805    }
806
807    /**
808     * 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
809     * length, the left hand side is lost. If the object is null, the null text value is used.
810     *
811     * @param obj     the object to append, null uses null text
812     * @param width   the fixed field width, zero or negative has no effect
813     * @param padChar the pad character to use
814     * @return {@code this} instance.
815     */
816    public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) {
817        if (width > 0) {
818            ensureCapacity(size + width);
819            String str = Objects.toString(obj, getNullText());
820            if (str == null) {
821                str = StringUtils.EMPTY;
822            }
823            final int strLen = str.length();
824            if (strLen >= width) {
825                str.getChars(strLen - width, strLen, buffer, size);
826            } else {
827                final int padLen = width - strLen;
828                final int toIndex = size + padLen;
829                Arrays.fill(buffer, size, toIndex, padChar);
830                str.getChars(0, strLen, buffer, toIndex);
831            }
832            size += width;
833        }
834        return this;
835    }
836
837    /**
838     * 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
839     * larger than the length, the right hand side is lost.
840     *
841     * @param value   the value to append
842     * @param width   the fixed field width, zero or negative has no effect
843     * @param padChar the pad character to use
844     * @return {@code this} instance.
845     */
846    public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) {
847        return appendFixedWidthPadRight(String.valueOf(value), width, padChar);
848    }
849
850    /**
851     * 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
852     * length, the right hand side is lost. If the object is null, null text value is used.
853     *
854     * @param obj     the object to append, null uses null text
855     * @param width   the fixed field width, zero or negative has no effect
856     * @param padChar the pad character to use
857     * @return {@code this} instance.
858     */
859    public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) {
860        if (width > 0) {
861            ensureCapacity(size + width);
862            String str = Objects.toString(obj, getNullText());
863            if (str == null) {
864                str = StringUtils.EMPTY;
865            }
866            final int strLen = str.length();
867            if (strLen >= width) {
868                str.getChars(0, width, buffer, size);
869            } else {
870                str.getChars(0, strLen, buffer, size);
871                final int fromIndex = size + strLen;
872                Arrays.fill(buffer, fromIndex, fromIndex + width - strLen, padChar);
873            }
874            size += width;
875        }
876        return this;
877    }
878
879    /**
880     * Appends a boolean value followed by a {@link #appendNewLine() new line} to the string builder.
881     *
882     * @param value the value to append
883     * @return {@code this} instance.
884     * @see #appendNewLine()
885     */
886    public StrBuilder appendln(final boolean value) {
887        return append(value).appendNewLine();
888    }
889
890    /**
891     * Appends a char value followed by a {@link #appendNewLine() new line} to the string builder.
892     *
893     * @param ch the value to append
894     * @return {@code this} instance.
895     * @see #appendNewLine()
896     */
897    public StrBuilder appendln(final char ch) {
898        return append(ch).appendNewLine();
899    }
900
901    /**
902     * Appends a char array followed by a {@link #appendNewLine() new line} to the string builder. Appending null will call {@link #appendNull()}.
903     *
904     * @param chars the char array to append
905     * @return {@code this} instance.
906     * @see #appendNewLine()
907     */
908    public StrBuilder appendln(final char[] chars) {
909        return append(chars).appendNewLine();
910    }
911
912    /**
913     * Appends a char array followed by a {@link #appendNewLine() new line} to the string builder. Appending null will call {@link #appendNull()}.
914     *
915     * @param chars      the char array to append
916     * @param startIndex the start index, inclusive, must be valid
917     * @param length     the length to append, must be valid
918     * @return {@code this} instance.
919     * @see #appendNewLine()
920     */
921    public StrBuilder appendln(final char[] chars, final int startIndex, final int length) {
922        return append(chars, startIndex, length).appendNewLine();
923    }
924
925    /**
926     * Appends a double value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}.
927     *
928     * @param value the value to append
929     * @return {@code this} instance.
930     * @see #appendNewLine()
931     */
932    public StrBuilder appendln(final double value) {
933        return append(value).appendNewLine();
934    }
935
936    /**
937     * Appends a float value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}.
938     *
939     * @param value the value to append
940     * @return {@code this} instance.
941     * @see #appendNewLine()
942     */
943    public StrBuilder appendln(final float value) {
944        return append(value).appendNewLine();
945    }
946
947    /**
948     * Appends an int value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}.
949     *
950     * @param value the value to append
951     * @return {@code this} instance.
952     * @see #appendNewLine()
953     */
954    public StrBuilder appendln(final int value) {
955        return append(value).appendNewLine();
956    }
957
958    /**
959     * Appends a long value followed by a {@link #appendNewLine() new line} to the string builder using {@code String.valueOf}.
960     *
961     * @param value the value to append
962     * @return {@code this} instance.
963     * @see #appendNewLine()
964     */
965    public StrBuilder appendln(final long value) {
966        return append(value).appendNewLine();
967    }
968
969    /**
970     * Appends an object followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
971     *
972     * @param obj the object to append
973     * @return {@code this} instance.
974     * @see #appendNewLine()
975     */
976    public StrBuilder appendln(final Object obj) {
977        return append(obj).appendNewLine();
978    }
979
980    /**
981     * Appends another string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
982     *
983     * @param str the string builder to append
984     * @return {@code this} instance.
985     * @see #appendNewLine()
986     */
987    public StrBuilder appendln(final StrBuilder str) {
988        return append(str).appendNewLine();
989    }
990
991    /**
992     * Appends part of a string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
993     *
994     * @param str        the string to append
995     * @param startIndex the start index, inclusive, must be valid
996     * @param length     the length to append, must be valid
997     * @return {@code this} instance.
998     * @see #appendNewLine()
999     */
1000    public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) {
1001        return append(str, startIndex, length).appendNewLine();
1002    }
1003
1004    /**
1005     * Appends a string followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
1006     *
1007     * @param str the string to append
1008     * @return {@code this} instance.
1009     * @see #appendNewLine()
1010     */
1011    public StrBuilder appendln(final String str) {
1012        return append(str).appendNewLine();
1013    }
1014
1015    /**
1016     * Appends part of a string followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
1017     *
1018     * @param str        the string to append
1019     * @param startIndex the start index, inclusive, must be valid
1020     * @param length     the length to append, must be valid
1021     * @return {@code this} instance.
1022     * @see #appendNewLine()
1023     */
1024    public StrBuilder appendln(final String str, final int startIndex, final int length) {
1025        return append(str, startIndex, length).appendNewLine();
1026    }
1027
1028    /**
1029     * Calls {@link String#format(String, Object...)} and appends the result.
1030     *
1031     * @param format the format string
1032     * @param objs   the objects to use in the format string
1033     * @return {@code this} to enable chaining
1034     * @see String#format(String, Object...)
1035     * @see #appendNewLine()
1036     */
1037    public StrBuilder appendln(final String format, final Object... objs) {
1038        return append(format, objs).appendNewLine();
1039    }
1040
1041    /**
1042     * Appends a string buffer followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
1043     *
1044     * @param str the string buffer to append
1045     * @return {@code this} instance.
1046     * @see #appendNewLine()
1047     */
1048    public StrBuilder appendln(final StringBuffer str) {
1049        return append(str).appendNewLine();
1050    }
1051
1052    /**
1053     * Appends part of a string buffer followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
1054     *
1055     * @param str        the string to append
1056     * @param startIndex the start index, inclusive, must be valid
1057     * @param length     the length to append, must be valid
1058     * @return {@code this} instance.
1059     * @see #appendNewLine()
1060     */
1061    public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) {
1062        return append(str, startIndex, length).appendNewLine();
1063    }
1064
1065    /**
1066     * Appends a string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
1067     *
1068     * @param str the string builder to append
1069     * @return {@code this} instance.
1070     * @see #appendNewLine()
1071     */
1072    public StrBuilder appendln(final StringBuilder str) {
1073        return append(str).appendNewLine();
1074    }
1075
1076    /**
1077     * Appends part of a string builder followed by a {@link #appendNewLine() new line} to this string builder. Appending null will call {@link #appendNull()}.
1078     *
1079     * @param str        the string builder to append
1080     * @param startIndex the start index, inclusive, must be valid
1081     * @param length     the length to append, must be valid
1082     * @return {@code this} instance.
1083     * @see #appendNewLine()
1084     */
1085    public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) {
1086        return append(str, startIndex, length).appendNewLine();
1087    }
1088
1089    /**
1090     * Appends this builder's new line string to this builder.
1091     * <p>
1092     * By default, the new line is the system default from {@link System#lineSeparator()}.
1093     * </p>
1094     * <p>
1095     * The new line string can be changed using {@link #setNewLineText(String)}. For example, you can use this to force the output to always use Unix line
1096     * endings even when on Windows.
1097     * </p>
1098     *
1099     * @return {@code this} instance.
1100     * @see #getNewLineText()
1101     * @see #setNewLineText(String)
1102     */
1103    public StrBuilder appendNewLine() {
1104        if (newLine == null) {
1105            append(System.lineSeparator());
1106            return this;
1107        }
1108        return append(newLine);
1109    }
1110
1111    /**
1112     * Appends this builder's null text to this builder.
1113     *
1114     * @return {@code this} instance.
1115     */
1116    public StrBuilder appendNull() {
1117        if (nullText == null) {
1118            return this;
1119        }
1120        return append(nullText);
1121    }
1122
1123    /**
1124     * Appends the pad character to the builder the specified number of times.
1125     *
1126     * @param length  the length to append, negative means no append
1127     * @param padChar the character to append
1128     * @return {@code this} instance.
1129     */
1130    public StrBuilder appendPadding(final int length, final char padChar) {
1131        if (length >= 0) {
1132            ensureCapacity(size + length);
1133            for (int i = 0; i < length; i++) {
1134                buffer[size++] = padChar;
1135            }
1136        }
1137        return this;
1138    }
1139
1140    /**
1141     * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}.
1142     * <p>
1143     * This method is useful for adding a separator each time around the loop except the first.
1144     * </p>
1145     *
1146     * <pre>
1147     * for (Iterator it = list.iterator(); it.hasNext();) {
1148     *     appendSeparator(',');
1149     *     append(it.next());
1150     * }
1151     * </pre>
1152     * <p>
1153     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1154     * </p>
1155     *
1156     * @param separator the separator to use
1157     * @return {@code this} instance.
1158     */
1159    public StrBuilder appendSeparator(final char separator) {
1160        if (isNotEmpty()) {
1161            append(separator);
1162        }
1163        return this;
1164    }
1165
1166    /**
1167     * Appends one of both separators to the builder If the builder is currently empty it will append the defaultIfEmpty-separator Otherwise it will append the
1168     * standard-separator
1169     *
1170     * The separator is appended using {@link #append(char)}.
1171     *
1172     * @param standard       the separator if builder is not empty
1173     * @param defaultIfEmpty the separator if builder is empty
1174     * @return {@code this} instance.
1175     */
1176    public StrBuilder appendSeparator(final char standard, final char defaultIfEmpty) {
1177        if (isNotEmpty()) {
1178            append(standard);
1179        } else {
1180            append(defaultIfEmpty);
1181        }
1182        return this;
1183    }
1184
1185    /**
1186     * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using {@link #append(char)}.
1187     * <p>
1188     * This method is useful for adding a separator each time around the loop except the first.
1189     * </p>
1190     *
1191     * <pre>
1192     * for (int i = 0; i &lt; list.size(); i++) {
1193     *     appendSeparator(",", i);
1194     *     append(list.get(i));
1195     * }
1196     * </pre>
1197     * <p>
1198     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1199     * </p>
1200     *
1201     * @param separator the separator to use
1202     * @param loopIndex the loop index
1203     * @return {@code this} instance.
1204     */
1205    public StrBuilder appendSeparator(final char separator, final int loopIndex) {
1206        if (loopIndex > 0) {
1207            append(separator);
1208        }
1209        return this;
1210    }
1211
1212    /**
1213     * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The separator is appended using
1214     * {@link #append(String)}.
1215     * <p>
1216     * This method is useful for adding a separator each time around the loop except the first.
1217     * </p>
1218     *
1219     * <pre>
1220     * for (Iterator it = list.iterator(); it.hasNext();) {
1221     *     appendSeparator(",");
1222     *     append(it.next());
1223     * }
1224     * </pre>
1225     * <p>
1226     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1227     * </p>
1228     *
1229     * @param separator the separator to use, null means no separator
1230     * @return {@code this} instance.
1231     */
1232    public StrBuilder appendSeparator(final String separator) {
1233        return appendSeparator(separator, null);
1234    }
1235
1236    /**
1237     * 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
1238     * using {@link #append(String)}.
1239     * <p>
1240     * This method is useful for adding a separator each time around the loop except the first.
1241     * </p>
1242     *
1243     * <pre>
1244     * for (int i = 0; i &lt; list.size(); i++) {
1245     *     appendSeparator(",", i);
1246     *     append(list.get(i));
1247     * }
1248     * </pre>
1249     * <p>
1250     * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}.
1251     * </p>
1252     *
1253     * @param separator the separator to use, null means no separator
1254     * @param loopIndex the loop index
1255     * @return {@code this} instance.
1256     */
1257    public StrBuilder appendSeparator(final String separator, final int loopIndex) {
1258        if (separator != null && loopIndex > 0) {
1259            append(separator);
1260        }
1261        return this;
1262    }
1263
1264    /**
1265     * Appends one of both separators to the StrBuilder. If the builder is currently empty it will append the defaultIfEmpty-separator Otherwise it will append
1266     * the standard-separator
1267     * <p>
1268     * Appending a null separator will have no effect. The separator is appended using {@link #append(String)}.
1269     * </p>
1270     * <p>
1271     * This method is for example useful for constructing queries
1272     * </p>
1273     *
1274     * <pre>
1275     * StrBuilder whereClause = new StrBuilder();
1276     * if (searchCommand.getPriority() != null) {
1277     *   whereClause.appendSeparator(" and", " where");
1278     *   whereClause.append(" priority = ?")
1279     * }
1280     * if (searchCommand.getComponent() != null) {
1281     *   whereClause.appendSeparator(" and", " where");
1282     *   whereClause.append(" component = ?")
1283     * }
1284     * selectClause.append(whereClause)
1285     * </pre>
1286     *
1287     * @param standard       the separator if builder is not empty, null means no separator
1288     * @param defaultIfEmpty the separator if builder is empty, null means no separator
1289     * @return {@code this} instance.
1290     */
1291    public StrBuilder appendSeparator(final String standard, final String defaultIfEmpty) {
1292        final String str = isEmpty() ? defaultIfEmpty : standard;
1293        if (str != null) {
1294            append(str);
1295        }
1296        return this;
1297    }
1298
1299    /**
1300     * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}.
1301     * <p>
1302     * This method tries to avoid doing any extra copies of contents.
1303     * </p>
1304     *
1305     * @param appendable the appendable to append data to
1306     * @throws IOException if an I/O error occurs
1307     * @see #readFrom(Readable)
1308     */
1309    public void appendTo(final Appendable appendable) throws IOException {
1310        if (appendable instanceof Writer) {
1311            ((Writer) appendable).write(buffer, 0, size);
1312        } else if (appendable instanceof StringBuilder) {
1313            ((StringBuilder) appendable).append(buffer, 0, size);
1314        } else if (appendable instanceof StringBuffer) {
1315            ((StringBuffer) appendable).append(buffer, 0, size);
1316        } else if (appendable instanceof CharBuffer) {
1317            ((CharBuffer) appendable).put(buffer, 0, size);
1318        } else {
1319            appendable.append(this);
1320        }
1321    }
1322
1323    /**
1324     * Appends an iterable placing separators between each value, but not before the first or after the last. Appending a null iterable will have no effect.
1325     * Each object is appended using {@link #append(Object)}.
1326     *
1327     * @param iterable  the iterable to append
1328     * @param separator the separator to use, null means no separator
1329     * @return {@code this} instance.
1330     */
1331    public StrBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) {
1332        if (iterable != null) {
1333            appendWithSeparators(iterable.iterator(), separator);
1334        }
1335        return this;
1336    }
1337
1338    /**
1339     * Appends an iterator placing separators between each value, but not before the first or after the last. Appending a null iterator will have no effect.
1340     * Each object is appended using {@link #append(Object)}.
1341     *
1342     * @param iterator  the iterator to append
1343     * @param separator the separator to use, null means no separator
1344     * @return {@code this} instance.
1345     */
1346    public StrBuilder appendWithSeparators(final Iterator<?> iterator, final String separator) {
1347        if (iterator != null) {
1348            final String sep = Objects.toString(separator, StringUtils.EMPTY);
1349            while (iterator.hasNext()) {
1350                append(iterator.next());
1351                if (iterator.hasNext()) {
1352                    append(sep);
1353                }
1354            }
1355        }
1356        return this;
1357    }
1358
1359    /**
1360     * 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
1361     * object is appended using {@link #append(Object)}.
1362     *
1363     * @param array     the array to append
1364     * @param separator the separator to use, null means no separator
1365     * @return {@code this} instance.
1366     */
1367    public StrBuilder appendWithSeparators(final Object[] array, final String separator) {
1368        if (array != null && array.length > 0) {
1369            final String sep = Objects.toString(separator, StringUtils.EMPTY);
1370            append(array[0]);
1371            for (int i = 1; i < array.length; i++) {
1372                append(sep);
1373                append(array[i]);
1374            }
1375        }
1376        return this;
1377    }
1378
1379    /**
1380     * Gets the contents of this builder as a Reader.
1381     * <p>
1382     * This method allows the contents of the builder to be read using any standard method that expects a Reader.
1383     * </p>
1384     * <p>
1385     * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away.
1386     * </p>
1387     * <p>
1388     * 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
1389     * 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
1390     * thread.
1391     * </p>
1392     * <p>
1393     * The returned reader supports marking, and ignores the flush method.
1394     * </p>
1395     *
1396     * @return a reader that reads from this builder
1397     */
1398    public Reader asReader() {
1399        return new StrBuilderReader();
1400    }
1401
1402    /**
1403     * Creates a tokenizer that can tokenize the contents of this builder.
1404     * <p>
1405     * 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
1406     * (as per StringTokenizer). These values can be changed on the tokenizer class, before retrieving the tokens.
1407     * </p>
1408     * <p>
1409     * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within certain limits, however there is no
1410     * synchronization. Once the tokenizer has been used once, it must be {@link StrTokenizer#reset() reset} to pickup the latest changes in the builder. For
1411     * example:
1412     * </p>
1413     *
1414     * <pre>
1415     * StrBuilder b = new StrBuilder();
1416     * b.append("a b ");
1417     * StrTokenizer t = b.asTokenizer();
1418     * String[] tokens1 = t.getTokenArray(); // returns a,b
1419     * b.append("c d ");
1420     * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored)
1421     * t.reset(); // reset causes builder changes to be picked up
1422     * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d
1423     * </pre>
1424     * <p>
1425     * 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
1426     * to call reset when you want to pickup builder changes.
1427     * </p>
1428     * <p>
1429     * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])} with a non-null value will break the link with the builder.
1430     * </p>
1431     *
1432     * @return a tokenizer that is linked to this builder
1433     */
1434    public StrTokenizer asTokenizer() {
1435        return new StrBuilderTokenizer();
1436    }
1437
1438    /**
1439     * Gets this builder as a Writer that can be written to.
1440     * <p>
1441     * This method allows you to populate the contents of the builder using any standard method that takes a Writer.
1442     * </p>
1443     * <p>
1444     * 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
1445     * {@code StrBuilder}.
1446     * </p>
1447     * <p>
1448     * 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
1449     * 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
1450     * the writer in one thread.
1451     * </p>
1452     * <p>
1453     * The returned writer ignores the close and flush methods.
1454     * </p>
1455     *
1456     * @return a writer that populates this builder
1457     */
1458    public Writer asWriter() {
1459        return new StrBuilderWriter();
1460    }
1461
1462    /**
1463     * Converts this instance to a String.
1464     *
1465     * @return This instance as a String
1466     * @see #toString()
1467     * @deprecated Use {@link #get()}.
1468     */
1469    @Deprecated
1470    @Override
1471    public String build() {
1472        return toString();
1473    }
1474
1475    /**
1476     * Gets the current size of the internal character array buffer.
1477     *
1478     * @return The capacity
1479     */
1480    public int capacity() {
1481        return buffer.length;
1482    }
1483
1484    /**
1485     * Gets the character at the specified index.
1486     *
1487     * @see #setCharAt(int, char)
1488     * @see #deleteCharAt(int)
1489     * @param index the index to retrieve, must be valid
1490     * @return The character at the index
1491     * @throws IndexOutOfBoundsException if the index is invalid
1492     */
1493    @Override
1494    public char charAt(final int index) {
1495        if (index < 0 || index >= length()) {
1496            throw new StringIndexOutOfBoundsException(index);
1497        }
1498        return buffer[index];
1499    }
1500
1501    /**
1502     * Clears the string builder (convenience Collections API style method).
1503     * <p>
1504     * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed by {@link #minimizeCapacity()}.
1505     * </p>
1506     * <p>
1507     * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of Collections.
1508     * </p>
1509     *
1510     * @return {@code this} instance.
1511     */
1512    public StrBuilder clear() {
1513        size = 0;
1514        return this;
1515    }
1516
1517    /**
1518     * Checks if the string builder contains the specified char.
1519     *
1520     * @param ch the character to find
1521     * @return true if the builder contains the character
1522     */
1523    public boolean contains(final char ch) {
1524        final char[] thisBuf = buffer;
1525        for (int i = 0; i < this.size; i++) {
1526            if (thisBuf[i] == ch) {
1527                return true;
1528            }
1529        }
1530        return false;
1531    }
1532
1533    /**
1534     * Tests if the string builder contains the specified string.
1535     *
1536     * @param str the string to find
1537     * @return true if the builder contains the string
1538     */
1539    public boolean contains(final String str) {
1540        return indexOf(str, 0) >= 0;
1541    }
1542
1543    /**
1544     * Tests if the string builder contains a string matched using the specified matcher.
1545     * <p>
1546     * 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.
1547     * </p>
1548     *
1549     * @param matcher the matcher to use, null returns -1
1550     * @return true if the matcher finds a match in the builder
1551     */
1552    public boolean contains(final StrMatcher matcher) {
1553        return indexOf(matcher, 0) >= 0;
1554    }
1555
1556    /**
1557     * Deletes the characters between the two specified indices.
1558     *
1559     * @param startIndex the start index, inclusive, must be valid
1560     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
1561     * @return {@code this} instance.
1562     * @throws IndexOutOfBoundsException if the index is invalid
1563     */
1564    public StrBuilder delete(final int startIndex, int endIndex) {
1565        endIndex = validateRange(startIndex, endIndex);
1566        final int len = endIndex - startIndex;
1567        if (len > 0) {
1568            deleteImpl(startIndex, endIndex, len);
1569        }
1570        return this;
1571    }
1572
1573    /**
1574     * Deletes the character wherever it occurs in the builder.
1575     *
1576     * @param ch the character to delete
1577     * @return {@code this} instance.
1578     */
1579    public StrBuilder deleteAll(final char ch) {
1580        for (int i = 0; i < size; i++) {
1581            if (buffer[i] == ch) {
1582                final int start = i;
1583                while (++i < size) {
1584                    if (buffer[i] != ch) {
1585                        break;
1586                    }
1587                }
1588                final int len = i - start;
1589                deleteImpl(start, i, len);
1590                i -= len;
1591            }
1592        }
1593        return this;
1594    }
1595
1596    /**
1597     * Deletes the string wherever it occurs in the builder.
1598     *
1599     * @param str the string to delete, null causes no action
1600     * @return {@code this} instance.
1601     */
1602    public StrBuilder deleteAll(final String str) {
1603        final int len = str == null ? 0 : str.length();
1604        if (len > 0) {
1605            int index = indexOf(str, 0);
1606            while (index >= 0) {
1607                deleteImpl(index, index + len, len);
1608                index = indexOf(str, index);
1609            }
1610        }
1611        return this;
1612    }
1613
1614    /**
1615     * Deletes all parts of the builder that the matcher matches.
1616     * <p>
1617     * 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
1618     * followed by a number.
1619     * </p>
1620     *
1621     * @param matcher the matcher to use to find the deletion, null causes no action
1622     * @return {@code this} instance.
1623     */
1624    public StrBuilder deleteAll(final StrMatcher matcher) {
1625        return replace(matcher, null, 0, size, -1);
1626    }
1627
1628    /**
1629     * Deletes the character at the specified index.
1630     *
1631     * @see #charAt(int)
1632     * @see #setCharAt(int, char)
1633     * @param index the index to delete
1634     * @return {@code this} instance.
1635     * @throws IndexOutOfBoundsException if the index is invalid
1636     */
1637    public StrBuilder deleteCharAt(final int index) {
1638        if (index < 0 || index >= size) {
1639            throw new StringIndexOutOfBoundsException(index);
1640        }
1641        deleteImpl(index, index + 1, 1);
1642        return this;
1643    }
1644
1645    /**
1646     * Deletes the character wherever it occurs in the builder.
1647     *
1648     * @param ch the character to delete
1649     * @return {@code this} instance.
1650     */
1651    public StrBuilder deleteFirst(final char ch) {
1652        for (int i = 0; i < size; i++) {
1653            if (buffer[i] == ch) {
1654                deleteImpl(i, i + 1, 1);
1655                break;
1656            }
1657        }
1658        return this;
1659    }
1660
1661    /**
1662     * Deletes the string wherever it occurs in the builder.
1663     *
1664     * @param str the string to delete, null causes no action
1665     * @return {@code this} instance.
1666     */
1667    public StrBuilder deleteFirst(final String str) {
1668        final int len = str == null ? 0 : str.length();
1669        if (len > 0) {
1670            final int index = indexOf(str, 0);
1671            if (index >= 0) {
1672                deleteImpl(index, index + len, len);
1673            }
1674        }
1675        return this;
1676    }
1677
1678    /**
1679     * Deletes the first match within the builder using the specified matcher.
1680     * <p>
1681     * 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
1682     * number.
1683     * </p>
1684     *
1685     * @param matcher the matcher to use to find the deletion, null causes no action
1686     * @return {@code this} instance.
1687     */
1688    public StrBuilder deleteFirst(final StrMatcher matcher) {
1689        return replace(matcher, null, 0, size, 1);
1690    }
1691
1692    /**
1693     * Internal method to delete a range without validation.
1694     *
1695     * @param startIndex the start index, must be valid
1696     * @param endIndex   the end index (exclusive), must be valid
1697     * @param len        the length, must be valid
1698     * @throws IndexOutOfBoundsException if any index is invalid
1699     */
1700    private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1701        System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1702        size -= len;
1703    }
1704
1705    /**
1706     * Tests whether this builder ends with the specified string.
1707     * <p>
1708     * Note that this method handles null input quietly, unlike String.
1709     * </p>
1710     *
1711     * @param str the string to search for, null returns false
1712     * @return true if the builder ends with the string
1713     */
1714    public boolean endsWith(final String str) {
1715        if (str == null) {
1716            return false;
1717        }
1718        final int len = str.length();
1719        if (len == 0) {
1720            return true;
1721        }
1722        if (len > size) {
1723            return false;
1724        }
1725        int pos = size - len;
1726        for (int i = 0; i < len; i++, pos++) {
1727            if (buffer[pos] != str.charAt(i)) {
1728                return false;
1729            }
1730        }
1731        return true;
1732    }
1733
1734    /**
1735     * Tests the capacity and ensures that it is at least the size specified.
1736     *
1737     * @param capacity the capacity to ensure
1738     * @return {@code this} instance.
1739     */
1740    public StrBuilder ensureCapacity(final int capacity) {
1741        if (capacity > buffer.length) {
1742            final char[] old = buffer;
1743            buffer = new char[capacity * 2];
1744            System.arraycopy(old, 0, buffer, 0, size);
1745        }
1746        return this;
1747    }
1748
1749    /**
1750     * Tests the contents of this builder against another to see if they contain the same character content.
1751     *
1752     * @param obj the object to check, null returns false
1753     * @return true if the builders contain the same characters in the same order
1754     */
1755    @Override
1756    public boolean equals(final Object obj) {
1757        return obj instanceof StrBuilder && equals((StrBuilder) obj);
1758    }
1759
1760    /**
1761     * Tests the contents of this builder against another to see if they contain the same character content.
1762     *
1763     * @param other the object to check, null returns false
1764     * @return true if the builders contain the same characters in the same order
1765     */
1766    public boolean equals(final StrBuilder other) {
1767        if (this == other) {
1768            return true;
1769        }
1770        if (other == null) {
1771            return false;
1772        }
1773        if (this.size != other.size) {
1774            return false;
1775        }
1776        final char[] thisBuf = this.buffer;
1777        final char[] otherBuf = other.buffer;
1778        for (int i = size - 1; i >= 0; i--) {
1779            if (thisBuf[i] != otherBuf[i]) {
1780                return false;
1781            }
1782        }
1783        return true;
1784    }
1785
1786    /**
1787     * Tests the contents of this builder against another to see if they contain the same character content ignoring case.
1788     *
1789     * @param other the object to check, null returns false
1790     * @return true if the builders contain the same characters in the same order
1791     */
1792    public boolean equalsIgnoreCase(final StrBuilder other) {
1793        if (this == other) {
1794            return true;
1795        }
1796        if (this.size != other.size) {
1797            return false;
1798        }
1799        final char[] thisBuf = this.buffer;
1800        final char[] otherBuf = other.buffer;
1801        for (int i = size - 1; i >= 0; i--) {
1802            final char c1 = thisBuf[i];
1803            final char c2 = otherBuf[i];
1804            if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
1805                return false;
1806            }
1807        }
1808        return true;
1809    }
1810
1811    /**
1812     * Converts this instance to a String.
1813     *
1814     * @return This instance as a String
1815     * @see #toString()
1816     * @since 1.12.0
1817     */
1818    @Override
1819    public String get() {
1820        return toString();
1821    }
1822
1823    /**
1824     * Copies the character array into the specified array.
1825     *
1826     * @param destination the destination array, null will cause an array to be created
1827     * @return The input array, unless that was null or too small
1828     */
1829    public char[] getChars(char[] destination) {
1830        final int len = length();
1831        if (destination == null || destination.length < len) {
1832            destination = new char[len];
1833        }
1834        System.arraycopy(buffer, 0, destination, 0, len);
1835        return destination;
1836    }
1837
1838    /**
1839     * Copies the character array into the specified array.
1840     *
1841     * @param startIndex       first index to copy, inclusive, must be valid
1842     * @param endIndex         last index, exclusive, must be valid
1843     * @param destination      the destination array, must not be null or too small
1844     * @param destinationIndex the index to start copying in destination
1845     * @throws NullPointerException      if the array is null
1846     * @throws IndexOutOfBoundsException if any index is invalid
1847     */
1848    public void getChars(final int startIndex, final int endIndex, final char[] destination, final int destinationIndex) {
1849        if (startIndex < 0) {
1850            throw new StringIndexOutOfBoundsException(startIndex);
1851        }
1852        if (endIndex < 0 || endIndex > length()) {
1853            throw new StringIndexOutOfBoundsException(endIndex);
1854        }
1855        if (startIndex > endIndex) {
1856            throw new StringIndexOutOfBoundsException("end < start");
1857        }
1858        System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
1859    }
1860
1861    /**
1862     * Gets the text to be appended when a {@link #appendNewLine() new line} is added.
1863     *
1864     * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
1865     */
1866    public String getNewLineText() {
1867        return newLine;
1868    }
1869
1870    /**
1871     * Gets the text to be appended when null is added.
1872     *
1873     * @return The null text, null means no append
1874     */
1875    public String getNullText() {
1876        return nullText;
1877    }
1878
1879    /**
1880     * Gets a suitable hash code for this builder.
1881     *
1882     * @return a hash code
1883     */
1884    @Override
1885    public int hashCode() {
1886        final char[] buf = buffer;
1887        int hash = 0;
1888        for (int i = size - 1; i >= 0; i--) {
1889            hash = 31 * hash + buf[i];
1890        }
1891        return hash;
1892    }
1893
1894    /**
1895     * Searches the string builder to find the first reference to the specified char.
1896     *
1897     * @param ch the character to find
1898     * @return The first index of the character, or -1 if not found
1899     */
1900    public int indexOf(final char ch) {
1901        return indexOf(ch, 0);
1902    }
1903
1904    /**
1905     * Searches the string builder to find the first reference to the specified char.
1906     *
1907     * @param ch         the character to find
1908     * @param startIndex the index to start at, invalid index rounded to edge
1909     * @return The first index of the character, or -1 if not found
1910     */
1911    public int indexOf(final char ch, int startIndex) {
1912        startIndex = Math.max(startIndex, 0);
1913        if (startIndex >= size) {
1914            return -1;
1915        }
1916        final char[] thisBuf = buffer;
1917        for (int i = startIndex; i < size; i++) {
1918            if (thisBuf[i] == ch) {
1919                return i;
1920            }
1921        }
1922        return -1;
1923    }
1924
1925    /**
1926     * Searches the string builder to find the first reference to the specified string.
1927     * <p>
1928     * Note that a null input string will return -1, whereas the JDK throws an exception.
1929     * </p>
1930     *
1931     * @param str the string to find, null returns -1
1932     * @return The first index of the string, or -1 if not found
1933     */
1934    public int indexOf(final String str) {
1935        return indexOf(str, 0);
1936    }
1937
1938    /**
1939     * Searches the string builder to find the first reference to the specified string starting searching from the given index.
1940     * <p>
1941     * Note that a null input string will return -1, whereas the JDK throws an exception.
1942     * </p>
1943     *
1944     * @param str        the string to find, null returns -1
1945     * @param startIndex the index to start at, invalid index rounded to edge
1946     * @return The first index of the string, or -1 if not found
1947     */
1948    public int indexOf(final String str, int startIndex) {
1949        startIndex = Math.max(startIndex, 0);
1950        if (str == null || startIndex >= size) {
1951            return -1;
1952        }
1953        final int strLen = str.length();
1954        if (strLen == 1) {
1955            return indexOf(str.charAt(0), startIndex);
1956        }
1957        if (strLen == 0) {
1958            return startIndex;
1959        }
1960        if (strLen > size) {
1961            return -1;
1962        }
1963        final char[] thisBuf = buffer;
1964        final int len = size - strLen + 1;
1965        outer: for (int i = startIndex; i < len; i++) {
1966            for (int j = 0; j < strLen; j++) {
1967                if (str.charAt(j) != thisBuf[i + j]) {
1968                    continue outer;
1969                }
1970            }
1971            return i;
1972        }
1973        return -1;
1974    }
1975
1976    /**
1977     * Searches the string builder using the matcher to find the first match.
1978     * <p>
1979     * 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.
1980     * </p>
1981     *
1982     * @param matcher the matcher to use, null returns -1
1983     * @return The first index matched, or -1 if not found
1984     */
1985    public int indexOf(final StrMatcher matcher) {
1986        return indexOf(matcher, 0);
1987    }
1988
1989    /**
1990     * Searches the string builder using the matcher to find the first match searching from the given index.
1991     * <p>
1992     * 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.
1993     * </p>
1994     *
1995     * @param matcher    the matcher to use, null returns -1
1996     * @param startIndex the index to start at, invalid index rounded to edge
1997     * @return The first index matched, or -1 if not found
1998     */
1999    public int indexOf(final StrMatcher matcher, int startIndex) {
2000        startIndex = Math.max(startIndex, 0);
2001        if (matcher == null || startIndex >= size) {
2002            return -1;
2003        }
2004        final int len = size;
2005        final char[] buf = buffer;
2006        for (int i = startIndex; i < len; i++) {
2007            if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2008                return i;
2009            }
2010        }
2011        return -1;
2012    }
2013
2014    /**
2015     * Inserts the value into this builder.
2016     *
2017     * @param index the index to add at, must be valid
2018     * @param value the value to insert
2019     * @return {@code this} instance.
2020     * @throws IndexOutOfBoundsException if the index is invalid
2021     */
2022    public StrBuilder insert(int index, final boolean value) {
2023        validateIndex(index);
2024        if (value) {
2025            ensureCapacity(size + 4);
2026            System.arraycopy(buffer, index, buffer, index + 4, size - index);
2027            buffer[index++] = 't';
2028            buffer[index++] = 'r';
2029            buffer[index++] = 'u';
2030            buffer[index] = 'e';
2031            size += 4;
2032        } else {
2033            ensureCapacity(size + 5);
2034            System.arraycopy(buffer, index, buffer, index + 5, size - index);
2035            buffer[index++] = 'f';
2036            buffer[index++] = 'a';
2037            buffer[index++] = 'l';
2038            buffer[index++] = 's';
2039            buffer[index] = 'e';
2040            size += 5;
2041        }
2042        return this;
2043    }
2044
2045    /**
2046     * Inserts the value into this builder.
2047     *
2048     * @param index the index to add at, must be valid
2049     * @param value the value to insert
2050     * @return {@code this} instance.
2051     * @throws IndexOutOfBoundsException if the index is invalid
2052     */
2053    public StrBuilder insert(final int index, final char value) {
2054        validateIndex(index);
2055        ensureCapacity(size + 1);
2056        System.arraycopy(buffer, index, buffer, index + 1, size - index);
2057        buffer[index] = value;
2058        size++;
2059        return this;
2060    }
2061
2062    /**
2063     * Inserts the character array into this builder. Inserting null will use the stored null text value.
2064     *
2065     * @param index the index to add at, must be valid
2066     * @param chars the char array to insert
2067     * @return {@code this} instance.
2068     * @throws IndexOutOfBoundsException if the index is invalid
2069     */
2070    public StrBuilder insert(final int index, final char[] chars) {
2071        validateIndex(index);
2072        if (chars == null) {
2073            return insert(index, nullText);
2074        }
2075        final int len = chars.length;
2076        if (len > 0) {
2077            ensureCapacity(size + len);
2078            System.arraycopy(buffer, index, buffer, index + len, size - index);
2079            System.arraycopy(chars, 0, buffer, index, len);
2080            size += len;
2081        }
2082        return this;
2083    }
2084
2085    /**
2086     * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
2087     *
2088     * @param index  the index to add at, must be valid
2089     * @param chars  the char array to insert
2090     * @param offset the offset into the character array to start at, must be valid
2091     * @param length the length of the character array part to copy, must be positive
2092     * @return {@code this} instance.
2093     * @throws IndexOutOfBoundsException if any index is invalid
2094     */
2095    public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2096        validateIndex(index);
2097        if (chars == null) {
2098            return insert(index, nullText);
2099        }
2100        if (offset < 0 || offset > chars.length) {
2101            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2102        }
2103        if (length < 0 || offset + length > chars.length) {
2104            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2105        }
2106        if (length > 0) {
2107            ensureCapacity(size + length);
2108            System.arraycopy(buffer, index, buffer, index + length, size - index);
2109            System.arraycopy(chars, offset, buffer, index, length);
2110            size += length;
2111        }
2112        return this;
2113    }
2114
2115    /**
2116     * Inserts the value into this builder.
2117     *
2118     * @param index the index to add at, must be valid
2119     * @param value the value to insert
2120     * @return {@code this} instance.
2121     * @throws IndexOutOfBoundsException if the index is invalid
2122     */
2123    public StrBuilder insert(final int index, final double value) {
2124        return insert(index, String.valueOf(value));
2125    }
2126
2127    /**
2128     * Inserts the value into this builder.
2129     *
2130     * @param index the index to add at, must be valid
2131     * @param value the value to insert
2132     * @return {@code this} instance.
2133     * @throws IndexOutOfBoundsException if the index is invalid
2134     */
2135    public StrBuilder insert(final int index, final float value) {
2136        return insert(index, String.valueOf(value));
2137    }
2138
2139    /**
2140     * Inserts the value into this builder.
2141     *
2142     * @param index the index to add at, must be valid
2143     * @param value the value to insert
2144     * @return {@code this} instance.
2145     * @throws IndexOutOfBoundsException if the index is invalid
2146     */
2147    public StrBuilder insert(final int index, final int value) {
2148        return insert(index, String.valueOf(value));
2149    }
2150
2151    /**
2152     * Inserts the value into this builder.
2153     *
2154     * @param index the index to add at, must be valid
2155     * @param value the value to insert
2156     * @return {@code this} instance.
2157     * @throws IndexOutOfBoundsException if the index is invalid
2158     */
2159    public StrBuilder insert(final int index, final long value) {
2160        return insert(index, String.valueOf(value));
2161    }
2162
2163    /**
2164     * Inserts the string representation of an object into this builder. Inserting null will use the stored null text value.
2165     *
2166     * @param index the index to add at, must be valid
2167     * @param obj   the object to insert
2168     * @return {@code this} instance.
2169     * @throws IndexOutOfBoundsException if the index is invalid
2170     */
2171    public StrBuilder insert(final int index, final Object obj) {
2172        if (obj == null) {
2173            return insert(index, nullText);
2174        }
2175        return insert(index, obj.toString());
2176    }
2177
2178    /**
2179     * Inserts the string into this builder. Inserting null will use the stored null text value.
2180     *
2181     * @param index the index to add at, must be valid
2182     * @param str   the string to insert
2183     * @return {@code this} instance.
2184     * @throws IndexOutOfBoundsException if the index is invalid
2185     */
2186    public StrBuilder insert(final int index, String str) {
2187        validateIndex(index);
2188        if (str == null) {
2189            str = nullText;
2190        }
2191        if (str != null) {
2192            final int strLen = str.length();
2193            if (strLen > 0) {
2194                final int newSize = size + strLen;
2195                ensureCapacity(newSize);
2196                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2197                size = newSize;
2198                str.getChars(0, strLen, buffer, index);
2199            }
2200        }
2201        return this;
2202    }
2203
2204    /**
2205     * Tests if the string builder is empty (convenience Collections API style method).
2206     * <p>
2207     * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2208     * </p>
2209     *
2210     * @return {@code true} if the size is {@code 0}.
2211     */
2212    public boolean isEmpty() {
2213        return size == 0;
2214    }
2215
2216    /**
2217     * Tests if the string builder is not empty (convenience Collections API style method).
2218     * <p>
2219     * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2220     * </p>
2221     *
2222     * @return {@code true} if the size is greater than {@code 0}.
2223     * @since 1.10.0
2224     */
2225    public boolean isNotEmpty() {
2226        return size > 0;
2227    }
2228
2229    /**
2230     * Searches the string builder to find the last reference to the specified char.
2231     *
2232     * @param ch the character to find
2233     * @return The last index of the character, or -1 if not found
2234     */
2235    public int lastIndexOf(final char ch) {
2236        return lastIndexOf(ch, size - 1);
2237    }
2238
2239    /**
2240     * Searches the string builder to find the last reference to the specified char.
2241     *
2242     * @param ch         the character to find
2243     * @param startIndex the index to start at, invalid index rounded to edge
2244     * @return The last index of the character, or -1 if not found
2245     */
2246    public int lastIndexOf(final char ch, int startIndex) {
2247        startIndex = startIndex >= size ? size - 1 : startIndex;
2248        if (startIndex < 0) {
2249            return -1;
2250        }
2251        for (int i = startIndex; i >= 0; i--) {
2252            if (buffer[i] == ch) {
2253                return i;
2254            }
2255        }
2256        return -1;
2257    }
2258
2259    /**
2260     * Searches the string builder to find the last reference to the specified string.
2261     * <p>
2262     * Note that a null input string will return -1, whereas the JDK throws an exception.
2263     * </p>
2264     *
2265     * @param str the string to find, null returns -1
2266     * @return The last index of the string, or -1 if not found
2267     */
2268    public int lastIndexOf(final String str) {
2269        return lastIndexOf(str, size - 1);
2270    }
2271
2272    /**
2273     * Searches the string builder to find the last reference to the specified string starting searching from the given index.
2274     * <p>
2275     * Note that a null input string will return -1, whereas the JDK throws an exception.
2276     * </p>
2277     *
2278     * @param str        the string to find, null returns -1
2279     * @param startIndex the index to start at, invalid index rounded to edge
2280     * @return The last index of the string, or -1 if not found
2281     */
2282    public int lastIndexOf(final String str, int startIndex) {
2283        startIndex = startIndex >= size ? size - 1 : startIndex;
2284        if (str == null || startIndex < 0) {
2285            return -1;
2286        }
2287        final int strLen = str.length();
2288        if (strLen > 0 && strLen <= size) {
2289            if (strLen == 1) {
2290                return lastIndexOf(str.charAt(0), startIndex);
2291            }
2292
2293            outer: for (int i = startIndex - strLen + 1; i >= 0; i--) {
2294                for (int j = 0; j < strLen; j++) {
2295                    if (str.charAt(j) != buffer[i + j]) {
2296                        continue outer;
2297                    }
2298                }
2299                return i;
2300            }
2301
2302        } else if (strLen == 0) {
2303            return startIndex;
2304        }
2305        return -1;
2306    }
2307
2308    /**
2309     * Searches the string builder using the matcher to find the last match.
2310     * <p>
2311     * 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.
2312     * </p>
2313     *
2314     * @param matcher the matcher to use, null returns -1
2315     * @return The last index matched, or -1 if not found
2316     */
2317    public int lastIndexOf(final StrMatcher matcher) {
2318        return lastIndexOf(matcher, size);
2319    }
2320
2321    /**
2322     * Searches the string builder using the matcher to find the last match searching from the given index.
2323     * <p>
2324     * 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.
2325     * </p>
2326     *
2327     * @param matcher    the matcher to use, null returns -1
2328     * @param startIndex the index to start at, invalid index rounded to edge
2329     * @return The last index matched, or -1 if not found
2330     */
2331    public int lastIndexOf(final StrMatcher matcher, int startIndex) {
2332        startIndex = startIndex >= size ? size - 1 : startIndex;
2333        if (matcher == null || startIndex < 0) {
2334            return -1;
2335        }
2336        final char[] buf = buffer;
2337        final int endIndex = startIndex + 1;
2338        for (int i = startIndex; i >= 0; i--) {
2339            if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2340                return i;
2341            }
2342        }
2343        return -1;
2344    }
2345
2346    /**
2347     * Extracts the leftmost characters from the string builder without throwing an exception.
2348     * <p>
2349     * This method extracts the left {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus
2350     * the returned string may be shorter than the length requested.
2351     * </p>
2352     *
2353     * @param length the number of characters to extract, negative returns empty string
2354     * @return The new string
2355     */
2356    public String leftString(final int length) {
2357        if (length <= 0) {
2358            return StringUtils.EMPTY;
2359        }
2360        if (length >= size) {
2361            return new String(buffer, 0, size);
2362        }
2363        return new String(buffer, 0, length);
2364    }
2365
2366    /**
2367     * Gets the length of the string builder.
2368     *
2369     * @return The length
2370     */
2371    @Override
2372    public int length() {
2373        return size;
2374    }
2375
2376    /**
2377     * Extracts some characters from the middle of the string builder without throwing an exception.
2378     * <p>
2379     * 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
2380     * 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
2381     * available in the builder, as much as possible is returned. Thus the returned string may be shorter than the length requested.
2382     * </p>
2383     *
2384     * @param index  the index to start at, negative means zero
2385     * @param length the number of characters to extract, negative returns empty string
2386     * @return The new string
2387     */
2388    public String midString(int index, final int length) {
2389        if (index < 0) {
2390            index = 0;
2391        }
2392        if (length <= 0 || index >= size) {
2393            return StringUtils.EMPTY;
2394        }
2395        if (size <= index + length) {
2396            return new String(buffer, index, size - index);
2397        }
2398        return new String(buffer, index, length);
2399    }
2400
2401    /**
2402     * Minimizes the capacity to the actual length of the string.
2403     *
2404     * @return {@code this} instance.
2405     */
2406    public StrBuilder minimizeCapacity() {
2407        if (buffer.length > length()) {
2408            final char[] old = buffer;
2409            buffer = new char[length()];
2410            System.arraycopy(old, 0, buffer, 0, size);
2411        }
2412        return this;
2413    }
2414
2415    /**
2416     * If possible, reads chars from the provided {@link Readable} directly into underlying character buffer without making extra copies.
2417     *
2418     * @param readable object to read from
2419     * @return The number of characters read
2420     * @throws IOException if an I/O error occurs.
2421     * @see #appendTo(Appendable)
2422     */
2423    public int readFrom(final Readable readable) throws IOException {
2424        final int oldSize = size;
2425        if (readable instanceof Reader) {
2426            final Reader r = (Reader) readable;
2427            ensureCapacity(size + 1);
2428            int read;
2429            while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
2430                size += read;
2431                ensureCapacity(size + 1);
2432            }
2433        } else if (readable instanceof CharBuffer) {
2434            final CharBuffer cb = (CharBuffer) readable;
2435            final int remaining = cb.remaining();
2436            ensureCapacity(size + remaining);
2437            cb.get(buffer, size, remaining);
2438            size += remaining;
2439        } else {
2440            while (true) {
2441                ensureCapacity(size + 1);
2442                final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2443                final int read = readable.read(buf);
2444                if (read == -1) {
2445                    break;
2446                }
2447                size += read;
2448            }
2449        }
2450        return size - oldSize;
2451    }
2452
2453    /**
2454     * Replaces a portion of the string builder with another string. The length of the inserted string does not have to match the removed length.
2455     *
2456     * @param startIndex the start index, inclusive, must be valid
2457     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2458     * @param replaceStr the string to replace with, null means delete range
2459     * @return {@code this} instance.
2460     * @throws IndexOutOfBoundsException if the index is invalid
2461     */
2462    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
2463        endIndex = validateRange(startIndex, endIndex);
2464        final int insertLen = replaceStr == null ? 0 : replaceStr.length();
2465        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
2466        return this;
2467    }
2468
2469    /**
2470     * Advanced search and replaces within the builder using a matcher.
2471     * <p>
2472     * 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
2473     * a number.
2474     * </p>
2475     *
2476     * @param matcher      the matcher to use to find the deletion, null causes no action
2477     * @param replaceStr   the string to replace the match with, null is a delete
2478     * @param startIndex   the start index, inclusive, must be valid
2479     * @param endIndex     the end index, exclusive, must be valid except that if too large it is treated as end of string
2480     * @param replaceCount the number of times to replace, -1 for replace all
2481     * @return {@code this} instance.
2482     * @throws IndexOutOfBoundsException if start index is invalid
2483     */
2484    public StrBuilder replace(final StrMatcher matcher, final String replaceStr, final int startIndex, int endIndex, final int replaceCount) {
2485        endIndex = validateRange(startIndex, endIndex);
2486        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2487    }
2488
2489    /**
2490     * Replaces the search character with the replace character throughout the builder.
2491     *
2492     * @param search  the search character
2493     * @param replace the replace character
2494     * @return {@code this} instance.
2495     */
2496    public StrBuilder replaceAll(final char search, final char replace) {
2497        if (search != replace) {
2498            for (int i = 0; i < size; i++) {
2499                if (buffer[i] == search) {
2500                    buffer[i] = replace;
2501                }
2502            }
2503        }
2504        return this;
2505    }
2506
2507    /**
2508     * Replaces the search string with the replace string throughout the builder.
2509     *
2510     * @param searchStr  the search string, null causes no action to occur
2511     * @param replaceStr the replace string, null is equivalent to an empty string
2512     * @return {@code this} instance.
2513     */
2514    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
2515        final int searchLen = searchStr == null ? 0 : searchStr.length();
2516        if (searchLen > 0) {
2517            final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2518            int index = indexOf(searchStr, 0);
2519            while (index >= 0) {
2520                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2521                index = indexOf(searchStr, index + replaceLen);
2522            }
2523        }
2524        return this;
2525    }
2526
2527    /**
2528     * Replaces all matches within the builder with the replace string.
2529     * <p>
2530     * 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
2531     * followed by a number.
2532     * </p>
2533     *
2534     * @param matcher    the matcher to use to find the deletion, null causes no action
2535     * @param replaceStr the replace string, null is equivalent to an empty string
2536     * @return {@code this} instance.
2537     */
2538    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
2539        return replace(matcher, replaceStr, 0, size, -1);
2540    }
2541
2542    /**
2543     * Replaces the first instance of the search character with the replace character in the builder.
2544     *
2545     * @param search  the search character
2546     * @param replace the replace character
2547     * @return {@code this} instance.
2548     */
2549    public StrBuilder replaceFirst(final char search, final char replace) {
2550        if (search != replace) {
2551            for (int i = 0; i < size; i++) {
2552                if (buffer[i] == search) {
2553                    buffer[i] = replace;
2554                    break;
2555                }
2556            }
2557        }
2558        return this;
2559    }
2560
2561    /**
2562     * Replaces the first instance of the search string with the replace string.
2563     *
2564     * @param searchStr  the search string, null causes no action to occur
2565     * @param replaceStr the replace string, null is equivalent to an empty string
2566     * @return {@code this} instance.
2567     */
2568    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
2569        final int searchLen = searchStr == null ? 0 : searchStr.length();
2570        if (searchLen > 0) {
2571            final int index = indexOf(searchStr, 0);
2572            if (index >= 0) {
2573                final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2574                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2575            }
2576        }
2577        return this;
2578    }
2579
2580    /**
2581     * Replaces the first match within the builder with the replace string.
2582     * <p>
2583     * 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
2584     * number.
2585     * </p>
2586     *
2587     * @param matcher    the matcher to use to find the deletion, null causes no action
2588     * @param replaceStr the replace string, null is equivalent to an empty string
2589     * @return {@code this} instance.
2590     */
2591    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
2592        return replace(matcher, replaceStr, 0, size, 1);
2593    }
2594
2595    /**
2596     * Internal method to delete a range without validation.
2597     *
2598     * @param startIndex the start index, must be valid
2599     * @param endIndex   the end index (exclusive), must be valid
2600     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
2601     * @param insertStr  the string to replace with, null means delete range
2602     * @param insertLen  the length of the insert string, must be valid
2603     * @throws IndexOutOfBoundsException if any index is invalid
2604     */
2605    private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) {
2606        final int newSize = size - removeLen + insertLen;
2607        if (insertLen != removeLen) {
2608            ensureCapacity(newSize);
2609            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
2610            size = newSize;
2611        }
2612        if (insertLen > 0) {
2613            insertStr.getChars(0, insertLen, buffer, startIndex);
2614        }
2615    }
2616
2617    /**
2618     * Replaces within the builder using a matcher.
2619     * <p>
2620     * 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
2621     * a number.
2622     * </p>
2623     *
2624     * @param matcher      the matcher to use to find the deletion, null causes no action
2625     * @param replaceStr   the string to replace the match with, null is a delete
2626     * @param from         the start index, must be valid
2627     * @param to           the end index (exclusive), must be valid
2628     * @param replaceCount the number of times to replace, -1 for replace all
2629     * @return {@code this} instance.
2630     * @throws IndexOutOfBoundsException if any index is invalid
2631     */
2632    private StrBuilder replaceImpl(final StrMatcher matcher, final String replaceStr, final int from, int to, int replaceCount) {
2633        if (matcher == null || size == 0) {
2634            return this;
2635        }
2636        final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2637        for (int i = from; i < to && replaceCount != 0; i++) {
2638            final char[] buf = buffer;
2639            final int removeLen = matcher.isMatch(buf, i, from, to);
2640            if (removeLen > 0) {
2641                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2642                to = to - removeLen + replaceLen;
2643                i = i + replaceLen - 1;
2644                if (replaceCount > 0) {
2645                    replaceCount--;
2646                }
2647            }
2648        }
2649        return this;
2650    }
2651
2652    /**
2653     * Reverses the string builder placing each character in the opposite index.
2654     *
2655     * @return {@code this} instance.
2656     */
2657    public StrBuilder reverse() {
2658        if (size == 0) {
2659            return this;
2660        }
2661
2662        final int half = size / 2;
2663        final char[] buf = buffer;
2664        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2665            final char swap = buf[leftIdx];
2666            buf[leftIdx] = buf[rightIdx];
2667            buf[rightIdx] = swap;
2668        }
2669        return this;
2670    }
2671
2672    /**
2673     * Extracts the rightmost characters from the string builder without throwing an exception.
2674     * <p>
2675     * This method extracts the right {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus
2676     * the returned string may be shorter than the length requested.
2677     * </p>
2678     *
2679     * @param length the number of characters to extract, negative returns empty string
2680     * @return The new string
2681     */
2682    public String rightString(final int length) {
2683        if (length <= 0) {
2684            return StringUtils.EMPTY;
2685        }
2686        if (length >= size) {
2687            return new String(buffer, 0, size);
2688        }
2689        return new String(buffer, size - length, length);
2690    }
2691
2692    /**
2693     * Sets the character at the specified index.
2694     *
2695     * @see #charAt(int)
2696     * @see #deleteCharAt(int)
2697     * @param index the index to set
2698     * @param ch    the new character
2699     * @return {@code this} instance.
2700     * @throws IndexOutOfBoundsException if the index is invalid
2701     */
2702    public StrBuilder setCharAt(final int index, final char ch) {
2703        if (index < 0 || index >= length()) {
2704            throw new StringIndexOutOfBoundsException(index);
2705        }
2706        buffer[index] = ch;
2707        return this;
2708    }
2709
2710    /**
2711     * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero.
2712     *
2713     * @param length the length to set to, must be zero or positive
2714     * @return {@code this} instance.
2715     * @throws IndexOutOfBoundsException if the length is negative
2716     */
2717    public StrBuilder setLength(final int length) {
2718        if (length < 0) {
2719            throw new StringIndexOutOfBoundsException(length);
2720        }
2721        if (length < size) {
2722            size = length;
2723        } else if (length > size) {
2724            ensureCapacity(length);
2725            Arrays.fill(buffer, size, length, CharUtils.NUL);
2726            size = length;
2727        }
2728        return this;
2729    }
2730
2731    /**
2732     * Sets the text to be appended when {@link #appendNewLine() new line} is called.
2733     *
2734     * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
2735     * @return {@code this} instance.
2736     */
2737    public StrBuilder setNewLineText(final String newLine) {
2738        this.newLine = newLine;
2739        return this;
2740    }
2741
2742    /**
2743     * Sets the text to be appended when null is added.
2744     *
2745     * @param nullText the null text, null means no append
2746     * @return {@code this} instance.
2747     */
2748    public StrBuilder setNullText(String nullText) {
2749        if (nullText != null && nullText.isEmpty()) {
2750            nullText = null;
2751        }
2752        this.nullText = nullText;
2753        return this;
2754    }
2755
2756    /**
2757     * Gets the length of the string builder.
2758     * <p>
2759     * This method is the same as {@link #length()} and is provided to match the API of Collections.
2760     * </p>
2761     *
2762     * @return The length
2763     */
2764    public int size() {
2765        return size;
2766    }
2767
2768    /**
2769     * Checks whether this builder starts with the specified string.
2770     * <p>
2771     * Note that this method handles null input quietly, unlike String.
2772     * </p>
2773     *
2774     * @param str the string to search for, null returns false
2775     * @return true if the builder starts with the string
2776     */
2777    public boolean startsWith(final String str) {
2778        if (str == null) {
2779            return false;
2780        }
2781        final int len = str.length();
2782        if (len == 0) {
2783            return true;
2784        }
2785        if (len > size) {
2786            return false;
2787        }
2788        for (int i = 0; i < len; i++) {
2789            if (buffer[i] != str.charAt(i)) {
2790                return false;
2791            }
2792        }
2793        return true;
2794    }
2795
2796    /**
2797     * {@inheritDoc}
2798     */
2799    @Override
2800    public CharSequence subSequence(final int startIndex, final int endIndex) {
2801        if (startIndex < 0) {
2802            throw new StringIndexOutOfBoundsException(startIndex);
2803        }
2804        if (endIndex > size) {
2805            throw new StringIndexOutOfBoundsException(endIndex);
2806        }
2807        if (startIndex > endIndex) {
2808            throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2809        }
2810        return substring(startIndex, endIndex);
2811    }
2812
2813    /**
2814     * Extracts a portion of this string builder as a string.
2815     *
2816     * @param start the start index, inclusive, must be valid
2817     * @return The new string
2818     * @throws IndexOutOfBoundsException if the index is invalid
2819     */
2820    public String substring(final int start) {
2821        return substring(start, size);
2822    }
2823
2824    /**
2825     * Extracts a portion of this string builder as a string.
2826     * <p>
2827     * 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
2828     * StringBuffer or String.
2829     *
2830     * @param startIndex the start index, inclusive, must be valid
2831     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2832     * @return The new string
2833     * @throws IndexOutOfBoundsException if the index is invalid
2834     */
2835    public String substring(final int startIndex, int endIndex) {
2836        endIndex = validateRange(startIndex, endIndex);
2837        return new String(buffer, startIndex, endIndex - startIndex);
2838    }
2839
2840    /**
2841     * Copies the builder's character array into a new character array.
2842     *
2843     * @return a new array that represents the contents of the builder
2844     */
2845    public char[] toCharArray() {
2846        return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size);
2847    }
2848
2849    /**
2850     * Copies part of the builder's character array into a new character array.
2851     *
2852     * @param startIndex the start index, inclusive, must be valid
2853     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2854     * @return a new array that holds part of the contents of the builder
2855     * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than size is valid)
2856     */
2857    public char[] toCharArray(final int startIndex, int endIndex) {
2858        endIndex = validateRange(startIndex, endIndex);
2859        final int len = endIndex - startIndex;
2860        if (len == 0) {
2861            return ArrayUtils.EMPTY_CHAR_ARRAY;
2862        }
2863        final char[] chars = new char[len];
2864        System.arraycopy(buffer, startIndex, chars, 0, len);
2865        return chars;
2866    }
2867
2868    /**
2869     * Gets a String version of the string builder, creating a new instance each time the method is called.
2870     * <p>
2871     * Note that unlike StringBuffer, the string version returned is independent of the string builder.
2872     * </p>
2873     *
2874     * @return The builder as a String
2875     */
2876    @Override
2877    public String toString() {
2878        return new String(buffer, 0, size);
2879    }
2880
2881    /**
2882     * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called.
2883     *
2884     * @return The builder as a StringBuffer
2885     */
2886    public StringBuffer toStringBuffer() {
2887        return new StringBuffer(size).append(buffer, 0, size);
2888    }
2889
2890    /**
2891     * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called.
2892     *
2893     * @return The builder as a StringBuilder
2894     */
2895    public StringBuilder toStringBuilder() {
2896        return new StringBuilder(size).append(buffer, 0, size);
2897    }
2898
2899    /**
2900     * Trims the builder by removing characters less than or equal to a space from the beginning and end.
2901     *
2902     * @return {@code this} instance.
2903     */
2904    public StrBuilder trim() {
2905        if (size == 0) {
2906            return this;
2907        }
2908        int len = size;
2909        final char[] buf = buffer;
2910        int pos = 0;
2911        while (pos < len && buf[pos] <= ' ') {
2912            pos++;
2913        }
2914        while (pos < len && buf[len - 1] <= ' ') {
2915            len--;
2916        }
2917        if (len < size) {
2918            delete(len, size);
2919        }
2920        if (pos > 0) {
2921            delete(0, pos);
2922        }
2923        return this;
2924    }
2925
2926    /**
2927     * Validates parameters defining a single index in the builder.
2928     *
2929     * @param index the index, must be valid
2930     * @throws IndexOutOfBoundsException if the index is invalid
2931     */
2932    protected void validateIndex(final int index) {
2933        if (index < 0 || index > size) {
2934            throw new StringIndexOutOfBoundsException(index);
2935        }
2936    }
2937
2938    /**
2939     * Validates parameters defining a range of the builder.
2940     *
2941     * @param startIndex the start index, inclusive, must be valid
2942     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2943     * @return The new string
2944     * @throws IndexOutOfBoundsException if the index is invalid
2945     */
2946    protected int validateRange(final int startIndex, int endIndex) {
2947        if (startIndex < 0) {
2948            throw new StringIndexOutOfBoundsException(startIndex);
2949        }
2950        if (endIndex > size) {
2951            endIndex = size;
2952        }
2953        if (startIndex > endIndex) {
2954            throw new StringIndexOutOfBoundsException("end < start");
2955        }
2956        return endIndex;
2957    }
2958
2959}