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