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