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