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