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