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    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    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    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     * Builds a string.
1514     *
1515     * @return The builder as a String
1516     * @see #toString()
1517     */
1518    @Override
1519    public String build() {
1520        return toString();
1521    }
1522
1523    /**
1524     * Gets the current size of the internal character array buffer.
1525     *
1526     * @return The capacity
1527     */
1528    public int capacity() {
1529        return buffer.length;
1530    }
1531
1532    /**
1533     * Gets the character at the specified index.
1534     *
1535     * @see #setCharAt(int, char)
1536     * @see #deleteCharAt(int)
1537     * @param index  the index to retrieve, must be valid
1538     * @return The character at the index
1539     * @throws IndexOutOfBoundsException if the index is invalid
1540     */
1541    @Override
1542    public char charAt(final int index) {
1543        if (index < 0 || index >= length()) {
1544            throw new StringIndexOutOfBoundsException(index);
1545        }
1546        return buffer[index];
1547    }
1548
1549    /**
1550     * Clears the string builder (convenience Collections API style method).
1551     * <p>
1552     * This method does not reduce the size of the internal character buffer.
1553     * To do that, call {@code clear()} followed by {@link #minimizeCapacity()}.
1554     * </p>
1555     * <p>
1556     * This method is the same as {@link #setLength(int)} called with zero
1557     * and is provided to match the API of Collections.
1558     * </p>
1559     *
1560     * @return this, to enable chaining
1561     */
1562    public StrBuilder clear() {
1563        size = 0;
1564        return this;
1565    }
1566
1567    /**
1568     * Checks if the string builder contains the specified char.
1569     *
1570     * @param ch  the character to find
1571     * @return true if the builder contains the character
1572     */
1573    public boolean contains(final char ch) {
1574        final char[] thisBuf = buffer;
1575        for (int i = 0; i < this.size; i++) {
1576            if (thisBuf[i] == ch) {
1577                return true;
1578            }
1579        }
1580        return false;
1581    }
1582
1583    /**
1584     * Tests if the string builder contains the specified string.
1585     *
1586     * @param str  the string to find
1587     * @return true if the builder contains the string
1588     */
1589    public boolean contains(final String str) {
1590        return indexOf(str, 0) >= 0;
1591    }
1592
1593    /**
1594     * Tests if the string builder contains a string matched using the
1595     * specified matcher.
1596     * <p>
1597     * Matchers can be used to perform advanced searching behavior.
1598     * For example you could write a matcher to search for the character
1599     * 'a' followed by a number.
1600     * </p>
1601     *
1602     * @param matcher  the matcher to use, null returns -1
1603     * @return true if the matcher finds a match in the builder
1604     */
1605    public boolean contains(final StrMatcher matcher) {
1606        return indexOf(matcher, 0) >= 0;
1607    }
1608
1609    /**
1610     * Deletes the characters between the two specified indices.
1611     *
1612     * @param startIndex  the start index, inclusive, must be valid
1613     * @param endIndex  the end index, exclusive, must be valid except
1614     *  that if too large it is treated as end of string
1615     * @return this, to enable chaining
1616     * @throws IndexOutOfBoundsException if the index is invalid
1617     */
1618    public StrBuilder delete(final int startIndex, int endIndex) {
1619        endIndex = validateRange(startIndex, endIndex);
1620        final int len = endIndex - startIndex;
1621        if (len > 0) {
1622            deleteImpl(startIndex, endIndex, len);
1623        }
1624        return this;
1625    }
1626
1627    /**
1628     * Deletes the character wherever it occurs in the builder.
1629     *
1630     * @param ch  the character to delete
1631     * @return this, to enable chaining
1632     */
1633    public StrBuilder deleteAll(final char ch) {
1634        for (int i = 0; i < size; i++) {
1635            if (buffer[i] == ch) {
1636                final int start = i;
1637                while (++i < size) {
1638                    if (buffer[i] != ch) {
1639                        break;
1640                    }
1641                }
1642                final int len = i - start;
1643                deleteImpl(start, i, len);
1644                i -= len;
1645            }
1646        }
1647        return this;
1648    }
1649
1650    /**
1651     * Deletes the string wherever it occurs in the builder.
1652     *
1653     * @param str  the string to delete, null causes no action
1654     * @return this, to enable chaining
1655     */
1656    public StrBuilder deleteAll(final String str) {
1657        final int len = str == null ? 0 : str.length();
1658        if (len > 0) {
1659            int index = indexOf(str, 0);
1660            while (index >= 0) {
1661                deleteImpl(index, index + len, len);
1662                index = indexOf(str, index);
1663            }
1664        }
1665        return this;
1666    }
1667
1668    /**
1669     * Deletes all parts of the builder that the matcher matches.
1670     * <p>
1671     * Matchers can be used to perform advanced deletion behavior.
1672     * For example you could write a matcher to delete all occurrences
1673     * where the character 'a' is followed by a number.
1674     * </p>
1675     *
1676     * @param matcher  the matcher to use to find the deletion, null causes no action
1677     * @return this, to enable chaining
1678     */
1679    public StrBuilder deleteAll(final StrMatcher matcher) {
1680        return replace(matcher, null, 0, size, -1);
1681    }
1682
1683    /**
1684     * Deletes the character at the specified index.
1685     *
1686     * @see #charAt(int)
1687     * @see #setCharAt(int, char)
1688     * @param index  the index to delete
1689     * @return this, to enable chaining
1690     * @throws IndexOutOfBoundsException if the index is invalid
1691     */
1692    public StrBuilder deleteCharAt(final int index) {
1693        if (index < 0 || index >= size) {
1694            throw new StringIndexOutOfBoundsException(index);
1695        }
1696        deleteImpl(index, index + 1, 1);
1697        return this;
1698    }
1699
1700    /**
1701     * Deletes the character wherever it occurs in the builder.
1702     *
1703     * @param ch  the character to delete
1704     * @return this, to enable chaining
1705     */
1706    public StrBuilder deleteFirst(final char ch) {
1707        for (int i = 0; i < size; i++) {
1708            if (buffer[i] == ch) {
1709                deleteImpl(i, i + 1, 1);
1710                break;
1711            }
1712        }
1713        return this;
1714    }
1715
1716    /**
1717     * Deletes the string wherever it occurs in the builder.
1718     *
1719     * @param str  the string to delete, null causes no action
1720     * @return this, to enable chaining
1721     */
1722    public StrBuilder deleteFirst(final String str) {
1723        final int len = str == null ? 0 : str.length();
1724        if (len > 0) {
1725            final int index = indexOf(str, 0);
1726            if (index >= 0) {
1727                deleteImpl(index, index + len, len);
1728            }
1729        }
1730        return this;
1731    }
1732
1733    /**
1734     * Deletes the first match within the builder using the specified matcher.
1735     * <p>
1736     * Matchers can be used to perform advanced deletion behavior.
1737     * For example you could write a matcher to delete
1738     * where the character 'a' is followed by a number.
1739     * </p>
1740     *
1741     * @param matcher  the matcher to use to find the deletion, null causes no action
1742     * @return this, to enable chaining
1743     */
1744    public StrBuilder deleteFirst(final StrMatcher matcher) {
1745        return replace(matcher, null, 0, size, 1);
1746    }
1747
1748    /**
1749     * Internal method to delete a range without validation.
1750     *
1751     * @param startIndex  the start index, must be valid
1752     * @param endIndex  the end index (exclusive), must be valid
1753     * @param len  the length, must be valid
1754     * @throws IndexOutOfBoundsException if any index is invalid
1755     */
1756    private void deleteImpl(final int startIndex, final int endIndex, final int len) {
1757        System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex);
1758        size -= len;
1759    }
1760
1761    /**
1762     * Tests whether this builder ends with the specified string.
1763     * <p>
1764     * Note that this method handles null input quietly, unlike String.
1765     * </p>
1766     *
1767     * @param str  the string to search for, null returns false
1768     * @return true if the builder ends with the string
1769     */
1770    public boolean endsWith(final String str) {
1771        if (str == null) {
1772            return false;
1773        }
1774        final int len = str.length();
1775        if (len == 0) {
1776            return true;
1777        }
1778        if (len > size) {
1779            return false;
1780        }
1781        int pos = size - len;
1782        for (int i = 0; i < len; i++, pos++) {
1783            if (buffer[pos] != str.charAt(i)) {
1784                return false;
1785            }
1786        }
1787        return true;
1788    }
1789
1790    /**
1791     * Tests the capacity and ensures that it is at least the size specified.
1792     *
1793     * @param capacity  the capacity to ensure
1794     * @return this, to enable chaining
1795     */
1796    public StrBuilder ensureCapacity(final int capacity) {
1797        if (capacity > buffer.length) {
1798            final char[] old = buffer;
1799            buffer = new char[capacity * 2];
1800            System.arraycopy(old, 0, buffer, 0, size);
1801        }
1802        return this;
1803    }
1804
1805    /**
1806     * Tests the contents of this builder against another to see if they
1807     * contain the same character content.
1808     *
1809     * @param obj  the object to check, null returns false
1810     * @return true if the builders contain the same characters in the same order
1811     */
1812    @Override
1813    public boolean equals(final Object obj) {
1814        return obj instanceof StrBuilder
1815                && equals((StrBuilder) obj);
1816    }
1817
1818    /**
1819     * Tests the contents of this builder against another to see if they
1820     * contain the same character content.
1821     *
1822     * @param other  the object to check, null returns false
1823     * @return true if the builders contain the same characters in the same order
1824     */
1825    public boolean equals(final StrBuilder other) {
1826        if (this == other) {
1827            return true;
1828        }
1829        if (other == null) {
1830            return false;
1831        }
1832        if (this.size != other.size) {
1833            return false;
1834        }
1835        final char[] thisBuf = this.buffer;
1836        final char[] otherBuf = other.buffer;
1837        for (int i = size - 1; i >= 0; i--) {
1838            if (thisBuf[i] != otherBuf[i]) {
1839                return false;
1840            }
1841        }
1842        return true;
1843    }
1844
1845    /**
1846     * Tests the contents of this builder against another to see if they
1847     * contain the same character content ignoring case.
1848     *
1849     * @param other  the object to check, null returns false
1850     * @return true if the builders contain the same characters in the same order
1851     */
1852    public boolean equalsIgnoreCase(final StrBuilder other) {
1853        if (this == other) {
1854            return true;
1855        }
1856        if (this.size != other.size) {
1857            return false;
1858        }
1859        final char[] thisBuf = this.buffer;
1860        final char[] otherBuf = other.buffer;
1861        for (int i = size - 1; i >= 0; i--) {
1862            final char c1 = thisBuf[i];
1863            final char c2 = otherBuf[i];
1864            if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) {
1865                return false;
1866            }
1867        }
1868        return true;
1869    }
1870
1871    /**
1872     * Copies the character array into the specified array.
1873     *
1874     * @param destination  the destination array, null will cause an array to be created
1875     * @return The input array, unless that was null or too small
1876     */
1877    public char[] getChars(char[] destination) {
1878        final int len = length();
1879        if (destination == null || destination.length < len) {
1880            destination = new char[len];
1881        }
1882        System.arraycopy(buffer, 0, destination, 0, len);
1883        return destination;
1884    }
1885
1886    /**
1887     * Copies the character array into the specified array.
1888     *
1889     * @param startIndex  first index to copy, inclusive, must be valid
1890     * @param endIndex  last index, exclusive, must be valid
1891     * @param destination  the destination array, must not be null or too small
1892     * @param destinationIndex  the index to start copying in destination
1893     * @throws NullPointerException if the array is null
1894     * @throws IndexOutOfBoundsException if any index is invalid
1895     */
1896    public void getChars(final int startIndex,
1897                         final int endIndex,
1898                         final char[] destination,
1899                         final int destinationIndex) {
1900        if (startIndex < 0) {
1901            throw new StringIndexOutOfBoundsException(startIndex);
1902        }
1903        if (endIndex < 0 || endIndex > length()) {
1904            throw new StringIndexOutOfBoundsException(endIndex);
1905        }
1906        if (startIndex > endIndex) {
1907            throw new StringIndexOutOfBoundsException("end < start");
1908        }
1909        System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex);
1910    }
1911
1912    /**
1913     * Gets the text to be appended when a new line is added.
1914     *
1915     * @return The new line text, null means use system default
1916     */
1917    public String getNewLineText() {
1918        return newLine;
1919    }
1920
1921    /**
1922     * Gets the text to be appended when null is added.
1923     *
1924     * @return The null text, null means no append
1925     */
1926    public String getNullText() {
1927        return nullText;
1928    }
1929
1930    /**
1931     * Gets a suitable hash code for this builder.
1932     *
1933     * @return a hash code
1934     */
1935    @Override
1936    public int hashCode() {
1937        final char[] buf = buffer;
1938        int hash = 0;
1939        for (int i = size - 1; i >= 0; i--) {
1940            hash = 31 * hash + buf[i];
1941        }
1942        return hash;
1943    }
1944
1945    /**
1946     * Searches the string builder to find the first reference to the specified char.
1947     *
1948     * @param ch  the character to find
1949     * @return The first index of the character, or -1 if not found
1950     */
1951    public int indexOf(final char ch) {
1952        return indexOf(ch, 0);
1953    }
1954
1955    /**
1956     * Searches the string builder to find the first reference to the specified char.
1957     *
1958     * @param ch  the character to find
1959     * @param startIndex  the index to start at, invalid index rounded to edge
1960     * @return The first index of the character, or -1 if not found
1961     */
1962    public int indexOf(final char ch, int startIndex) {
1963        startIndex = Math.max(startIndex, 0);
1964        if (startIndex >= size) {
1965            return -1;
1966        }
1967        final char[] thisBuf = buffer;
1968        for (int i = startIndex; i < size; i++) {
1969            if (thisBuf[i] == ch) {
1970                return i;
1971            }
1972        }
1973        return -1;
1974    }
1975
1976    /**
1977     * Searches the string builder to find the first reference to the specified string.
1978     * <p>
1979     * Note that a null input string will return -1, whereas the JDK throws an exception.
1980     * </p>
1981     *
1982     * @param str  the string to find, null returns -1
1983     * @return The first index of the string, or -1 if not found
1984     */
1985    public int indexOf(final String str) {
1986        return indexOf(str, 0);
1987    }
1988
1989    /**
1990     * Searches the string builder to find the first reference to the specified
1991     * string starting searching from the given index.
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     * @param startIndex  the index to start at, invalid index rounded to edge
1998     * @return The first index of the string, or -1 if not found
1999     */
2000    public int indexOf(final String str, int startIndex) {
2001        startIndex = Math.max(startIndex, 0);
2002        if (str == null || startIndex >= size) {
2003            return -1;
2004        }
2005        final int strLen = str.length();
2006        if (strLen == 1) {
2007            return indexOf(str.charAt(0), startIndex);
2008        }
2009        if (strLen == 0) {
2010            return startIndex;
2011        }
2012        if (strLen > size) {
2013            return -1;
2014        }
2015        final char[] thisBuf = buffer;
2016        final int len = size - strLen + 1;
2017        outer:
2018        for (int i = startIndex; i < len; i++) {
2019            for (int j = 0; j < strLen; j++) {
2020                if (str.charAt(j) != thisBuf[i + j]) {
2021                    continue outer;
2022                }
2023            }
2024            return i;
2025        }
2026        return -1;
2027    }
2028
2029    /**
2030     * Searches the string builder using the matcher to find the first match.
2031     * <p>
2032     * Matchers can be used to perform advanced searching behavior.
2033     * For example you could write a matcher to find the character 'a'
2034     * followed by a number.
2035     * </p>
2036     *
2037     * @param matcher  the matcher to use, null returns -1
2038     * @return The first index matched, or -1 if not found
2039     */
2040    public int indexOf(final StrMatcher matcher) {
2041        return indexOf(matcher, 0);
2042    }
2043
2044    /**
2045     * Searches the string builder using the matcher to find the first
2046     * match searching from the given index.
2047     * <p>
2048     * Matchers can be used to perform advanced searching behavior.
2049     * For example you could write a matcher to find the character 'a'
2050     * followed by a number.
2051     * </p>
2052     *
2053     * @param matcher  the matcher to use, null returns -1
2054     * @param startIndex  the index to start at, invalid index rounded to edge
2055     * @return The first index matched, or -1 if not found
2056     */
2057    public int indexOf(final StrMatcher matcher, int startIndex) {
2058        startIndex = Math.max(startIndex, 0);
2059        if (matcher == null || startIndex >= size) {
2060            return -1;
2061        }
2062        final int len = size;
2063        final char[] buf = buffer;
2064        for (int i = startIndex; i < len; i++) {
2065            if (matcher.isMatch(buf, i, startIndex, len) > 0) {
2066                return i;
2067            }
2068        }
2069        return -1;
2070    }
2071
2072    /**
2073     * Inserts the value into this builder.
2074     *
2075     * @param index  the index to add at, must be valid
2076     * @param value  the value to insert
2077     * @return this, to enable chaining
2078     * @throws IndexOutOfBoundsException if the index is invalid
2079     */
2080    public StrBuilder insert(int index, final boolean value) {
2081        validateIndex(index);
2082        if (value) {
2083            ensureCapacity(size + 4);
2084            System.arraycopy(buffer, index, buffer, index + 4, size - index);
2085            buffer[index++] = 't';
2086            buffer[index++] = 'r';
2087            buffer[index++] = 'u';
2088            buffer[index] = 'e';
2089            size += 4;
2090        } else {
2091            ensureCapacity(size + 5);
2092            System.arraycopy(buffer, index, buffer, index + 5, size - index);
2093            buffer[index++] = 'f';
2094            buffer[index++] = 'a';
2095            buffer[index++] = 'l';
2096            buffer[index++] = 's';
2097            buffer[index] = 'e';
2098            size += 5;
2099        }
2100        return this;
2101    }
2102
2103    /**
2104     * Inserts the value into this builder.
2105     *
2106     * @param index  the index to add at, must be valid
2107     * @param value  the value to insert
2108     * @return this, to enable chaining
2109     * @throws IndexOutOfBoundsException if the index is invalid
2110     */
2111    public StrBuilder insert(final int index, final char value) {
2112        validateIndex(index);
2113        ensureCapacity(size + 1);
2114        System.arraycopy(buffer, index, buffer, index + 1, size - index);
2115        buffer[index] = value;
2116        size++;
2117        return this;
2118    }
2119
2120    /**
2121     * Inserts the character array into this builder.
2122     * Inserting null will use the stored null text value.
2123     *
2124     * @param index  the index to add at, must be valid
2125     * @param chars  the char array to insert
2126     * @return this, to enable chaining
2127     * @throws IndexOutOfBoundsException if the index is invalid
2128     */
2129    public StrBuilder insert(final int index, final char[] chars) {
2130        validateIndex(index);
2131        if (chars == null) {
2132            return insert(index, nullText);
2133        }
2134        final int len = chars.length;
2135        if (len > 0) {
2136            ensureCapacity(size + len);
2137            System.arraycopy(buffer, index, buffer, index + len, size - index);
2138            System.arraycopy(chars, 0, buffer, index, len);
2139            size += len;
2140        }
2141        return this;
2142    }
2143
2144    /**
2145     * Inserts part of the character array into this builder.
2146     * Inserting null will use the stored null text value.
2147     *
2148     * @param index  the index to add at, must be valid
2149     * @param chars  the char array to insert
2150     * @param offset  the offset into the character array to start at, must be valid
2151     * @param length  the length of the character array part to copy, must be positive
2152     * @return this, to enable chaining
2153     * @throws IndexOutOfBoundsException if any index is invalid
2154     */
2155    public StrBuilder insert(final int index, final char[] chars, final int offset, final int length) {
2156        validateIndex(index);
2157        if (chars == null) {
2158            return insert(index, nullText);
2159        }
2160        if (offset < 0 || offset > chars.length) {
2161            throw new StringIndexOutOfBoundsException("Invalid offset: " + offset);
2162        }
2163        if (length < 0 || offset + length > chars.length) {
2164            throw new StringIndexOutOfBoundsException("Invalid length: " + length);
2165        }
2166        if (length > 0) {
2167            ensureCapacity(size + length);
2168            System.arraycopy(buffer, index, buffer, index + length, size - index);
2169            System.arraycopy(chars, offset, buffer, index, length);
2170            size += length;
2171        }
2172        return this;
2173    }
2174
2175    /**
2176     * Inserts the value into this builder.
2177     *
2178     * @param index  the index to add at, must be valid
2179     * @param value  the value to insert
2180     * @return this, to enable chaining
2181     * @throws IndexOutOfBoundsException if the index is invalid
2182     */
2183    public StrBuilder insert(final int index, final double value) {
2184        return insert(index, String.valueOf(value));
2185    }
2186
2187    /**
2188     * Inserts the value into this builder.
2189     *
2190     * @param index  the index to add at, must be valid
2191     * @param value  the value to insert
2192     * @return this, to enable chaining
2193     * @throws IndexOutOfBoundsException if the index is invalid
2194     */
2195    public StrBuilder insert(final int index, final float value) {
2196        return insert(index, String.valueOf(value));
2197    }
2198
2199    /**
2200     * Inserts the value into this builder.
2201     *
2202     * @param index  the index to add at, must be valid
2203     * @param value  the value to insert
2204     * @return this, to enable chaining
2205     * @throws IndexOutOfBoundsException if the index is invalid
2206     */
2207    public StrBuilder insert(final int index, final int value) {
2208        return insert(index, String.valueOf(value));
2209    }
2210
2211    /**
2212     * Inserts the value into this builder.
2213     *
2214     * @param index  the index to add at, must be valid
2215     * @param value  the value to insert
2216     * @return this, to enable chaining
2217     * @throws IndexOutOfBoundsException if the index is invalid
2218     */
2219    public StrBuilder insert(final int index, final long value) {
2220        return insert(index, String.valueOf(value));
2221    }
2222
2223    /**
2224     * Inserts the string representation of an object into this builder.
2225     * Inserting null will use the stored null text value.
2226     *
2227     * @param index  the index to add at, must be valid
2228     * @param obj  the object to insert
2229     * @return this, to enable chaining
2230     * @throws IndexOutOfBoundsException if the index is invalid
2231     */
2232    public StrBuilder insert(final int index, final Object obj) {
2233        if (obj == null) {
2234            return insert(index, nullText);
2235        }
2236        return insert(index, obj.toString());
2237    }
2238
2239    /**
2240     * Inserts the string into this builder.
2241     * Inserting null will use the stored null text value.
2242     *
2243     * @param index  the index to add at, must be valid
2244     * @param str  the string to insert
2245     * @return this, to enable chaining
2246     * @throws IndexOutOfBoundsException if the index is invalid
2247     */
2248    public StrBuilder insert(final int index, String str) {
2249        validateIndex(index);
2250        if (str == null) {
2251            str = nullText;
2252        }
2253        if (str != null) {
2254            final int strLen = str.length();
2255            if (strLen > 0) {
2256                final int newSize = size + strLen;
2257                ensureCapacity(newSize);
2258                System.arraycopy(buffer, index, buffer, index + strLen, size - index);
2259                size = newSize;
2260                str.getChars(0, strLen, buffer, index);
2261            }
2262        }
2263        return this;
2264    }
2265
2266    /**
2267     * Tests if the string builder is empty (convenience Collections API style method).
2268     * <p>
2269     * This method is the same as checking {@link #length()} and is provided to match the
2270     * API of Collections.
2271     * </p>
2272     *
2273     * @return {@code true} if the size is {@code 0}.
2274     */
2275    public boolean isEmpty() {
2276        return size == 0;
2277    }
2278
2279    /**
2280     * Tests if the string builder is not empty (convenience Collections API style method).
2281     * <p>
2282     * This method is the same as checking {@link #length()} and is provided to match the
2283     * API of Collections.
2284     * </p>
2285     *
2286     * @return {@code true} if the size is greater than {@code 0}.
2287     * @since 1.10.0
2288     */
2289    public boolean isNotEmpty() {
2290        return size > 0;
2291    }
2292
2293    /**
2294     * Searches the string builder to find the last reference to the specified char.
2295     *
2296     * @param ch  the character to find
2297     * @return The last index of the character, or -1 if not found
2298     */
2299    public int lastIndexOf(final char ch) {
2300        return lastIndexOf(ch, size - 1);
2301    }
2302
2303    /**
2304     * Searches the string builder to find the last reference to the specified char.
2305     *
2306     * @param ch  the character to find
2307     * @param startIndex  the index to start at, invalid index rounded to edge
2308     * @return The last index of the character, or -1 if not found
2309     */
2310    public int lastIndexOf(final char ch, int startIndex) {
2311        startIndex = startIndex >= size ? size - 1 : startIndex;
2312        if (startIndex < 0) {
2313            return -1;
2314        }
2315        for (int i = startIndex; i >= 0; i--) {
2316            if (buffer[i] == ch) {
2317                return i;
2318            }
2319        }
2320        return -1;
2321    }
2322
2323    /**
2324     * Searches the string builder to find the last reference to the specified string.
2325     * <p>
2326     * Note that a null input string will return -1, whereas the JDK throws an exception.
2327     * </p>
2328     *
2329     * @param str  the string to find, null returns -1
2330     * @return The last index of the string, or -1 if not found
2331     */
2332    public int lastIndexOf(final String str) {
2333        return lastIndexOf(str, size - 1);
2334    }
2335
2336    /**
2337     * Searches the string builder to find the last reference to the specified
2338     * string starting searching from the given index.
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     * @param startIndex  the index to start at, invalid index rounded to edge
2345     * @return The last index of the string, or -1 if not found
2346     */
2347    public int lastIndexOf(final String str, int startIndex) {
2348        startIndex = startIndex >= size ? size - 1 : startIndex;
2349        if (str == null || startIndex < 0) {
2350            return -1;
2351        }
2352        final int strLen = str.length();
2353        if (strLen > 0 && strLen <= size) {
2354            if (strLen == 1) {
2355                return lastIndexOf(str.charAt(0), startIndex);
2356            }
2357
2358            outer:
2359            for (int i = startIndex - strLen + 1; i >= 0; i--) {
2360                for (int j = 0; j < strLen; j++) {
2361                    if (str.charAt(j) != buffer[i + j]) {
2362                        continue outer;
2363                    }
2364                }
2365                return i;
2366            }
2367
2368        } else if (strLen == 0) {
2369            return startIndex;
2370        }
2371        return -1;
2372    }
2373
2374    /**
2375     * Searches the string builder using the matcher to find the last match.
2376     * <p>
2377     * Matchers can be used to perform advanced searching behavior.
2378     * For example you could write a matcher to find the character 'a'
2379     * followed by a number.
2380     * </p>
2381     *
2382     * @param matcher  the matcher to use, null returns -1
2383     * @return The last index matched, or -1 if not found
2384     */
2385    public int lastIndexOf(final StrMatcher matcher) {
2386        return lastIndexOf(matcher, size);
2387    }
2388
2389    /**
2390     * Searches the string builder using the matcher to find the last
2391     * match searching from the given index.
2392     * <p>
2393     * Matchers can be used to perform advanced searching behavior.
2394     * For example you could write a matcher to find the character 'a'
2395     * followed by a number.
2396     * </p>
2397     *
2398     * @param matcher  the matcher to use, null returns -1
2399     * @param startIndex  the index to start at, invalid index rounded to edge
2400     * @return The last index matched, or -1 if not found
2401     */
2402    public int lastIndexOf(final StrMatcher matcher, int startIndex) {
2403        startIndex = startIndex >= size ? size - 1 : startIndex;
2404        if (matcher == null || startIndex < 0) {
2405            return -1;
2406        }
2407        final char[] buf = buffer;
2408        final int endIndex = startIndex + 1;
2409        for (int i = startIndex; i >= 0; i--) {
2410            if (matcher.isMatch(buf, i, 0, endIndex) > 0) {
2411                return i;
2412            }
2413        }
2414        return -1;
2415    }
2416
2417    /**
2418     * Extracts the leftmost characters from the string builder without
2419     * throwing an exception.
2420     * <p>
2421     * This method extracts the left {@code length} characters from
2422     * the builder. If this many characters are not available, the whole
2423     * builder is returned. Thus the returned string may be shorter than the
2424     * length requested.
2425     * </p>
2426     *
2427     * @param length  the number of characters to extract, negative returns empty string
2428     * @return The new string
2429     */
2430    public String leftString(final int length) {
2431        if (length <= 0) {
2432            return StringUtils.EMPTY;
2433        }
2434        if (length >= size) {
2435            return new String(buffer, 0, size);
2436        }
2437        return new String(buffer, 0, length);
2438    }
2439
2440    /**
2441     * Gets the length of the string builder.
2442     *
2443     * @return The length
2444     */
2445    @Override
2446    public int length() {
2447        return size;
2448    }
2449
2450    /**
2451     * Extracts some characters from the middle of the string builder without
2452     * throwing an exception.
2453     * <p>
2454     * This method extracts {@code length} characters from the builder
2455     * at the specified index.
2456     * If the index is negative it is treated as zero.
2457     * If the index is greater than the builder size, it is treated as the builder size.
2458     * If the length is negative, the empty string is returned.
2459     * If insufficient characters are available in the builder, as much as possible is returned.
2460     * Thus the returned string may be shorter than the length requested.
2461     * </p>
2462     *
2463     * @param index  the index to start at, negative means zero
2464     * @param length  the number of characters to extract, negative returns empty string
2465     * @return The new string
2466     */
2467    public String midString(int index, final int length) {
2468        if (index < 0) {
2469            index = 0;
2470        }
2471        if (length <= 0 || index >= size) {
2472            return StringUtils.EMPTY;
2473        }
2474        if (size <= index + length) {
2475            return new String(buffer, index, size - index);
2476        }
2477        return new String(buffer, index, length);
2478    }
2479
2480    /**
2481     * Minimizes the capacity to the actual length of the string.
2482     *
2483     * @return this, to enable chaining
2484     */
2485    public StrBuilder minimizeCapacity() {
2486        if (buffer.length > length()) {
2487            final char[] old = buffer;
2488            buffer = new char[length()];
2489            System.arraycopy(old, 0, buffer, 0, size);
2490        }
2491        return this;
2492    }
2493
2494    /**
2495     * If possible, reads chars from the provided {@link Readable} directly into underlying
2496     * character buffer without making extra copies.
2497     *
2498     * @param readable  object to read from
2499     * @return The number of characters read
2500     * @throws IOException if an I/O error occurs.
2501     *
2502     * @see #appendTo(Appendable)
2503     */
2504    public int readFrom(final Readable readable) throws IOException {
2505        final int oldSize = size;
2506        if (readable instanceof Reader) {
2507            final Reader r = (Reader) readable;
2508            ensureCapacity(size + 1);
2509            int read;
2510            while ((read = r.read(buffer, size, buffer.length - size)) != -1) {
2511                size += read;
2512                ensureCapacity(size + 1);
2513            }
2514        } else if (readable instanceof CharBuffer) {
2515            final CharBuffer cb = (CharBuffer) readable;
2516            final int remaining = cb.remaining();
2517            ensureCapacity(size + remaining);
2518            cb.get(buffer, size, remaining);
2519            size += remaining;
2520        } else {
2521            while (true) {
2522                ensureCapacity(size + 1);
2523                final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size);
2524                final int read = readable.read(buf);
2525                if (read == -1) {
2526                    break;
2527                }
2528                size += read;
2529            }
2530        }
2531        return size - oldSize;
2532    }
2533
2534    /**
2535     * Replaces a portion of the string builder with another string.
2536     * The length of the inserted string does not have to match the removed length.
2537     *
2538     * @param startIndex  the start index, inclusive, must be valid
2539     * @param endIndex  the end index, exclusive, must be valid except
2540     *  that if too large it is treated as end of string
2541     * @param replaceStr  the string to replace with, null means delete range
2542     * @return this, to enable chaining
2543     * @throws IndexOutOfBoundsException if the index is invalid
2544     */
2545    public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) {
2546        endIndex = validateRange(startIndex, endIndex);
2547        final int insertLen = replaceStr == null ? 0 : replaceStr.length();
2548        replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen);
2549        return this;
2550    }
2551
2552    /**
2553     * Advanced search and replaces within the builder using a matcher.
2554     * <p>
2555     * Matchers can be used to perform advanced behavior.
2556     * For example you could write a matcher to delete all occurrences
2557     * where the character 'a' is followed by a number.
2558     * </p>
2559     *
2560     * @param matcher  the matcher to use to find the deletion, null causes no action
2561     * @param replaceStr  the string to replace the match with, null is a delete
2562     * @param startIndex  the start index, inclusive, must be valid
2563     * @param endIndex  the end index, exclusive, must be valid except
2564     *  that if too large it is treated as end of string
2565     * @param replaceCount  the number of times to replace, -1 for replace all
2566     * @return this, to enable chaining
2567     * @throws IndexOutOfBoundsException if start index is invalid
2568     */
2569    public StrBuilder replace(
2570            final StrMatcher matcher, final String replaceStr,
2571            final int startIndex, int endIndex, final int replaceCount) {
2572        endIndex = validateRange(startIndex, endIndex);
2573        return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount);
2574    }
2575
2576    /**
2577     * Replaces the search character with the replace character
2578     * throughout the builder.
2579     *
2580     * @param search  the search character
2581     * @param replace  the replace character
2582     * @return this, to enable chaining
2583     */
2584    public StrBuilder replaceAll(final char search, final char replace) {
2585        if (search != replace) {
2586            for (int i = 0; i < size; i++) {
2587                if (buffer[i] == search) {
2588                    buffer[i] = replace;
2589                }
2590            }
2591        }
2592        return this;
2593    }
2594
2595    /**
2596     * Replaces the search string with the replace string throughout the builder.
2597     *
2598     * @param searchStr  the search string, null causes no action to occur
2599     * @param replaceStr  the replace string, null is equivalent to an empty string
2600     * @return this, to enable chaining
2601     */
2602    public StrBuilder replaceAll(final String searchStr, final String replaceStr) {
2603        final int searchLen = searchStr == null ? 0 : searchStr.length();
2604        if (searchLen > 0) {
2605            final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2606            int index = indexOf(searchStr, 0);
2607            while (index >= 0) {
2608                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2609                index = indexOf(searchStr, index + replaceLen);
2610            }
2611        }
2612        return this;
2613    }
2614
2615    /**
2616     * Replaces all matches within the builder with the replace string.
2617     * <p>
2618     * Matchers can be used to perform advanced replace behavior.
2619     * For example you could write a matcher to replace all occurrences
2620     * where the character 'a' is followed by a number.
2621     * </p>
2622     *
2623     * @param matcher  the matcher to use to find the deletion, null causes no action
2624     * @param replaceStr  the replace string, null is equivalent to an empty string
2625     * @return this, to enable chaining
2626     */
2627    public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) {
2628        return replace(matcher, replaceStr, 0, size, -1);
2629    }
2630
2631    /**
2632     * Replaces the first instance of the search character with the
2633     * replace character in the builder.
2634     *
2635     * @param search  the search character
2636     * @param replace  the replace character
2637     * @return this, to enable chaining
2638     */
2639    public StrBuilder replaceFirst(final char search, final char replace) {
2640        if (search != replace) {
2641            for (int i = 0; i < size; i++) {
2642                if (buffer[i] == search) {
2643                    buffer[i] = replace;
2644                    break;
2645                }
2646            }
2647        }
2648        return this;
2649    }
2650
2651    /**
2652     * Replaces the first instance of the search string with the replace string.
2653     *
2654     * @param searchStr  the search string, null causes no action to occur
2655     * @param replaceStr  the replace string, null is equivalent to an empty string
2656     * @return this, to enable chaining
2657     */
2658    public StrBuilder replaceFirst(final String searchStr, final String replaceStr) {
2659        final int searchLen = searchStr == null ? 0 : searchStr.length();
2660        if (searchLen > 0) {
2661            final int index = indexOf(searchStr, 0);
2662            if (index >= 0) {
2663                final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2664                replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen);
2665            }
2666        }
2667        return this;
2668    }
2669
2670    /**
2671     * Replaces the first match within the builder with the replace string.
2672     * <p>
2673     * Matchers can be used to perform advanced replace behavior.
2674     * For example you could write a matcher to replace
2675     * where the character 'a' is followed by a number.
2676     * </p>
2677     *
2678     * @param matcher  the matcher to use to find the deletion, null causes no action
2679     * @param replaceStr  the replace string, null is equivalent to an empty string
2680     * @return this, to enable chaining
2681     */
2682    public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) {
2683        return replace(matcher, replaceStr, 0, size, 1);
2684    }
2685
2686    /**
2687     * Internal method to delete a range without validation.
2688     *
2689     * @param startIndex  the start index, must be valid
2690     * @param endIndex  the end index (exclusive), must be valid
2691     * @param removeLen  the length to remove (endIndex - startIndex), must be valid
2692     * @param insertStr  the string to replace with, null means delete range
2693     * @param insertLen  the length of the insert string, must be valid
2694     * @throws IndexOutOfBoundsException if any index is invalid
2695     */
2696    private void replaceImpl(final int startIndex,
2697                             final int endIndex,
2698                             final int removeLen,
2699                             final String insertStr,
2700                             final int insertLen) {
2701        final int newSize = size - removeLen + insertLen;
2702        if (insertLen != removeLen) {
2703            ensureCapacity(newSize);
2704            System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex);
2705            size = newSize;
2706        }
2707        if (insertLen > 0) {
2708            insertStr.getChars(0, insertLen, buffer, startIndex);
2709        }
2710    }
2711
2712    /**
2713     * Replaces within the builder using a matcher.
2714     * <p>
2715     * Matchers can be used to perform advanced behavior.
2716     * For example you could write a matcher to delete all occurrences
2717     * where the character 'a' is followed by a number.
2718     * </p>
2719     *
2720     * @param matcher  the matcher to use to find the deletion, null causes no action
2721     * @param replaceStr  the string to replace the match with, null is a delete
2722     * @param from  the start index, must be valid
2723     * @param to  the end index (exclusive), must be valid
2724     * @param replaceCount  the number of times to replace, -1 for replace all
2725     * @return this, to enable chaining
2726     * @throws IndexOutOfBoundsException if any index is invalid
2727     */
2728    private StrBuilder replaceImpl(
2729            final StrMatcher matcher, final String replaceStr,
2730            final int from, int to, int replaceCount) {
2731        if (matcher == null || size == 0) {
2732            return this;
2733        }
2734        final int replaceLen = replaceStr == null ? 0 : replaceStr.length();
2735        for (int i = from; i < to && replaceCount != 0; i++) {
2736            final char[] buf = buffer;
2737            final int removeLen = matcher.isMatch(buf, i, from, to);
2738            if (removeLen > 0) {
2739                replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen);
2740                to = to - removeLen + replaceLen;
2741                i = i + replaceLen - 1;
2742                if (replaceCount > 0) {
2743                    replaceCount--;
2744                }
2745            }
2746        }
2747        return this;
2748    }
2749
2750    /**
2751     * Reverses the string builder placing each character in the opposite index.
2752     *
2753     * @return this, to enable chaining
2754     */
2755    public StrBuilder reverse() {
2756        if (size == 0) {
2757            return this;
2758        }
2759
2760        final int half = size / 2;
2761        final char[] buf = buffer;
2762        for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) {
2763            final char swap = buf[leftIdx];
2764            buf[leftIdx] = buf[rightIdx];
2765            buf[rightIdx] = swap;
2766        }
2767        return this;
2768    }
2769
2770    /**
2771     * Extracts the rightmost characters from the string builder without
2772     * throwing an exception.
2773     * <p>
2774     * This method extracts the right {@code length} characters from
2775     * the builder. If this many characters are not available, the whole
2776     * builder is returned. Thus the returned string may be shorter than the
2777     * length requested.
2778     * </p>
2779     *
2780     * @param length  the number of characters to extract, negative returns empty string
2781     * @return The new string
2782     */
2783    public String rightString(final int length) {
2784        if (length <= 0) {
2785            return StringUtils.EMPTY;
2786        }
2787        if (length >= size) {
2788            return new String(buffer, 0, size);
2789        }
2790        return new String(buffer, size - length, length);
2791    }
2792
2793    /**
2794     * Sets the character at the specified index.
2795     *
2796     * @see #charAt(int)
2797     * @see #deleteCharAt(int)
2798     * @param index  the index to set
2799     * @param ch  the new character
2800     * @return this, to enable chaining
2801     * @throws IndexOutOfBoundsException if the index is invalid
2802     */
2803    public StrBuilder setCharAt(final int index, final char ch) {
2804        if (index < 0 || index >= length()) {
2805            throw new StringIndexOutOfBoundsException(index);
2806        }
2807        buffer[index] = ch;
2808        return this;
2809    }
2810
2811    /**
2812     * Updates the length of the builder by either dropping the last characters
2813     * or adding filler of Unicode zero.
2814     *
2815     * @param length  the length to set to, must be zero or positive
2816     * @return this, to enable chaining
2817     * @throws IndexOutOfBoundsException if the length is negative
2818     */
2819    public StrBuilder setLength(final int length) {
2820        if (length < 0) {
2821            throw new StringIndexOutOfBoundsException(length);
2822        }
2823        if (length < size) {
2824            size = length;
2825        } else if (length > size) {
2826            ensureCapacity(length);
2827            final int oldEnd = size;
2828            size = length;
2829            for (int i = oldEnd; i < length; i++) {
2830                buffer[i] = '\0';
2831            }
2832        }
2833        return this;
2834    }
2835
2836    /**
2837     * Sets the text to be appended when a new line is added.
2838     *
2839     * @param newLine  the new line text, null means use system default
2840     * @return this, to enable chaining
2841     */
2842    public StrBuilder setNewLineText(final String newLine) {
2843        this.newLine = newLine;
2844        return this;
2845    }
2846
2847    /**
2848     * Sets the text to be appended when null is added.
2849     *
2850     * @param nullText  the null text, null means no append
2851     * @return this, to enable chaining
2852     */
2853    public StrBuilder setNullText(String nullText) {
2854        if (nullText != null && nullText.isEmpty()) {
2855            nullText = null;
2856        }
2857        this.nullText = nullText;
2858        return this;
2859    }
2860
2861    /**
2862     * Gets the length of the string builder.
2863     * <p>
2864     * This method is the same as {@link #length()} and is provided to match the
2865     * API of Collections.
2866     * </p>
2867     *
2868     * @return The length
2869     */
2870    public int size() {
2871        return size;
2872    }
2873
2874    /**
2875     * Checks whether this builder starts with the specified string.
2876     * <p>
2877     * Note that this method handles null input quietly, unlike String.
2878     * </p>
2879     *
2880     * @param str  the string to search for, null returns false
2881     * @return true if the builder starts with the string
2882     */
2883    public boolean startsWith(final String str) {
2884        if (str == null) {
2885            return false;
2886        }
2887        final int len = str.length();
2888        if (len == 0) {
2889            return true;
2890        }
2891        if (len > size) {
2892            return false;
2893        }
2894        for (int i = 0; i < len; i++) {
2895            if (buffer[i] != str.charAt(i)) {
2896                return false;
2897            }
2898        }
2899        return true;
2900    }
2901
2902    /**
2903     * {@inheritDoc}
2904     */
2905    @Override
2906    public CharSequence subSequence(final int startIndex, final int endIndex) {
2907      if (startIndex < 0) {
2908          throw new StringIndexOutOfBoundsException(startIndex);
2909      }
2910      if (endIndex > size) {
2911          throw new StringIndexOutOfBoundsException(endIndex);
2912      }
2913      if (startIndex > endIndex) {
2914          throw new StringIndexOutOfBoundsException(endIndex - startIndex);
2915      }
2916      return substring(startIndex, endIndex);
2917    }
2918
2919    /**
2920     * Extracts a portion of this string builder as a string.
2921     *
2922     * @param start  the start index, inclusive, must be valid
2923     * @return The new string
2924     * @throws IndexOutOfBoundsException if the index is invalid
2925     */
2926    public String substring(final int start) {
2927        return substring(start, size);
2928    }
2929
2930    /**
2931     * Extracts a portion of this string builder as a string.
2932     * <p>
2933     * Note: This method treats an endIndex greater than the length of the
2934     * builder as equal to the length of the builder, and continues
2935     * without error, unlike StringBuffer or String.
2936     *
2937     * @param startIndex  the start index, inclusive, must be valid
2938     * @param endIndex  the end index, exclusive, must be valid except
2939     *  that if too large it is treated as end of string
2940     * @return The new string
2941     * @throws IndexOutOfBoundsException if the index is invalid
2942     */
2943    public String substring(final int startIndex, int endIndex) {
2944        endIndex = validateRange(startIndex, endIndex);
2945        return new String(buffer, startIndex, endIndex - startIndex);
2946    }
2947
2948    /**
2949     * Copies the builder's character array into a new character array.
2950     *
2951     * @return a new array that represents the contents of the builder
2952     */
2953    public char[] toCharArray() {
2954        return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size);
2955    }
2956
2957    /**
2958     * Copies part of the builder's character array into a new character array.
2959     *
2960     * @param startIndex  the start index, inclusive, must be valid
2961     * @param endIndex  the end index, exclusive, must be valid except that
2962     *  if too large it is treated as end of string
2963     * @return a new array that holds part of the contents of the builder
2964     * @throws IndexOutOfBoundsException if startIndex is invalid,
2965     *  or if endIndex is invalid (but endIndex greater than size is valid)
2966     */
2967    public char[] toCharArray(final int startIndex, int endIndex) {
2968        endIndex = validateRange(startIndex, endIndex);
2969        final int len = endIndex - startIndex;
2970        if (len == 0) {
2971            return ArrayUtils.EMPTY_CHAR_ARRAY;
2972        }
2973        final char[] chars = new char[len];
2974        System.arraycopy(buffer, startIndex, chars, 0, len);
2975        return chars;
2976    }
2977
2978    /**
2979     * Gets a String version of the string builder, creating a new instance
2980     * each time the method is called.
2981     * <p>
2982     * Note that unlike StringBuffer, the string version returned is
2983     * independent of the string builder.
2984     * </p>
2985     *
2986     * @return The builder as a String
2987     */
2988    @Override
2989    public String toString() {
2990        return new String(buffer, 0, size);
2991    }
2992
2993    /**
2994     * Gets a StringBuffer version of the string builder, creating a
2995     * new instance each time the method is called.
2996     *
2997     * @return The builder as a StringBuffer
2998     */
2999    public StringBuffer toStringBuffer() {
3000        return new StringBuffer(size).append(buffer, 0, size);
3001    }
3002
3003    /**
3004     * Gets a StringBuilder version of the string builder, creating a
3005     * new instance each time the method is called.
3006     *
3007     * @return The builder as a StringBuilder
3008     */
3009    public StringBuilder toStringBuilder() {
3010        return new StringBuilder(size).append(buffer, 0, size);
3011    }
3012
3013    /**
3014     * Trims the builder by removing characters less than or equal to a space
3015     * from the beginning and end.
3016     *
3017     * @return this, to enable chaining
3018     */
3019    public StrBuilder trim() {
3020        if (size == 0) {
3021            return this;
3022        }
3023        int len = size;
3024        final char[] buf = buffer;
3025        int pos = 0;
3026        while (pos < len && buf[pos] <= ' ') {
3027            pos++;
3028        }
3029        while (pos < len && buf[len - 1] <= ' ') {
3030            len--;
3031        }
3032        if (len < size) {
3033            delete(len, size);
3034        }
3035        if (pos > 0) {
3036            delete(0, pos);
3037        }
3038        return this;
3039    }
3040
3041    /**
3042     * Validates parameters defining a single index in the builder.
3043     *
3044     * @param index  the index, must be valid
3045     * @throws IndexOutOfBoundsException if the index is invalid
3046     */
3047    protected void validateIndex(final int index) {
3048        if (index < 0 || index > size) {
3049            throw new StringIndexOutOfBoundsException(index);
3050        }
3051    }
3052
3053    /**
3054     * Validates parameters defining a range of the builder.
3055     *
3056     * @param startIndex  the start index, inclusive, must be valid
3057     * @param endIndex  the end index, exclusive, must be valid except
3058     *  that if too large it is treated as end of string
3059     * @return The new string
3060     * @throws IndexOutOfBoundsException if the index is invalid
3061     */
3062    protected int validateRange(final int startIndex, int endIndex) {
3063        if (startIndex < 0) {
3064            throw new StringIndexOutOfBoundsException(startIndex);
3065        }
3066        if (endIndex > size) {
3067            endIndex = size;
3068        }
3069        if (startIndex > endIndex) {
3070            throw new StringIndexOutOfBoundsException("end < start");
3071        }
3072        return endIndex;
3073    }
3074
3075}