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