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