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