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 *      https://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(0, startIndex);
1950        if (str == null || startIndex >= size) {
1951            return StringUtils.INDEX_NOT_FOUND;
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 StringUtils.INDEX_NOT_FOUND;
1962        }
1963        final char[] thisBuf = buffer;
1964        final int searchLen = size - strLen + 1;
1965        for (int i = startIndex; i < searchLen; i++) {
1966            boolean found = true;
1967            for (int j = 0; j < strLen && found; j++) {
1968                found = str.charAt(j) == thisBuf[i + j];
1969            }
1970            if (found) {
1971                return i;
1972            }
1973        }
1974        return StringUtils.INDEX_NOT_FOUND;
1975    }
1976
1977    /**
1978     * Searches the string builder using the matcher to find the first match.
1979     * <p>
1980     * 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.
1981     * </p>
1982     *
1983     * @param matcher the matcher to use, null returns -1
1984     * @return The first index matched, or -1 if not found
1985     */
1986    public int indexOf(final StrMatcher matcher) {
1987        return indexOf(matcher, 0);
1988    }
1989
1990    /**
1991     * Searches the string builder using the matcher to find the first match searching from the given index.
1992     * <p>
1993     * 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.
1994     * </p>
1995     *
1996     * @param matcher    the matcher to use, null returns -1
1997     * @param startIndex the index to start at, invalid index rounded to edge
1998     * @return The first index matched, or -1 if not found
1999     */
2000    public int indexOf(final StrMatcher matcher, int startIndex) {
2001        startIndex = Math.max(startIndex, 0);
2002        if (matcher == null || startIndex >= size) {
2003            return -1;
2004        }
2005        final int len = size;
2006        final char[] buf = buffer;
2007        for (int i = startIndex; i < len; i++) {
2008            if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2009                return i;
2010            }
2011        }
2012        return -1;
2013    }
2014
2015    /**
2016     * Inserts the value into this builder.
2017     *
2018     * @param index the index to add at, must be valid
2019     * @param value the value to insert
2020     * @return {@code this} instance.
2021     * @throws IndexOutOfBoundsException if the index is invalid
2022     */
2023    public StrBuilder insert(int index, final boolean value) {
2024        validateIndex(index);
2025        if (value) {
2026            ensureCapacity(size + 4);
2027            System.arraycopy(buffer, index, buffer, index + 4, size - index);
2028            buffer[index++] = 't';
2029            buffer[index++] = 'r';
2030            buffer[index++] = 'u';
2031            buffer[index] = 'e';
2032            size += 4;
2033        } else {
2034            ensureCapacity(size + 5);
2035            System.arraycopy(buffer, index, buffer, index + 5, size - index);
2036            buffer[index++] = 'f';
2037            buffer[index++] = 'a';
2038            buffer[index++] = 'l';
2039            buffer[index++] = 's';
2040            buffer[index] = 'e';
2041            size += 5;
2042        }
2043        return this;
2044    }
2045
2046    /**
2047     * Inserts the value into this builder.
2048     *
2049     * @param index the index to add at, must be valid
2050     * @param value the value to insert
2051     * @return {@code this} instance.
2052     * @throws IndexOutOfBoundsException if the index is invalid
2053     */
2054    public StrBuilder insert(final int index, final char value) {
2055        validateIndex(index);
2056        ensureCapacity(size + 1);
2057        System.arraycopy(buffer, index, buffer, index + 1, size - index);
2058        buffer[index] = value;
2059        size++;
2060        return this;
2061    }
2062
2063    /**
2064     * Inserts the character array into this builder. Inserting null will use the stored null text value.
2065     *
2066     * @param index the index to add at, must be valid
2067     * @param chars the char array to insert
2068     * @return {@code this} instance.
2069     * @throws IndexOutOfBoundsException if the index is invalid
2070     */
2071    public StrBuilder insert(final int index, final char[] chars) {
2072        validateIndex(index);
2073        if (chars == null) {
2074            return insert(index, nullText);
2075        }
2076        final int len = chars.length;
2077        if (len > 0) {
2078            ensureCapacity(size + len);
2079            System.arraycopy(buffer, index, buffer, index + len, size - index);
2080            System.arraycopy(chars, 0, buffer, index, len);
2081            size += len;
2082        }
2083        return this;
2084    }
2085
2086    /**
2087     * Inserts part of the character array into this builder. Inserting null will use the stored null text value.
2088     *
2089     * @param index  the index to add at, must be valid
2090     * @param chars  the char array to insert
2091     * @param offset the offset into the character array to start at, must be valid
2092     * @param length the length of the character array part to copy, must be positive
2093     * @return {@code this} instance.
2094     * @throws IndexOutOfBoundsException if any index is invalid
2095     */
2096    public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2097        validateIndex(index);
2098        if (chars == null) {
2099            return insert(index, nullText);
2100        }
2101        if (offset < 0 || offset > chars.length) {
2102            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2103        }
2104        if (length < 0 || offset + length > chars.length) {
2105            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2106        }
2107        if (length > 0) {
2108            ensureCapacity(size + length);
2109            System.arraycopy(buffer, index, buffer, index + length, size - index);
2110            System.arraycopy(chars, offset, buffer, index, length);
2111            size += length;
2112        }
2113        return this;
2114    }
2115
2116    /**
2117     * Inserts the value into this builder.
2118     *
2119     * @param index the index to add at, must be valid
2120     * @param value the value to insert
2121     * @return {@code this} instance.
2122     * @throws IndexOutOfBoundsException if the index is invalid
2123     */
2124    public StrBuilder insert(final int index, final double value) {
2125        return insert(index, String.valueOf(value));
2126    }
2127
2128    /**
2129     * Inserts the value into this builder.
2130     *
2131     * @param index the index to add at, must be valid
2132     * @param value the value to insert
2133     * @return {@code this} instance.
2134     * @throws IndexOutOfBoundsException if the index is invalid
2135     */
2136    public StrBuilder insert(final int index, final float value) {
2137        return insert(index, String.valueOf(value));
2138    }
2139
2140    /**
2141     * Inserts the value into this builder.
2142     *
2143     * @param index the index to add at, must be valid
2144     * @param value the value to insert
2145     * @return {@code this} instance.
2146     * @throws IndexOutOfBoundsException if the index is invalid
2147     */
2148    public StrBuilder insert(final int index, final int value) {
2149        return insert(index, String.valueOf(value));
2150    }
2151
2152    /**
2153     * Inserts the value into this builder.
2154     *
2155     * @param index the index to add at, must be valid
2156     * @param value the value to insert
2157     * @return {@code this} instance.
2158     * @throws IndexOutOfBoundsException if the index is invalid
2159     */
2160    public StrBuilder insert(final int index, final long value) {
2161        return insert(index, String.valueOf(value));
2162    }
2163
2164    /**
2165     * Inserts the string representation of an object into this builder. Inserting null will use the stored null text value.
2166     *
2167     * @param index the index to add at, must be valid
2168     * @param obj   the object to insert
2169     * @return {@code this} instance.
2170     * @throws IndexOutOfBoundsException if the index is invalid
2171     */
2172    public StrBuilder insert(final int index, final Object obj) {
2173        if (obj == null) {
2174            return insert(index, nullText);
2175        }
2176        return insert(index, obj.toString());
2177    }
2178
2179    /**
2180     * Inserts the string into this builder. Inserting null will use the stored null text value.
2181     *
2182     * @param index the index to add at, must be valid
2183     * @param str   the string to insert
2184     * @return {@code this} instance.
2185     * @throws IndexOutOfBoundsException if the index is invalid
2186     */
2187    public StrBuilder insert(final int index, String str) {
2188        validateIndex(index);
2189        if (str == null) {
2190            str = nullText;
2191        }
2192        if (str != null) {
2193            final int strLen = str.length();
2194            if (strLen > 0) {
2195                final int newSize = size + strLen;
2196                ensureCapacity(newSize);
2197                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2198                size = newSize;
2199                str.getChars(0, strLen, buffer, index);
2200            }
2201        }
2202        return this;
2203    }
2204
2205    /**
2206     * Tests if the string builder is empty (convenience Collections API style method).
2207     * <p>
2208     * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2209     * </p>
2210     *
2211     * @return {@code true} if the size is {@code 0}.
2212     */
2213    public boolean isEmpty() {
2214        return size == 0;
2215    }
2216
2217    /**
2218     * Tests if the string builder is not empty (convenience Collections API style method).
2219     * <p>
2220     * This method is the same as checking {@link #length()} and is provided to match the API of Collections.
2221     * </p>
2222     *
2223     * @return {@code true} if the size is greater than {@code 0}.
2224     * @since 1.10.0
2225     */
2226    public boolean isNotEmpty() {
2227        return size > 0;
2228    }
2229
2230    /**
2231     * Searches the string builder to find the last reference to the specified char.
2232     *
2233     * @param ch the character to find
2234     * @return The last index of the character, or -1 if not found
2235     */
2236    public int lastIndexOf(final char ch) {
2237        return lastIndexOf(ch, size - 1);
2238    }
2239
2240    /**
2241     * Searches the string builder to find the last reference to the specified char.
2242     *
2243     * @param ch         the character to find
2244     * @param startIndex the index to start at, invalid index rounded to edge
2245     * @return The last index of the character, or -1 if not found
2246     */
2247    public int lastIndexOf(final char ch, int startIndex) {
2248        startIndex = startIndex >= size ? size - 1 : startIndex;
2249        if (startIndex < 0) {
2250            return -1;
2251        }
2252        for (int i = startIndex; i >= 0; i--) {
2253            if (buffer[i] == ch) {
2254                return i;
2255            }
2256        }
2257        return -1;
2258    }
2259
2260    /**
2261     * Searches the string builder to find the last reference to the specified string.
2262     * <p>
2263     * Note that a null input string will return -1, whereas the JDK throws an exception.
2264     * </p>
2265     *
2266     * @param str the string to find, null returns -1
2267     * @return The last index of the string, or -1 if not found
2268     */
2269    public int lastIndexOf(final String str) {
2270        return lastIndexOf(str, size - 1);
2271    }
2272
2273    /**
2274     * Searches the string builder to find the last reference to the specified string starting searching from the given index.
2275     * <p>
2276     * Note that a null input string will return -1, whereas the JDK throws an exception.
2277     * </p>
2278     *
2279     * @param str        the string to find, null returns -1
2280     * @param startIndex the index to start at, invalid index rounded to edge
2281     * @return The last index of the string, or -1 if not found
2282     */
2283    public int lastIndexOf(final String str, int startIndex) {
2284        startIndex = startIndex >= size ? size - 1 : startIndex;
2285        if (str == null || startIndex < 0) {
2286            return StringUtils.INDEX_NOT_FOUND;
2287        }
2288        final int strLen = str.length();
2289        if (strLen == 0) {
2290            return startIndex;
2291        }
2292        if (strLen > size) {
2293            return StringUtils.INDEX_NOT_FOUND;
2294        }
2295        if (strLen == 1) {
2296            return lastIndexOf(str.charAt(0), startIndex);
2297        }
2298        for (int i = startIndex - strLen + 1; i >= 0; i--) {
2299            boolean found = true;
2300            for (int j = 0; j < strLen && found; j++) {
2301                found = str.charAt(j) == buffer[i + j];
2302            }
2303            if (found) {
2304                return i;
2305            }
2306        }
2307        return StringUtils.INDEX_NOT_FOUND;
2308    }
2309
2310    /**
2311     * Searches the string builder using the matcher to find the last match.
2312     * <p>
2313     * 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.
2314     * </p>
2315     *
2316     * @param matcher the matcher to use, null returns -1
2317     * @return The last index matched, or -1 if not found
2318     */
2319    public int lastIndexOf(final StrMatcher matcher) {
2320        return lastIndexOf(matcher, size);
2321    }
2322
2323    /**
2324     * Searches the string builder using the matcher to find the last match searching from the given index.
2325     * <p>
2326     * 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.
2327     * </p>
2328     *
2329     * @param matcher    the matcher to use, null returns -1
2330     * @param startIndex the index to start at, invalid index rounded to edge
2331     * @return The last index matched, or -1 if not found
2332     */
2333    public int lastIndexOf(final StrMatcher matcher, int startIndex) {
2334        startIndex = startIndex >= size ? size - 1 : startIndex;
2335        if (matcher == null || startIndex < 0) {
2336            return -1;
2337        }
2338        final char[] buf = buffer;
2339        final int endIndex = startIndex + 1;
2340        for (int i = startIndex; i >= 0; i--) {
2341            if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2342                return i;
2343            }
2344        }
2345        return -1;
2346    }
2347
2348    /**
2349     * Extracts the leftmost characters from the string builder without throwing an exception.
2350     * <p>
2351     * This method extracts the left {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus
2352     * the returned string may be shorter than the length requested.
2353     * </p>
2354     *
2355     * @param length the number of characters to extract, negative returns empty string
2356     * @return The new string
2357     */
2358    public String leftString(final int length) {
2359        if (length <= 0) {
2360            return StringUtils.EMPTY;
2361        }
2362        if (length >= size) {
2363            return new String(buffer, 0, size);
2364        }
2365        return new String(buffer, 0, length);
2366    }
2367
2368    /**
2369     * Gets the length of the string builder.
2370     *
2371     * @return The length
2372     */
2373    @Override
2374    public int length() {
2375        return size;
2376    }
2377
2378    /**
2379     * Extracts some characters from the middle of the string builder without throwing an exception.
2380     * <p>
2381     * 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
2382     * 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
2383     * available in the builder, as much as possible is returned. Thus the returned string may be shorter than the length requested.
2384     * </p>
2385     *
2386     * @param index  the index to start at, negative means zero
2387     * @param length the number of characters to extract, negative returns empty string
2388     * @return The new string
2389     */
2390    public String midString(int index, final int length) {
2391        if (index < 0) {
2392            index = 0;
2393        }
2394        if (length <= 0 || index >= size) {
2395            return StringUtils.EMPTY;
2396        }
2397        if (size <= index + length) {
2398            return new String(buffer, index, size - index);
2399        }
2400        return new String(buffer, index, length);
2401    }
2402
2403    /**
2404     * Minimizes the capacity to the actual length of the string.
2405     *
2406     * @return {@code this} instance.
2407     */
2408    public StrBuilder minimizeCapacity() {
2409        if (buffer.length > length()) {
2410            final char[] old = buffer;
2411            buffer = new char[length()];
2412            System.arraycopy(old, 0, buffer, 0, size);
2413        }
2414        return this;
2415    }
2416
2417    /**
2418     * If possible, reads chars from the provided {@link Readable} directly into underlying character buffer without making extra copies.
2419     *
2420     * @param readable object to read from
2421     * @return The number of characters read
2422     * @throws IOException if an I/O error occurs.
2423     * @see #appendTo(Appendable)
2424     */
2425    public int readFrom(final Readable readable) throws IOException {
2426        final int oldSize = size;
2427        if (readable instanceof Reader) {
2428            final Reader r = (Reader) readable;
2429            ensureCapacity(size + 1);
2430            int read;
2431            while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
2432                size += read;
2433                ensureCapacity(size + 1);
2434            }
2435        } else if (readable instanceof CharBuffer) {
2436            final CharBuffer cb = (CharBuffer) readable;
2437            final int remaining = cb.remaining();
2438            ensureCapacity(size + remaining);
2439            cb.get(buffer, size, remaining);
2440            size += remaining;
2441        } else {
2442            while (true) {
2443                ensureCapacity(size + 1);
2444                final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2445                final int read = readable.read(buf);
2446                if (read == -1) {
2447                    break;
2448                }
2449                size += read;
2450            }
2451        }
2452        return size - oldSize;
2453    }
2454
2455    /**
2456     * Replaces a portion of the string builder with another string. The length of the inserted string does not have to match the removed length.
2457     *
2458     * @param startIndex the start index, inclusive, must be valid
2459     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2460     * @param replaceStr the string to replace with, null means delete range
2461     * @return {@code this} instance.
2462     * @throws IndexOutOfBoundsException if the index is invalid
2463     */
2464    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
2465        endIndex = validateRange(startIndex, endIndex);
2466        final int insertLen = replaceStr == null ? 0 : replaceStr.length();
2467        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
2468        return this;
2469    }
2470
2471    /**
2472     * Advanced search and replaces within the builder using a matcher.
2473     * <p>
2474     * 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
2475     * a number.
2476     * </p>
2477     *
2478     * @param matcher      the matcher to use to find the deletion, null causes no action
2479     * @param replaceStr   the string to replace the match with, null is a delete
2480     * @param startIndex   the start index, inclusive, must be valid
2481     * @param endIndex     the end index, exclusive, must be valid except that if too large it is treated as end of string
2482     * @param replaceCount the number of times to replace, -1 for replace all
2483     * @return {@code this} instance.
2484     * @throws IndexOutOfBoundsException if start index is invalid
2485     */
2486    public StrBuilder replace(final StrMatcher matcher, final String replaceStr, final int startIndex, int endIndex, final int replaceCount) {
2487        endIndex = validateRange(startIndex, endIndex);
2488        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2489    }
2490
2491    /**
2492     * Replaces the search character with the replace character throughout the builder.
2493     *
2494     * @param search  the search character
2495     * @param replace the replace character
2496     * @return {@code this} instance.
2497     */
2498    public StrBuilder replaceAll(final char search, final char replace) {
2499        if (search != replace) {
2500            for (int i = 0; i < size; i++) {
2501                if (buffer[i] == search) {
2502                    buffer[i] = replace;
2503                }
2504            }
2505        }
2506        return this;
2507    }
2508
2509    /**
2510     * Replaces the search string with the replace string throughout the builder.
2511     *
2512     * @param searchStr  the search string, null causes no action to occur
2513     * @param replaceStr the replace string, null is equivalent to an empty string
2514     * @return {@code this} instance.
2515     */
2516    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
2517        final int searchLen = searchStr == null ? 0 : searchStr.length();
2518        if (searchLen > 0) {
2519            final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2520            int index = indexOf(searchStr, 0);
2521            while (index >= 0) {
2522                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2523                index = indexOf(searchStr, index + replaceLen);
2524            }
2525        }
2526        return this;
2527    }
2528
2529    /**
2530     * Replaces all matches within the builder with the replace string.
2531     * <p>
2532     * 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
2533     * followed by a number.
2534     * </p>
2535     *
2536     * @param matcher    the matcher to use to find the deletion, null causes no action
2537     * @param replaceStr the replace string, null is equivalent to an empty string
2538     * @return {@code this} instance.
2539     */
2540    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
2541        return replace(matcher, replaceStr, 0, size, -1);
2542    }
2543
2544    /**
2545     * Replaces the first instance of the search character with the replace character in the builder.
2546     *
2547     * @param search  the search character
2548     * @param replace the replace character
2549     * @return {@code this} instance.
2550     */
2551    public StrBuilder replaceFirst(final char search, final char replace) {
2552        if (search != replace) {
2553            for (int i = 0; i < size; i++) {
2554                if (buffer[i] == search) {
2555                    buffer[i] = replace;
2556                    break;
2557                }
2558            }
2559        }
2560        return this;
2561    }
2562
2563    /**
2564     * Replaces the first instance of the search string with the replace string.
2565     *
2566     * @param searchStr  the search string, null causes no action to occur
2567     * @param replaceStr the replace string, null is equivalent to an empty string
2568     * @return {@code this} instance.
2569     */
2570    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
2571        final int searchLen = searchStr == null ? 0 : searchStr.length();
2572        if (searchLen > 0) {
2573            final int index = indexOf(searchStr, 0);
2574            if (index >= 0) {
2575                final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2576                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2577            }
2578        }
2579        return this;
2580    }
2581
2582    /**
2583     * Replaces the first match within the builder with the replace string.
2584     * <p>
2585     * 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
2586     * number.
2587     * </p>
2588     *
2589     * @param matcher    the matcher to use to find the deletion, null causes no action
2590     * @param replaceStr the replace string, null is equivalent to an empty string
2591     * @return {@code this} instance.
2592     */
2593    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
2594        return replace(matcher, replaceStr, 0, size, 1);
2595    }
2596
2597    /**
2598     * Internal method to delete a range without validation.
2599     *
2600     * @param startIndex the start index, must be valid
2601     * @param endIndex   the end index (exclusive), must be valid
2602     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
2603     * @param insertStr  the string to replace with, null means delete range
2604     * @param insertLen  the length of the insert string, must be valid
2605     * @throws IndexOutOfBoundsException if any index is invalid
2606     */
2607    private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) {
2608        final int newSize = size - removeLen + insertLen;
2609        if (insertLen != removeLen) {
2610            ensureCapacity(newSize);
2611            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
2612            size = newSize;
2613        }
2614        if (insertLen > 0) {
2615            insertStr.getChars(0, insertLen, buffer, startIndex);
2616        }
2617    }
2618
2619    /**
2620     * Replaces within the builder using a matcher.
2621     * <p>
2622     * 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
2623     * a number.
2624     * </p>
2625     *
2626     * @param matcher      the matcher to use to find the deletion, null causes no action
2627     * @param replaceStr   the string to replace the match with, null is a delete
2628     * @param from         the start index, must be valid
2629     * @param to           the end index (exclusive), must be valid
2630     * @param replaceCount the number of times to replace, -1 for replace all
2631     * @return {@code this} instance.
2632     * @throws IndexOutOfBoundsException if any index is invalid
2633     */
2634    private StrBuilder replaceImpl(final StrMatcher matcher, final String replaceStr, final int from, int to, int replaceCount) {
2635        if (matcher == null || size == 0) {
2636            return this;
2637        }
2638        final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2639        for (int i = from; i < to && replaceCount != 0; i++) {
2640            final char[] buf = buffer;
2641            final int removeLen = matcher.isMatch(buf, i, from, to);
2642            if (removeLen > 0) {
2643                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2644                to = to - removeLen + replaceLen;
2645                i = i + replaceLen - 1;
2646                if (replaceCount > 0) {
2647                    replaceCount--;
2648                }
2649            }
2650        }
2651        return this;
2652    }
2653
2654    /**
2655     * Reverses the string builder placing each character in the opposite index.
2656     *
2657     * @return {@code this} instance.
2658     */
2659    public StrBuilder reverse() {
2660        if (size == 0) {
2661            return this;
2662        }
2663
2664        final int half = size / 2;
2665        final char[] buf = buffer;
2666        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2667            final char swap = buf[leftIdx];
2668            buf[leftIdx] = buf[rightIdx];
2669            buf[rightIdx] = swap;
2670        }
2671        return this;
2672    }
2673
2674    /**
2675     * Extracts the rightmost characters from the string builder without throwing an exception.
2676     * <p>
2677     * This method extracts the right {@code length} characters from the builder. If this many characters are not available, the whole builder is returned. Thus
2678     * the returned string may be shorter than the length requested.
2679     * </p>
2680     *
2681     * @param length the number of characters to extract, negative returns empty string
2682     * @return The new string
2683     */
2684    public String rightString(final int length) {
2685        if (length <= 0) {
2686            return StringUtils.EMPTY;
2687        }
2688        if (length >= size) {
2689            return new String(buffer, 0, size);
2690        }
2691        return new String(buffer, size - length, length);
2692    }
2693
2694    /**
2695     * Sets the character at the specified index.
2696     *
2697     * @see #charAt(int)
2698     * @see #deleteCharAt(int)
2699     * @param index the index to set
2700     * @param ch    the new character
2701     * @return {@code this} instance.
2702     * @throws IndexOutOfBoundsException if the index is invalid
2703     */
2704    public StrBuilder setCharAt(final int index, final char ch) {
2705        if (index < 0 || index >= length()) {
2706            throw new StringIndexOutOfBoundsException(index);
2707        }
2708        buffer[index] = ch;
2709        return this;
2710    }
2711
2712    /**
2713     * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero.
2714     *
2715     * @param length the length to set to, must be zero or positive
2716     * @return {@code this} instance.
2717     * @throws IndexOutOfBoundsException if the length is negative
2718     */
2719    public StrBuilder setLength(final int length) {
2720        if (length < 0) {
2721            throw new StringIndexOutOfBoundsException(length);
2722        }
2723        if (length < size) {
2724            size = length;
2725        } else if (length > size) {
2726            ensureCapacity(length);
2727            Arrays.fill(buffer, size, length, CharUtils.NUL);
2728            size = length;
2729        }
2730        return this;
2731    }
2732
2733    /**
2734     * Sets the text to be appended when {@link #appendNewLine() new line} is called.
2735     *
2736     * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}.
2737     * @return {@code this} instance.
2738     */
2739    public StrBuilder setNewLineText(final String newLine) {
2740        this.newLine = newLine;
2741        return this;
2742    }
2743
2744    /**
2745     * Sets the text to be appended when null is added.
2746     *
2747     * @param nullText the null text, null means no append
2748     * @return {@code this} instance.
2749     */
2750    public StrBuilder setNullText(String nullText) {
2751        if (nullText != null && nullText.isEmpty()) {
2752            nullText = null;
2753        }
2754        this.nullText = nullText;
2755        return this;
2756    }
2757
2758    /**
2759     * Gets the length of the string builder.
2760     * <p>
2761     * This method is the same as {@link #length()} and is provided to match the API of Collections.
2762     * </p>
2763     *
2764     * @return The length
2765     */
2766    public int size() {
2767        return size;
2768    }
2769
2770    /**
2771     * Checks whether this builder starts with the specified string.
2772     * <p>
2773     * Note that this method handles null input quietly, unlike String.
2774     * </p>
2775     *
2776     * @param str the string to search for, null returns false
2777     * @return true if the builder starts with the string
2778     */
2779    public boolean startsWith(final String str) {
2780        if (str == null) {
2781            return false;
2782        }
2783        final int len = str.length();
2784        if (len == 0) {
2785            return true;
2786        }
2787        if (len > size) {
2788            return false;
2789        }
2790        for (int i = 0; i < len; i++) {
2791            if (buffer[i] != str.charAt(i)) {
2792                return false;
2793            }
2794        }
2795        return true;
2796    }
2797
2798    /**
2799     * {@inheritDoc}
2800     */
2801    @Override
2802    public CharSequence subSequence(final int startIndex, final int endIndex) {
2803        if (startIndex < 0) {
2804            throw new StringIndexOutOfBoundsException(startIndex);
2805        }
2806        if (endIndex > size) {
2807            throw new StringIndexOutOfBoundsException(endIndex);
2808        }
2809        if (startIndex > endIndex) {
2810            throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2811        }
2812        return substring(startIndex, endIndex);
2813    }
2814
2815    /**
2816     * Extracts a portion of this string builder as a string.
2817     *
2818     * @param start the start index, inclusive, must be valid
2819     * @return The new string
2820     * @throws IndexOutOfBoundsException if the index is invalid
2821     */
2822    public String substring(final int start) {
2823        return substring(start, size);
2824    }
2825
2826    /**
2827     * Extracts a portion of this string builder as a string.
2828     * <p>
2829     * 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
2830     * StringBuffer or String.
2831     *
2832     * @param startIndex the start index, inclusive, must be valid
2833     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2834     * @return The new string
2835     * @throws IndexOutOfBoundsException if the index is invalid
2836     */
2837    public String substring(final int startIndex, int endIndex) {
2838        endIndex = validateRange(startIndex, endIndex);
2839        return new String(buffer, startIndex, endIndex - startIndex);
2840    }
2841
2842    /**
2843     * Copies the builder's character array into a new character array.
2844     *
2845     * @return a new array that represents the contents of the builder
2846     */
2847    public char[] toCharArray() {
2848        return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size);
2849    }
2850
2851    /**
2852     * Copies part of the builder's character array into a new character array.
2853     *
2854     * @param startIndex the start index, inclusive, must be valid
2855     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2856     * @return a new array that holds part of the contents of the builder
2857     * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than size is valid)
2858     */
2859    public char[] toCharArray(final int startIndex, int endIndex) {
2860        endIndex = validateRange(startIndex, endIndex);
2861        final int len = endIndex - startIndex;
2862        if (len == 0) {
2863            return ArrayUtils.EMPTY_CHAR_ARRAY;
2864        }
2865        final char[] chars = new char[len];
2866        System.arraycopy(buffer, startIndex, chars, 0, len);
2867        return chars;
2868    }
2869
2870    /**
2871     * Gets a String version of the string builder, creating a new instance each time the method is called.
2872     * <p>
2873     * Note that unlike StringBuffer, the string version returned is independent of the string builder.
2874     * </p>
2875     *
2876     * @return The builder as a String
2877     */
2878    @Override
2879    public String toString() {
2880        return new String(buffer, 0, size);
2881    }
2882
2883    /**
2884     * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called.
2885     *
2886     * @return The builder as a StringBuffer
2887     */
2888    public StringBuffer toStringBuffer() {
2889        return new StringBuffer(size).append(buffer, 0, size);
2890    }
2891
2892    /**
2893     * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called.
2894     *
2895     * @return The builder as a StringBuilder
2896     */
2897    public StringBuilder toStringBuilder() {
2898        return new StringBuilder(size).append(buffer, 0, size);
2899    }
2900
2901    /**
2902     * Trims the builder by removing characters less than or equal to a space from the beginning and end.
2903     *
2904     * @return {@code this} instance.
2905     */
2906    public StrBuilder trim() {
2907        if (size == 0) {
2908            return this;
2909        }
2910        int len = size;
2911        final char[] buf = buffer;
2912        int pos = 0;
2913        while (pos < len && buf[pos] <= ' ') {
2914            pos++;
2915        }
2916        while (pos < len && buf[len - 1] <= ' ') {
2917            len--;
2918        }
2919        if (len < size) {
2920            delete(len, size);
2921        }
2922        if (pos > 0) {
2923            delete(0, pos);
2924        }
2925        return this;
2926    }
2927
2928    /**
2929     * Validates parameters defining a single index in the builder.
2930     *
2931     * @param index the index, must be valid
2932     * @throws IndexOutOfBoundsException if the index is invalid
2933     */
2934    protected void validateIndex(final int index) {
2935        if (index < 0 || index > size) {
2936            throw new StringIndexOutOfBoundsException(index);
2937        }
2938    }
2939
2940    /**
2941     * Validates parameters defining a range of the builder.
2942     *
2943     * @param startIndex the start index, inclusive, must be valid
2944     * @param endIndex   the end index, exclusive, must be valid except that if too large it is treated as end of string
2945     * @return The new string
2946     * @throws IndexOutOfBoundsException if the index is invalid
2947     */
2948    protected int validateRange(final int startIndex, int endIndex) {
2949        if (startIndex < 0) {
2950            throw new StringIndexOutOfBoundsException(startIndex);
2951        }
2952        if (endIndex > size) {
2953            endIndex = size;
2954        }
2955        if (startIndex > endIndex) {
2956            throw new StringIndexOutOfBoundsException("end < start");
2957        }
2958        return endIndex;
2959    }
2960
2961}