1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.text; 18 19 import java.io.IOException; 20 import java.io.Reader; 21 import java.io.Serializable; 22 import java.io.Writer; 23 import java.nio.CharBuffer; 24 import java.util.Arrays; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Objects; 28 29 import org.apache.commons.lang3.ArrayUtils; 30 import org.apache.commons.lang3.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 final int toIndex = size + padLen; 911 Arrays.fill(buffer, size, toIndex, padChar); 912 str.getChars(0, strLen, buffer, toIndex); 913 } 914 size += width; 915 } 916 return this; 917 } 918 919 /** 920 * Appends an object to the builder padding on the right to a fixed length. The {@code String.valueOf} of the 921 * {@code int} value is used. If the object is larger than the length, the right hand side is lost. 922 * 923 * @param value the value to append 924 * @param width the fixed field width, zero or negative has no effect 925 * @param padChar the pad character to use 926 * @return this, to enable chaining 927 */ 928 public TextStringBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) { 929 return appendFixedWidthPadRight(String.valueOf(value), width, padChar); 930 } 931 932 /** 933 * Appends an object to the builder padding on the right to a fixed length. The {@code toString} of the object is 934 * used. If the object is larger than the length, the right hand side is lost. If the object is null, null text 935 * value is used. 936 * 937 * @param obj the object to append, null uses null text 938 * @param width the fixed field width, zero or negative has no effect 939 * @param padChar the pad character to use 940 * @return this, to enable chaining 941 */ 942 public TextStringBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) { 943 if (width > 0) { 944 ensureCapacityInternal(size + width); 945 String str = Objects.toString(obj, getNullText()); 946 if (str == null) { 947 str = StringUtils.EMPTY; 948 } 949 final int strLen = str.length(); 950 if (strLen >= width) { 951 str.getChars(0, width, buffer, size); 952 } else { 953 str.getChars(0, strLen, buffer, size); 954 final int fromIndex = size + strLen; 955 Arrays.fill(buffer, fromIndex, fromIndex + width - strLen, padChar); 956 } 957 size += width; 958 } 959 return this; 960 } 961 962 /** 963 * Appends a boolean value followed by a new line to the string builder. 964 * 965 * @param value the value to append 966 * @return this, to enable chaining 967 */ 968 public TextStringBuilder appendln(final boolean value) { 969 return append(value).appendNewLine(); 970 } 971 972 /** 973 * Appends a char value followed by a new line to the string builder. 974 * 975 * @param ch the value to append 976 * @return this, to enable chaining 977 */ 978 public TextStringBuilder appendln(final char ch) { 979 return append(ch).appendNewLine(); 980 } 981 982 /** 983 * Appends a char array followed by a new line to the string builder. Appending null will call 984 * {@link #appendNull()}. 985 * 986 * @param chars the char array to append 987 * @return this, to enable chaining 988 */ 989 public TextStringBuilder appendln(final char[] chars) { 990 return append(chars).appendNewLine(); 991 } 992 993 /** 994 * Appends a char array followed by a new line to the string builder. Appending null will call 995 * {@link #appendNull()}. 996 * 997 * @param chars the char array to append 998 * @param startIndex the start index, inclusive, must be valid 999 * @param length the length to append, must be valid 1000 * @return this, to enable chaining 1001 */ 1002 public TextStringBuilder appendln(final char[] chars, final int startIndex, final int length) { 1003 return append(chars, startIndex, length).appendNewLine(); 1004 } 1005 1006 /** 1007 * Appends a double value followed by a new line to the string builder using {@code String.valueOf}. 1008 * 1009 * @param value the value to append 1010 * @return this, to enable chaining 1011 */ 1012 public TextStringBuilder appendln(final double value) { 1013 return append(value).appendNewLine(); 1014 } 1015 1016 /** 1017 * Appends a float value followed by a new line to the string builder using {@code String.valueOf}. 1018 * 1019 * @param value the value to append 1020 * @return this, to enable chaining 1021 */ 1022 public TextStringBuilder appendln(final float value) { 1023 return append(value).appendNewLine(); 1024 } 1025 1026 /** 1027 * Appends an int value followed by a new line to the string builder using {@code String.valueOf}. 1028 * 1029 * @param value the value to append 1030 * @return this, to enable chaining 1031 */ 1032 public TextStringBuilder appendln(final int value) { 1033 return append(value).appendNewLine(); 1034 } 1035 1036 /** 1037 * Appends a long value followed by a new line to the string builder using {@code String.valueOf}. 1038 * 1039 * @param value the value to append 1040 * @return this, to enable chaining 1041 */ 1042 public TextStringBuilder appendln(final long value) { 1043 return append(value).appendNewLine(); 1044 } 1045 1046 /** 1047 * Appends an object followed by a new line to this string builder. Appending null will call {@link #appendNull()}. 1048 * 1049 * @param obj the object to append 1050 * @return this, to enable chaining 1051 */ 1052 public TextStringBuilder appendln(final Object obj) { 1053 return append(obj).appendNewLine(); 1054 } 1055 1056 /** 1057 * Appends a string followed by a new line to this string builder. Appending null will call {@link #appendNull()}. 1058 * 1059 * @param str the string to append 1060 * @return this, to enable chaining 1061 */ 1062 public TextStringBuilder appendln(final String str) { 1063 return append(str).appendNewLine(); 1064 } 1065 1066 /** 1067 * Appends part of a string followed by a new line to this string builder. Appending null will call 1068 * {@link #appendNull()}. 1069 * 1070 * @param str the string to append 1071 * @param startIndex the start index, inclusive, must be valid 1072 * @param length the length to append, must be valid 1073 * @return this, to enable chaining 1074 */ 1075 public TextStringBuilder appendln(final String str, final int startIndex, final int length) { 1076 return append(str, startIndex, length).appendNewLine(); 1077 } 1078 1079 /** 1080 * Calls {@link String#format(String, Object...)} and appends the result. 1081 * 1082 * @param format the format string 1083 * @param objs the objects to use in the format string 1084 * @return {@code this} to enable chaining 1085 * @see String#format(String, Object...) 1086 */ 1087 public TextStringBuilder appendln(final String format, final Object... objs) { 1088 return append(format, objs).appendNewLine(); 1089 } 1090 1091 /** 1092 * Appends a string buffer followed by a new line to this string builder. Appending null will call 1093 * {@link #appendNull()}. 1094 * 1095 * @param str the string buffer to append 1096 * @return this, to enable chaining 1097 */ 1098 public TextStringBuilder appendln(final StringBuffer str) { 1099 return append(str).appendNewLine(); 1100 } 1101 1102 /** 1103 * Appends part of a string buffer followed by a new line to this string builder. Appending null will call 1104 * {@link #appendNull()}. 1105 * 1106 * @param str the string to append 1107 * @param startIndex the start index, inclusive, must be valid 1108 * @param length the length to append, must be valid 1109 * @return this, to enable chaining 1110 */ 1111 public TextStringBuilder appendln(final StringBuffer str, final int startIndex, final int length) { 1112 return append(str, startIndex, length).appendNewLine(); 1113 } 1114 1115 /** 1116 * Appends a string builder followed by a new line to this string builder. Appending null will call 1117 * {@link #appendNull()}. 1118 * 1119 * @param str the string builder to append 1120 * @return this, to enable chaining 1121 */ 1122 public TextStringBuilder appendln(final StringBuilder str) { 1123 return append(str).appendNewLine(); 1124 } 1125 1126 /** 1127 * Appends part of a string builder followed by a new line to this string builder. Appending null will call 1128 * {@link #appendNull()}. 1129 * 1130 * @param str the string builder to append 1131 * @param startIndex the start index, inclusive, must be valid 1132 * @param length the length to append, must be valid 1133 * @return this, to enable chaining 1134 */ 1135 public TextStringBuilder appendln(final StringBuilder str, final int startIndex, final int length) { 1136 return append(str, startIndex, length).appendNewLine(); 1137 } 1138 1139 /** 1140 * Appends another string builder followed by a new line to this string builder. Appending null will call 1141 * {@link #appendNull()}. 1142 * 1143 * @param str the string builder to append 1144 * @return this, to enable chaining 1145 */ 1146 public TextStringBuilder appendln(final TextStringBuilder str) { 1147 return append(str).appendNewLine(); 1148 } 1149 1150 /** 1151 * Appends part of a string builder followed by a new line to this string builder. Appending null will call 1152 * {@link #appendNull()}. 1153 * 1154 * @param str the string to append 1155 * @param startIndex the start index, inclusive, must be valid 1156 * @param length the length to append, must be valid 1157 * @return this, to enable chaining 1158 */ 1159 public TextStringBuilder appendln(final TextStringBuilder str, final int startIndex, final int length) { 1160 return append(str, startIndex, length).appendNewLine(); 1161 } 1162 1163 /** 1164 * Appends this builder's new line string to this builder. 1165 * <p> 1166 * By default, the new line is the system default from {@link System#lineSeparator()}. 1167 * </p> 1168 * <p> 1169 * 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 1170 * endings even when on Windows. 1171 * </p> 1172 * 1173 * @return this 1174 * @see #getNewLineText() 1175 * @see #setNewLineText(String) 1176 */ 1177 public TextStringBuilder appendNewLine() { 1178 if (newLine == null) { 1179 append(System.lineSeparator()); 1180 return this; 1181 } 1182 return append(newLine); 1183 } 1184 1185 /** 1186 * Appends the text representing {@code null} to this string builder. 1187 * 1188 * @return this, to enable chaining 1189 */ 1190 public TextStringBuilder appendNull() { 1191 if (nullText == null) { 1192 return this; 1193 } 1194 return append(nullText); 1195 } 1196 1197 /** 1198 * Appends the pad character to the builder the specified number of times. 1199 * 1200 * @param length the length to append, negative means no append 1201 * @param padChar the character to append 1202 * @return this, to enable chaining 1203 */ 1204 public TextStringBuilder appendPadding(final int length, final char padChar) { 1205 if (length >= 0) { 1206 ensureCapacityInternal(size + length); 1207 for (int i = 0; i < length; i++) { 1208 buffer[size++] = padChar; 1209 } 1210 } 1211 return this; 1212 } 1213 1214 /** 1215 * Appends a separator if the builder is currently non-empty. The separator is appended using {@link #append(char)}. 1216 * <p> 1217 * This method is useful for adding a separator each time around the loop except the first. 1218 * </p> 1219 * 1220 * <pre> 1221 * for (Iterator it = list.iterator(); it.hasNext();) { 1222 * appendSeparator(','); 1223 * append(it.next()); 1224 * } 1225 * </pre> 1226 * 1227 * <p> 1228 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1229 * </p> 1230 * 1231 * @param separator the separator to use 1232 * @return this, to enable chaining 1233 */ 1234 public TextStringBuilder appendSeparator(final char separator) { 1235 if (isNotEmpty()) { 1236 append(separator); 1237 } 1238 return this; 1239 } 1240 1241 /** 1242 * Appends one of both separators to the builder If the builder is currently empty it will append the 1243 * defaultIfEmpty-separator Otherwise it will append the standard-separator 1244 * 1245 * The separator is appended using {@link #append(char)}. 1246 * 1247 * @param standard the separator if builder is not empty 1248 * @param defaultIfEmpty the separator if builder is empty 1249 * @return this, to enable chaining 1250 */ 1251 public TextStringBuilder appendSeparator(final char standard, final char defaultIfEmpty) { 1252 if (isEmpty()) { 1253 append(defaultIfEmpty); 1254 } else { 1255 append(standard); 1256 } 1257 return this; 1258 } 1259 1260 /** 1261 * Appends a separator to the builder if the loop index is greater than zero. The separator is appended using 1262 * {@link #append(char)}. 1263 * <p> 1264 * This method is useful for adding a separator each time around the loop except the first. 1265 * </p> 1266 * 1267 * <pre> 1268 * for (int i = 0; i < list.size(); i++) { 1269 * appendSeparator(",", i); 1270 * append(list.get(i)); 1271 * } 1272 * </pre> 1273 * 1274 * <p> 1275 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1276 * </p> 1277 * 1278 * @param separator the separator to use 1279 * @param loopIndex the loop index 1280 * @return this, to enable chaining 1281 */ 1282 public TextStringBuilder appendSeparator(final char separator, final int loopIndex) { 1283 if (loopIndex > 0) { 1284 append(separator); 1285 } 1286 return this; 1287 } 1288 1289 /** 1290 * Appends a separator if the builder is currently non-empty. Appending a null separator will have no effect. The 1291 * separator is appended using {@link #append(String)}. 1292 * <p> 1293 * This method is useful for adding a separator each time around the loop except the first. 1294 * </p> 1295 * 1296 * <pre> 1297 * for (Iterator it = list.iterator(); it.hasNext();) { 1298 * appendSeparator(","); 1299 * append(it.next()); 1300 * } 1301 * </pre> 1302 * 1303 * <p> 1304 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1305 * </p> 1306 * 1307 * @param separator the separator to use, null means no separator 1308 * @return this, to enable chaining 1309 */ 1310 public TextStringBuilder appendSeparator(final String separator) { 1311 return appendSeparator(separator, null); 1312 } 1313 1314 /** 1315 * Appends a separator to the builder if the loop index is greater than zero. Appending a null separator will have 1316 * no effect. The separator is appended using {@link #append(String)}. 1317 * <p> 1318 * This method is useful for adding a separator each time around the loop except the first. 1319 * </p> 1320 * 1321 * <pre> 1322 * for (int i = 0; i < list.size(); i++) { 1323 * appendSeparator(",", i); 1324 * append(list.get(i)); 1325 * } 1326 * </pre> 1327 * 1328 * <p> 1329 * Note that for this simple example, you should use {@link #appendWithSeparators(Iterable, String)}. 1330 * </p> 1331 * 1332 * @param separator the separator to use, null means no separator 1333 * @param loopIndex the loop index 1334 * @return this, to enable chaining 1335 */ 1336 public TextStringBuilder appendSeparator(final String separator, final int loopIndex) { 1337 if (separator != null && loopIndex > 0) { 1338 append(separator); 1339 } 1340 return this; 1341 } 1342 1343 /** 1344 * Appends one of both separators to the StrBuilder. If the builder is currently empty, it will append the 1345 * defaultIfEmpty-separator, otherwise it will append the standard-separator. 1346 * <p> 1347 * Appending a null separator will have no effect. The separator is appended using {@link #append(String)}. 1348 * </p> 1349 * <p> 1350 * This method is for example useful for constructing queries 1351 * </p> 1352 * 1353 * <pre> 1354 * StrBuilder whereClause = new StrBuilder(); 1355 * if (searchCommand.getPriority() != null) { 1356 * whereClause.appendSeparator(" and", " where"); 1357 * whereClause.append(" priority = ?") 1358 * } 1359 * if (searchCommand.getComponent() != null) { 1360 * whereClause.appendSeparator(" and", " where"); 1361 * whereClause.append(" component = ?") 1362 * } 1363 * selectClause.append(whereClause) 1364 * </pre> 1365 * 1366 * @param standard the separator if builder is not empty, null means no separator 1367 * @param defaultIfEmpty the separator if builder is empty, null means no separator 1368 * @return this, to enable chaining 1369 */ 1370 public TextStringBuilder appendSeparator(final String standard, final String defaultIfEmpty) { 1371 final String str = isEmpty() ? defaultIfEmpty : standard; 1372 if (str != null) { 1373 append(str); 1374 } 1375 return this; 1376 } 1377 1378 /** 1379 * Appends current contents of this {@code StrBuilder} to the provided {@link Appendable}. 1380 * <p> 1381 * This method tries to avoid doing any extra copies of contents. 1382 * </p> 1383 * 1384 * @param appendable the appendable to append data to 1385 * @throws IOException if an I/O error occurs. 1386 * @see #readFrom(Readable) 1387 */ 1388 public void appendTo(final Appendable appendable) throws IOException { 1389 if (appendable instanceof Writer) { 1390 ((Writer) appendable).write(buffer, 0, size); 1391 } else if (appendable instanceof StringBuilder) { 1392 ((StringBuilder) appendable).append(buffer, 0, size); 1393 } else if (appendable instanceof StringBuffer) { 1394 ((StringBuffer) appendable).append(buffer, 0, size); 1395 } else if (appendable instanceof CharBuffer) { 1396 ((CharBuffer) appendable).put(buffer, 0, size); 1397 } else { 1398 appendable.append(this); 1399 } 1400 } 1401 1402 /** Appends {@code "true"}. */ 1403 private void appendTrue(int index) { 1404 buffer[index++] = 't'; 1405 buffer[index++] = 'r'; 1406 buffer[index++] = 'u'; 1407 buffer[index] = 'e'; 1408 size += TRUE_STRING_SIZE; 1409 } 1410 1411 /** 1412 * Appends an iterable placing separators between each value, but not before the first or after the last. Appending 1413 * a null iterable will have no effect. Each object is appended using {@link #append(Object)}. 1414 * 1415 * @param iterable the iterable to append 1416 * @param separator the separator to use, null means no separator 1417 * @return this, to enable chaining 1418 */ 1419 public TextStringBuilder appendWithSeparators(final Iterable<?> iterable, final String separator) { 1420 if (iterable != null) { 1421 appendWithSeparators(iterable.iterator(), separator); 1422 } 1423 return this; 1424 } 1425 1426 /** 1427 * Appends an iterator placing separators between each value, but not before the first or after the last. Appending 1428 * a null iterator will have no effect. Each object is appended using {@link #append(Object)}. 1429 * 1430 * @param it the iterator to append 1431 * @param separator the separator to use, null means no separator 1432 * @return this, to enable chaining 1433 */ 1434 public TextStringBuilder appendWithSeparators(final Iterator<?> it, final String separator) { 1435 if (it != null) { 1436 final String sep = Objects.toString(separator, StringUtils.EMPTY); 1437 while (it.hasNext()) { 1438 append(it.next()); 1439 if (it.hasNext()) { 1440 append(sep); 1441 } 1442 } 1443 } 1444 return this; 1445 } 1446 1447 /** 1448 * Appends an array placing separators between each value, but not before the first or after the last. Appending a 1449 * null array will have no effect. Each object is appended using {@link #append(Object)}. 1450 * 1451 * @param array the array to append 1452 * @param separator the separator to use, null means no separator 1453 * @return this, to enable chaining 1454 */ 1455 public TextStringBuilder appendWithSeparators(final Object[] array, final String separator) { 1456 if (array != null && array.length > 0) { 1457 final String sep = Objects.toString(separator, StringUtils.EMPTY); 1458 append(array[0]); 1459 for (int i = 1; i < array.length; i++) { 1460 append(sep); 1461 append(array[i]); 1462 } 1463 } 1464 return this; 1465 } 1466 1467 /** 1468 * Gets the contents of this builder as a Reader. 1469 * <p> 1470 * This method allows the contents of the builder to be read using any standard method that expects a Reader. 1471 * </p> 1472 * <p> 1473 * To use, simply create a {@code StrBuilder}, populate it with data, call {@code asReader}, and then read away. 1474 * </p> 1475 * <p> 1476 * The internal character array is shared between the builder and the reader. This allows you to append to the 1477 * builder after creating the reader, and the changes will be picked up. Note however, that no synchronization 1478 * occurs, so you must perform all operations with the builder and the reader in one thread. 1479 * </p> 1480 * <p> 1481 * The returned reader supports marking, and ignores the flush method. 1482 * </p> 1483 * 1484 * @return a reader that reads from this builder 1485 */ 1486 public Reader asReader() { 1487 return new TextStringBuilderReader(); 1488 } 1489 1490 /** 1491 * Creates a tokenizer that can tokenize the contents of this builder. 1492 * <p> 1493 * This method allows the contents of this builder to be tokenized. The tokenizer will be setup by default to 1494 * tokenize on space, tab, newline and form feed (as per StringTokenizer). These values can be changed on the 1495 * tokenizer class, before retrieving the tokens. 1496 * </p> 1497 * <p> 1498 * The returned tokenizer is linked to this builder. You may intermix calls to the builder and tokenizer within 1499 * certain limits, however there is no synchronization. Once the tokenizer has been used once, it must be 1500 * {@link StringTokenizer#reset() reset} to pickup the latest changes in the builder. For example: 1501 * </p> 1502 * 1503 * <pre> 1504 * StrBuilder b = new StrBuilder(); 1505 * b.append("a b "); 1506 * StrTokenizer t = b.asTokenizer(); 1507 * String[] tokens1 = t.getTokenArray(); // returns a,b 1508 * b.append("c d "); 1509 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored) 1510 * t.reset(); // reset causes builder changes to be picked up 1511 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d 1512 * </pre> 1513 * 1514 * <p> 1515 * In addition to simply intermixing appends and tokenization, you can also call the set methods on the tokenizer to 1516 * alter how it tokenizes. Just remember to call reset when you want to pickup builder changes. 1517 * </p> 1518 * <p> 1519 * Calling {@link StringTokenizer#reset(String)} or {@link StringTokenizer#reset(char[])} with a non-null value will 1520 * break the link with the builder. 1521 * </p> 1522 * 1523 * @return a tokenizer that is linked to this builder 1524 */ 1525 public StringTokenizer asTokenizer() { 1526 return new TextStringBuilderTokenizer(); 1527 } 1528 1529 /** 1530 * Gets this builder as a Writer that can be written to. 1531 * <p> 1532 * This method allows you to populate the contents of the builder using any standard method that takes a Writer. 1533 * </p> 1534 * <p> 1535 * To use, simply create a {@code StrBuilder}, call {@code asWriter}, and populate away. The data is available at 1536 * any time using the methods of the {@code StrBuilder}. 1537 * </p> 1538 * <p> 1539 * The internal character array is shared between the builder and the writer. This allows you to intermix calls that 1540 * append to the builder and write using the writer and the changes will be occur correctly. Note however, that no 1541 * synchronization occurs, so you must perform all operations with the builder and the writer in one thread. 1542 * </p> 1543 * <p> 1544 * The returned writer ignores the close and flush methods. 1545 * </p> 1546 * 1547 * @return a writer that populates this builder 1548 */ 1549 public Writer asWriter() { 1550 return new TextStringBuilderWriter(); 1551 } 1552 1553 /** 1554 * Converts this instance to a String. 1555 * 1556 * @return This instance as a String 1557 * @see #toString() 1558 * @deprecated Use {@link #get()}. 1559 */ 1560 @Deprecated 1561 @Override 1562 public String build() { 1563 return toString(); 1564 } 1565 1566 /** 1567 * Gets the current size of the internal character array buffer. 1568 * 1569 * @return The capacity 1570 */ 1571 public int capacity() { 1572 return buffer.length; 1573 } 1574 1575 /** 1576 * Gets the character at the specified index. 1577 * 1578 * @see #setCharAt(int, char) 1579 * @see #deleteCharAt(int) 1580 * @param index the index to retrieve, must be valid 1581 * @return The character at the index 1582 * @throws IndexOutOfBoundsException if the index is invalid 1583 */ 1584 @Override 1585 public char charAt(final int index) { 1586 validateIndex(index); 1587 return buffer[index]; 1588 } 1589 1590 /** 1591 * Clears the string builder (convenience Collections API style method). 1592 * <p> 1593 * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed 1594 * by {@link #minimizeCapacity()}. 1595 * </p> 1596 * <p> 1597 * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of 1598 * Collections. 1599 * </p> 1600 * 1601 * @return this, to enable chaining 1602 */ 1603 public TextStringBuilder clear() { 1604 size = 0; 1605 return this; 1606 } 1607 1608 /** 1609 * Tests if the string builder contains the specified char. 1610 * 1611 * @param ch the character to find 1612 * @return true if the builder contains the character 1613 */ 1614 public boolean contains(final char ch) { 1615 final char[] thisBuf = buffer; 1616 for (int i = 0; i < this.size; i++) { 1617 if (thisBuf[i] == ch) { 1618 return true; 1619 } 1620 } 1621 return false; 1622 } 1623 1624 /** 1625 * Tests if the string builder contains the specified string. 1626 * 1627 * @param str the string to find 1628 * @return true if the builder contains the string 1629 */ 1630 public boolean contains(final String str) { 1631 return indexOf(str, 0) >= 0; 1632 } 1633 1634 /** 1635 * Tests if the string builder contains a string matched using the specified matcher. 1636 * <p> 1637 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for 1638 * the character 'a' followed by a number. 1639 * </p> 1640 * 1641 * @param matcher the matcher to use, null returns -1 1642 * @return true if the matcher finds a match in the builder 1643 */ 1644 public boolean contains(final StringMatcher matcher) { 1645 return indexOf(matcher, 0) >= 0; 1646 } 1647 1648 /** 1649 * Deletes the characters between the two specified indices. 1650 * 1651 * @param startIndex the start index, inclusive, must be valid 1652 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 1653 * @return this, to enable chaining 1654 * @throws IndexOutOfBoundsException if the index is invalid 1655 */ 1656 public TextStringBuilder delete(final int startIndex, final int endIndex) { 1657 final int actualEndIndex = validateRange(startIndex, endIndex); 1658 final int len = actualEndIndex - startIndex; 1659 if (len > 0) { 1660 deleteImpl(startIndex, actualEndIndex, len); 1661 } 1662 return this; 1663 } 1664 1665 /** 1666 * Deletes the character wherever it occurs in the builder. 1667 * 1668 * @param ch the character to delete 1669 * @return this, to enable chaining 1670 */ 1671 public TextStringBuilder deleteAll(final char ch) { 1672 for (int i = 0; i < size; i++) { 1673 if (buffer[i] == ch) { 1674 final int start = i; 1675 while (++i < size) { 1676 if (buffer[i] != ch) { 1677 break; 1678 } 1679 } 1680 final int len = i - start; 1681 deleteImpl(start, i, len); 1682 i -= len; 1683 } 1684 } 1685 return this; 1686 } 1687 1688 /** 1689 * Deletes the string wherever it occurs in the builder. 1690 * 1691 * @param str the string to delete, null causes no action 1692 * @return this, to enable chaining 1693 */ 1694 public TextStringBuilder deleteAll(final String str) { 1695 final int len = str == null ? 0 : str.length(); 1696 if (len > 0) { 1697 int index = indexOf(str, 0); 1698 while (index >= 0) { 1699 deleteImpl(index, index + len, len); 1700 index = indexOf(str, index); 1701 } 1702 } 1703 return this; 1704 } 1705 1706 /** 1707 * Deletes all parts of the builder that the matcher matches. 1708 * <p> 1709 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all 1710 * occurrences where the character 'a' is followed by a number. 1711 * </p> 1712 * 1713 * @param matcher the matcher to use to find the deletion, null causes no action 1714 * @return this, to enable chaining 1715 */ 1716 public TextStringBuilder deleteAll(final StringMatcher matcher) { 1717 return replace(matcher, null, 0, size, -1); 1718 } 1719 1720 /** 1721 * Deletes the character at the specified index. 1722 * 1723 * @see #charAt(int) 1724 * @see #setCharAt(int, char) 1725 * @param index the index to delete 1726 * @return this, to enable chaining 1727 * @throws IndexOutOfBoundsException if the index is invalid 1728 */ 1729 public TextStringBuilder deleteCharAt(final int index) { 1730 validateIndex(index); 1731 deleteImpl(index, index + 1, 1); 1732 return this; 1733 } 1734 1735 /** 1736 * Deletes the character wherever it occurs in the builder. 1737 * 1738 * @param ch the character to delete 1739 * @return this, to enable chaining 1740 */ 1741 public TextStringBuilder deleteFirst(final char ch) { 1742 for (int i = 0; i < size; i++) { 1743 if (buffer[i] == ch) { 1744 deleteImpl(i, i + 1, 1); 1745 break; 1746 } 1747 } 1748 return this; 1749 } 1750 1751 /** 1752 * Deletes the string wherever it occurs in the builder. 1753 * 1754 * @param str the string to delete, null causes no action 1755 * @return this, to enable chaining 1756 */ 1757 public TextStringBuilder deleteFirst(final String str) { 1758 final int len = str == null ? 0 : str.length(); 1759 if (len > 0) { 1760 final int index = indexOf(str, 0); 1761 if (index >= 0) { 1762 deleteImpl(index, index + len, len); 1763 } 1764 } 1765 return this; 1766 } 1767 1768 /** 1769 * Deletes the first match within the builder using the specified matcher. 1770 * <p> 1771 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where 1772 * the character 'a' is followed by a number. 1773 * </p> 1774 * 1775 * @param matcher the matcher to use to find the deletion, null causes no action 1776 * @return this, to enable chaining 1777 */ 1778 public TextStringBuilder deleteFirst(final StringMatcher matcher) { 1779 return replace(matcher, null, 0, size, 1); 1780 } 1781 1782 /** 1783 * Internal method to delete a range without validation. 1784 * 1785 * @param startIndex the start index, must be valid 1786 * @param endIndex the end index (exclusive), must be valid 1787 * @param len the length, must be valid 1788 * @throws IndexOutOfBoundsException if any index is invalid 1789 */ 1790 private void deleteImpl(final int startIndex, final int endIndex, final int len) { 1791 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); 1792 size -= len; 1793 } 1794 1795 /** 1796 * Gets the character at the specified index before deleting it. 1797 * 1798 * @see #charAt(int) 1799 * @see #deleteCharAt(int) 1800 * @param index the index to retrieve, must be valid 1801 * @return The character at the index 1802 * @throws IndexOutOfBoundsException if the index is invalid 1803 * @since 1.9 1804 */ 1805 public char drainChar(final int index) { 1806 validateIndex(index); 1807 final char c = buffer[index]; 1808 deleteCharAt(index); 1809 return c; 1810 } 1811 1812 /** 1813 * Drains (copies, then deletes) this character sequence into the specified array. This is equivalent to copying the 1814 * characters from this sequence into the target and then deleting those character from this sequence. 1815 * 1816 * @param startIndex first index to copy, inclusive. 1817 * @param endIndex last index to copy, exclusive. 1818 * @param target the target array, must not be {@code null}. 1819 * @param targetIndex the index to start copying in the target. 1820 * @return How many characters where copied (then deleted). If this builder is empty, return {@code 0}. 1821 * @since 1.9 1822 */ 1823 public int drainChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) { 1824 final int length = endIndex - startIndex; 1825 if (isEmpty() || length == 0 || target.length == 0) { 1826 return 0; 1827 } 1828 final int actualLen = Math.min(Math.min(size, length), target.length - targetIndex); 1829 getChars(startIndex, actualLen, target, targetIndex); 1830 delete(startIndex, actualLen); 1831 return actualLen; 1832 } 1833 1834 /** 1835 * Checks whether this builder ends with the specified string. 1836 * <p> 1837 * Note that this method handles null input quietly, unlike String. 1838 * </p> 1839 * 1840 * @param str the string to search for, null returns false 1841 * @return true if the builder ends with the string 1842 */ 1843 public boolean endsWith(final String str) { 1844 if (str == null) { 1845 return false; 1846 } 1847 final int len = str.length(); 1848 if (len == 0) { 1849 return true; 1850 } 1851 if (len > size) { 1852 return false; 1853 } 1854 int pos = size - len; 1855 for (int i = 0; i < len; i++, pos++) { 1856 if (buffer[pos] != str.charAt(i)) { 1857 return false; 1858 } 1859 } 1860 return true; 1861 } 1862 1863 /** 1864 * Tests the capacity and ensures that it is at least the size specified. 1865 * 1866 * <p> 1867 * Note: This method can be used to minimise memory reallocations during 1868 * repeated addition of values by pre-allocating the character buffer. 1869 * The method ignores a negative {@code capacity} argument. 1870 * </p> 1871 * 1872 * @param capacity the capacity to ensure 1873 * @return this, to enable chaining 1874 * @throws OutOfMemoryError if the capacity cannot be allocated 1875 */ 1876 public TextStringBuilder ensureCapacity(final int capacity) { 1877 if (capacity > 0) { 1878 ensureCapacityInternal(capacity); 1879 } 1880 return this; 1881 } 1882 1883 /** 1884 * Ensures that the buffer is at least the size specified. The {@code capacity} argument 1885 * is treated as an unsigned integer. 1886 * 1887 * <p> 1888 * This method will raise an {@link OutOfMemoryError} if the capacity is too large 1889 * for an array, or cannot be allocated. 1890 * </p> 1891 * 1892 * @param capacity the capacity to ensure 1893 * @throws OutOfMemoryError if the capacity cannot be allocated 1894 */ 1895 private void ensureCapacityInternal(final int capacity) { 1896 // Check for overflow of the current buffer. 1897 // Assumes capacity is an unsigned integer up to Integer.MAX_VALUE * 2 1898 // (the largest possible addition of two maximum length arrays). 1899 if (capacity - buffer.length > 0) { 1900 resizeBuffer(capacity); 1901 } 1902 } 1903 1904 /** 1905 * Tests the contents of this builder against another to see if they contain the same character content. 1906 * 1907 * @param obj the object to check, null returns false 1908 * @return true if the builders contain the same characters in the same order 1909 */ 1910 @Override 1911 public boolean equals(final Object obj) { 1912 return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj); 1913 } 1914 1915 /** 1916 * Tests the contents of this builder against another to see if they contain the same character content. 1917 * 1918 * @param other the object to check, null returns false 1919 * @return true if the builders contain the same characters in the same order 1920 */ 1921 public boolean equals(final TextStringBuilder other) { 1922 if (this == other) { 1923 return true; 1924 } 1925 if (other == null) { 1926 return false; 1927 } 1928 if (this.size != other.size) { 1929 return false; 1930 } 1931 // Be aware not to use Arrays.equals(buffer, other.buffer) for equals() method 1932 // as length of the buffers may be different (TEXT-211) 1933 final char[] thisBuf = this.buffer; 1934 final char[] otherBuf = other.buffer; 1935 for (int i = size - 1; i >= 0; i--) { 1936 if (thisBuf[i] != otherBuf[i]) { 1937 return false; 1938 } 1939 } 1940 return true; 1941 } 1942 1943 /** 1944 * Tests the contents of this builder against another to see if they contain the same character content ignoring 1945 * case. 1946 * 1947 * @param other the object to check, null returns false 1948 * @return true if the builders contain the same characters in the same order 1949 */ 1950 public boolean equalsIgnoreCase(final TextStringBuilder other) { 1951 if (this == other) { 1952 return true; 1953 } 1954 if (this.size != other.size) { 1955 return false; 1956 } 1957 final char[] thisBuf = this.buffer; 1958 final char[] otherBuf = other.buffer; 1959 for (int i = size - 1; i >= 0; i--) { 1960 final char c1 = thisBuf[i]; 1961 final char c2 = otherBuf[i]; 1962 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { 1963 return false; 1964 } 1965 } 1966 return true; 1967 } 1968 1969 /** 1970 * Converts this instance to a String. 1971 * 1972 * @return This instance as a String 1973 * @see #toString() 1974 * @since 1.12.0 1975 */ 1976 @Override 1977 public String get() { 1978 return toString(); 1979 } 1980 1981 /** 1982 * Gets a direct reference to internal storage, not for public consumption. 1983 */ 1984 char[] getBuffer() { 1985 return buffer; 1986 } 1987 1988 /** 1989 * Copies this character array into the specified array. 1990 * 1991 * @param target the target array, null will cause an array to be created 1992 * @return The input array, unless that was null or too small 1993 */ 1994 public char[] getChars(char[] target) { 1995 final int len = length(); 1996 if (target == null || target.length < len) { 1997 target = new char[len]; 1998 } 1999 System.arraycopy(buffer, 0, target, 0, len); 2000 return target; 2001 } 2002 2003 /** 2004 * Copies this character array into the specified array. 2005 * 2006 * @param startIndex first index to copy, inclusive, must be valid. 2007 * @param endIndex last index to copy, exclusive, must be valid. 2008 * @param target the target array, must not be null or too small. 2009 * @param targetIndex the index to start copying in target. 2010 * @throws NullPointerException if the array is null. 2011 * @throws IndexOutOfBoundsException if any index is invalid. 2012 */ 2013 public void getChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) { 2014 if (startIndex < 0) { 2015 throw new StringIndexOutOfBoundsException(startIndex); 2016 } 2017 if (endIndex < 0 || endIndex > length()) { 2018 throw new StringIndexOutOfBoundsException(endIndex); 2019 } 2020 if (startIndex > endIndex) { 2021 throw new StringIndexOutOfBoundsException("end < start"); 2022 } 2023 System.arraycopy(buffer, startIndex, target, targetIndex, endIndex - startIndex); 2024 } 2025 2026 /** 2027 * Gets the text to be appended when a {@link #appendNewLine() new line} is added. 2028 * 2029 * @return The new line text, {@code null} means use the system default from {@link System#lineSeparator()}. 2030 */ 2031 public String getNewLineText() { 2032 return newLine; 2033 } 2034 2035 /** 2036 * Gets the text to be appended when null is added. 2037 * 2038 * @return The null text, null means no append 2039 */ 2040 public String getNullText() { 2041 return nullText; 2042 } 2043 2044 /** 2045 * Gets a suitable hash code for this builder. 2046 * 2047 * @return a hash code 2048 */ 2049 @Override 2050 public int hashCode() { 2051 // no allocation 2052 final char[] buf = buffer; 2053 int result = 0; 2054 for (int i = 0; i < size; i++) { 2055 result = 31 * result + buf[i]; 2056 } 2057 return result; 2058 } 2059 2060 /** 2061 * Searches the string builder to find the first reference to the specified char. 2062 * 2063 * @param ch the character to find 2064 * @return The first index of the character, or -1 if not found 2065 */ 2066 public int indexOf(final char ch) { 2067 return indexOf(ch, 0); 2068 } 2069 2070 /** 2071 * Searches the string builder to find the first reference to the specified char. 2072 * 2073 * @param ch the character to find 2074 * @param startIndex the index to start at, invalid index rounded to edge 2075 * @return The first index of the character, or -1 if not found 2076 */ 2077 public int indexOf(final char ch, int startIndex) { 2078 startIndex = Math.max(0, startIndex); 2079 if (startIndex >= size) { 2080 return StringUtils.INDEX_NOT_FOUND; 2081 } 2082 final char[] thisBuf = buffer; 2083 for (int i = startIndex; i < size; i++) { 2084 if (thisBuf[i] == ch) { 2085 return i; 2086 } 2087 } 2088 return StringUtils.INDEX_NOT_FOUND; 2089 } 2090 2091 /** 2092 * Searches the string builder to find the first reference to the specified string. 2093 * <p> 2094 * Note that a null input string will return -1, whereas the JDK throws an exception. 2095 * </p> 2096 * 2097 * @param str the string to find, null returns -1 2098 * @return The first index of the string, or -1 if not found 2099 */ 2100 public int indexOf(final String str) { 2101 return indexOf(str, 0); 2102 } 2103 2104 /** 2105 * Searches the string builder to find the first reference to the specified string starting searching from the given 2106 * index. 2107 * <p> 2108 * Note that a null input string will return -1, whereas the JDK throws an exception. 2109 * </p> 2110 * 2111 * @param str the string to find, null returns -1 2112 * @param startIndex the index to start at, invalid index rounded to edge 2113 * @return The first index of the string, or -1 if not found 2114 */ 2115 public int indexOf(final String str, int startIndex) { 2116 startIndex = Math.max(0, startIndex); 2117 if (str == null || startIndex >= size) { 2118 return StringUtils.INDEX_NOT_FOUND; 2119 } 2120 final int strLen = str.length(); 2121 if (strLen == 1) { 2122 return indexOf(str.charAt(0), startIndex); 2123 } 2124 if (strLen == 0) { 2125 return startIndex; 2126 } 2127 if (strLen > size) { 2128 return StringUtils.INDEX_NOT_FOUND; 2129 } 2130 final char[] thisBuf = buffer; 2131 final int searchLen = size - strLen + 1; 2132 for (int i = startIndex; i < searchLen; i++) { 2133 boolean found = true; 2134 for (int j = 0; j < strLen && found; j++) { 2135 found = str.charAt(j) == thisBuf[i + j]; 2136 } 2137 if (found) { 2138 return i; 2139 } 2140 } 2141 return StringUtils.INDEX_NOT_FOUND; 2142 } 2143 2144 /** 2145 * Searches the string builder using the matcher to find the first match. 2146 * <p> 2147 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2148 * character 'a' followed by a number. 2149 * </p> 2150 * 2151 * @param matcher the matcher to use, null returns -1 2152 * @return The first index matched, or -1 if not found 2153 */ 2154 public int indexOf(final StringMatcher matcher) { 2155 return indexOf(matcher, 0); 2156 } 2157 2158 /** 2159 * Searches the string builder using the matcher to find the first match searching from the given index. 2160 * <p> 2161 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2162 * character 'a' followed by a number. 2163 * </p> 2164 * 2165 * @param matcher the matcher to use, null returns -1 2166 * @param startIndex the index to start at, invalid index rounded to edge 2167 * @return The first index matched, or -1 if not found 2168 */ 2169 public int indexOf(final StringMatcher matcher, int startIndex) { 2170 startIndex = Math.max(0, startIndex); 2171 if (matcher == null || startIndex >= size) { 2172 return StringUtils.INDEX_NOT_FOUND; 2173 } 2174 final int len = size; 2175 final char[] buf = buffer; 2176 for (int i = startIndex; i < len; i++) { 2177 if (matcher.isMatch(buf, i, startIndex, len) > 0) { 2178 return i; 2179 } 2180 } 2181 return StringUtils.INDEX_NOT_FOUND; 2182 } 2183 2184 /** 2185 * Inserts the value into this builder. 2186 * 2187 * @param index the index to add at, must be valid 2188 * @param value the value to insert 2189 * @return this, to enable chaining 2190 * @throws IndexOutOfBoundsException if the index is invalid 2191 */ 2192 public TextStringBuilder insert(final int index, final boolean value) { 2193 validateIndex(index); 2194 if (value) { 2195 ensureCapacityInternal(size + TRUE_STRING_SIZE); 2196 System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index); 2197 appendTrue(index); 2198 } else { 2199 ensureCapacityInternal(size + FALSE_STRING_SIZE); 2200 System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index); 2201 appendFalse(index); 2202 } 2203 return this; 2204 } 2205 2206 /** 2207 * Inserts the value into this builder. 2208 * 2209 * @param index the index to add at, must be valid 2210 * @param value the value to insert 2211 * @return this, to enable chaining 2212 * @throws IndexOutOfBoundsException if the index is invalid 2213 */ 2214 public TextStringBuilder insert(final int index, final char value) { 2215 validateIndex(index); 2216 ensureCapacityInternal(size + 1); 2217 System.arraycopy(buffer, index, buffer, index + 1, size - index); 2218 buffer[index] = value; 2219 size++; 2220 return this; 2221 } 2222 2223 /** 2224 * Inserts the character array into this builder. Inserting null will use the stored null text value. 2225 * 2226 * @param index the index to add at, must be valid 2227 * @param chars the char array to insert 2228 * @return this, to enable chaining 2229 * @throws IndexOutOfBoundsException if the index is invalid 2230 */ 2231 public TextStringBuilder insert(final int index, final char[] chars) { 2232 validateIndex(index); 2233 if (chars == null) { 2234 return insert(index, nullText); 2235 } 2236 final int len = chars.length; 2237 if (len > 0) { 2238 ensureCapacityInternal(size + len); 2239 System.arraycopy(buffer, index, buffer, index + len, size - index); 2240 System.arraycopy(chars, 0, buffer, index, len); 2241 size += len; 2242 } 2243 return this; 2244 } 2245 2246 /** 2247 * Inserts part of the character array into this builder. Inserting null will use the stored null text value. 2248 * 2249 * @param index the index to add at, must be valid 2250 * @param chars the char array to insert 2251 * @param offset the offset into the character array to start at, must be valid 2252 * @param length the length of the character array part to copy, must be positive 2253 * @return this, to enable chaining 2254 * @throws IndexOutOfBoundsException if any index is invalid 2255 */ 2256 public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) { 2257 validateIndex(index); 2258 if (chars == null) { 2259 return insert(index, nullText); 2260 } 2261 if (offset < 0 || offset > chars.length) { 2262 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); 2263 } 2264 if (length < 0 || offset + length > chars.length) { 2265 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 2266 } 2267 if (length > 0) { 2268 ensureCapacityInternal(size + length); 2269 System.arraycopy(buffer, index, buffer, index + length, size - index); 2270 System.arraycopy(chars, offset, buffer, index, length); 2271 size += length; 2272 } 2273 return this; 2274 } 2275 2276 /** 2277 * Inserts the value into this builder. 2278 * 2279 * @param index the index to add at, must be valid 2280 * @param value the value to insert 2281 * @return this, to enable chaining 2282 * @throws IndexOutOfBoundsException if the index is invalid 2283 */ 2284 public TextStringBuilder insert(final int index, final double value) { 2285 return insert(index, String.valueOf(value)); 2286 } 2287 2288 /** 2289 * Inserts the value into this builder. 2290 * 2291 * @param index the index to add at, must be valid 2292 * @param value the value to insert 2293 * @return this, to enable chaining 2294 * @throws IndexOutOfBoundsException if the index is invalid 2295 */ 2296 public TextStringBuilder insert(final int index, final float value) { 2297 return insert(index, String.valueOf(value)); 2298 } 2299 2300 /** 2301 * Inserts the value into this builder. 2302 * 2303 * @param index the index to add at, must be valid 2304 * @param value the value to insert 2305 * @return this, to enable chaining 2306 * @throws IndexOutOfBoundsException if the index is invalid 2307 */ 2308 public TextStringBuilder insert(final int index, final int value) { 2309 return insert(index, String.valueOf(value)); 2310 } 2311 2312 /** 2313 * Inserts the value into this builder. 2314 * 2315 * @param index the index to add at, must be valid 2316 * @param value the value to insert 2317 * @return this, to enable chaining 2318 * @throws IndexOutOfBoundsException if the index is invalid 2319 */ 2320 public TextStringBuilder insert(final int index, final long value) { 2321 return insert(index, String.valueOf(value)); 2322 } 2323 2324 /** 2325 * Inserts the string representation of an object into this builder. Inserting null will use the stored null text 2326 * value. 2327 * 2328 * @param index the index to add at, must be valid 2329 * @param obj the object to insert 2330 * @return this, to enable chaining 2331 * @throws IndexOutOfBoundsException if the index is invalid 2332 */ 2333 public TextStringBuilder insert(final int index, final Object obj) { 2334 if (obj == null) { 2335 return insert(index, nullText); 2336 } 2337 return insert(index, obj.toString()); 2338 } 2339 2340 /** 2341 * Inserts the string into this builder. Inserting null will use the stored null text value. 2342 * 2343 * @param index the index to add at, must be valid 2344 * @param str the string to insert 2345 * @return this, to enable chaining 2346 * @throws IndexOutOfBoundsException if the index is invalid 2347 */ 2348 public TextStringBuilder insert(final int index, String str) { 2349 validateIndex(index); 2350 if (str == null) { 2351 str = nullText; 2352 } 2353 if (str != null) { 2354 final int strLen = str.length(); 2355 if (strLen > 0) { 2356 final int newSize = size + strLen; 2357 ensureCapacityInternal(newSize); 2358 System.arraycopy(buffer, index, buffer, index + strLen, size - index); 2359 size = newSize; 2360 str.getChars(0, strLen, buffer, index); 2361 } 2362 } 2363 return this; 2364 } 2365 2366 /** 2367 * Checks is the string builder is empty (convenience Collections API style method). 2368 * <p> 2369 * This method is the same as checking {@link #length()} and is provided to match the API of Collections. 2370 * </p> 2371 * 2372 * @return {@code true} if the size is {@code 0}. 2373 */ 2374 public boolean isEmpty() { 2375 return size == 0; 2376 } 2377 2378 /** 2379 * Checks is the string builder is not empty. 2380 * <p> 2381 * This method is the same as checking {@link #length()}. 2382 * </p> 2383 * 2384 * @return {@code true} if the size is not {@code 0}. 2385 * @since 1.9 2386 */ 2387 public boolean isNotEmpty() { 2388 return size != 0; 2389 } 2390 2391 /** 2392 * Gets whether the internal buffer has been reallocated. 2393 * 2394 * @return Whether the internal buffer has been reallocated. 2395 * @since 1.9 2396 */ 2397 public boolean isReallocated() { 2398 return reallocations > 0; 2399 } 2400 2401 /** 2402 * Searches the string builder to find the last reference to the specified char. 2403 * 2404 * @param ch the character to find 2405 * @return The last index of the character, or -1 if not found 2406 */ 2407 public int lastIndexOf(final char ch) { 2408 return lastIndexOf(ch, size - 1); 2409 } 2410 2411 /** 2412 * Searches the string builder to find the last reference to the specified char. 2413 * 2414 * @param ch the character to find 2415 * @param startIndex the index to start at, invalid index rounded to edge 2416 * @return The last index of the character, or -1 if not found 2417 */ 2418 public int lastIndexOf(final char ch, int startIndex) { 2419 startIndex = startIndex >= size ? size - 1 : startIndex; 2420 if (startIndex < 0) { 2421 return StringUtils.INDEX_NOT_FOUND; 2422 } 2423 for (int i = startIndex; i >= 0; i--) { 2424 if (buffer[i] == ch) { 2425 return i; 2426 } 2427 } 2428 return StringUtils.INDEX_NOT_FOUND; 2429 } 2430 2431 /** 2432 * Searches the string builder to find the last reference to the specified string. 2433 * <p> 2434 * Note that a null input string will return -1, whereas the JDK throws an exception. 2435 * </p> 2436 * 2437 * @param str the string to find, null returns -1 2438 * @return The last index of the string, or -1 if not found 2439 */ 2440 public int lastIndexOf(final String str) { 2441 return lastIndexOf(str, size - 1); 2442 } 2443 2444 /** 2445 * Searches the string builder to find the last reference to the specified string starting searching from the given 2446 * index. 2447 * <p> 2448 * Note that a null input string will return -1, whereas the JDK throws an exception. 2449 * </p> 2450 * 2451 * @param str the string to find, null returns -1 2452 * @param startIndex the index to start at, invalid index rounded to edge 2453 * @return The last index of the string, or -1 if not found 2454 */ 2455 public int lastIndexOf(final String str, int startIndex) { 2456 startIndex = startIndex >= size ? size - 1 : startIndex; 2457 if (str == null || startIndex < 0) { 2458 return StringUtils.INDEX_NOT_FOUND; 2459 } 2460 final int strLen = str.length(); 2461 if (strLen == 0) { 2462 return startIndex; 2463 } 2464 if (strLen > size) { 2465 return StringUtils.INDEX_NOT_FOUND; 2466 } 2467 if (strLen == 1) { 2468 return lastIndexOf(str.charAt(0), startIndex); 2469 } 2470 for (int i = startIndex - strLen + 1; i >= 0; i--) { 2471 boolean found = true; 2472 for (int j = 0; j < strLen && found; j++) { 2473 found = str.charAt(j) == buffer[i + j]; 2474 } 2475 if (found) { 2476 return i; 2477 } 2478 } 2479 return StringUtils.INDEX_NOT_FOUND; 2480 } 2481 2482 /** 2483 * Searches the string builder using the matcher to find the last match. 2484 * <p> 2485 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2486 * character 'a' followed by a number. 2487 * </p> 2488 * 2489 * @param matcher the matcher to use, null returns -1 2490 * @return The last index matched, or -1 if not found 2491 */ 2492 public int lastIndexOf(final StringMatcher matcher) { 2493 return lastIndexOf(matcher, size); 2494 } 2495 2496 /** 2497 * Searches the string builder using the matcher to find the last match searching from the given index. 2498 * <p> 2499 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2500 * character 'a' followed by a number. 2501 * </p> 2502 * 2503 * @param matcher the matcher to use, null returns -1 2504 * @param startIndex the index to start at, invalid index rounded to edge 2505 * @return The last index matched, or -1 if not found 2506 */ 2507 public int lastIndexOf(final StringMatcher matcher, int startIndex) { 2508 startIndex = startIndex >= size ? size - 1 : startIndex; 2509 if (matcher == null || startIndex < 0) { 2510 return StringUtils.INDEX_NOT_FOUND; 2511 } 2512 final char[] buf = buffer; 2513 final int endIndex = startIndex + 1; 2514 for (int i = startIndex; i >= 0; i--) { 2515 if (matcher.isMatch(buf, i, 0, endIndex) > 0) { 2516 return i; 2517 } 2518 } 2519 return StringUtils.INDEX_NOT_FOUND; 2520 } 2521 2522 /** 2523 * Extracts the leftmost characters from the string builder without throwing an exception. 2524 * <p> 2525 * This method extracts the left {@code length} characters from the builder. If this many characters are not 2526 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2527 * </p> 2528 * 2529 * @param length the number of characters to extract, negative returns empty string 2530 * @return The new string 2531 */ 2532 public String leftString(final int length) { 2533 if (length <= 0) { 2534 return StringUtils.EMPTY; 2535 } 2536 if (length >= size) { 2537 return new String(buffer, 0, size); 2538 } 2539 return new String(buffer, 0, length); 2540 } 2541 2542 /** 2543 * Gets the length of the string builder. 2544 * 2545 * @return The length 2546 */ 2547 @Override 2548 public int length() { 2549 return size; 2550 } 2551 2552 /** 2553 * Extracts some characters from the middle of the string builder without throwing an exception. 2554 * <p> 2555 * This method extracts {@code length} characters from the builder at the specified index. If the index is negative 2556 * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the 2557 * length is negative, the empty string is returned. If insufficient characters are available in the builder, as 2558 * much as possible is returned. Thus the returned string may be shorter than the length requested. 2559 * </p> 2560 * 2561 * @param index the index to start at, negative means zero 2562 * @param length the number of characters to extract, negative returns empty string 2563 * @return The new string 2564 */ 2565 public String midString(int index, final int length) { 2566 if (index < 0) { 2567 index = 0; 2568 } 2569 if (length <= 0 || index >= size) { 2570 return StringUtils.EMPTY; 2571 } 2572 if (size <= index + length) { 2573 return new String(buffer, index, size - index); 2574 } 2575 return new String(buffer, index, length); 2576 } 2577 2578 /** 2579 * Minimizes the capacity to the actual length of the string. 2580 * 2581 * @return this, to enable chaining 2582 */ 2583 public TextStringBuilder minimizeCapacity() { 2584 if (buffer.length > size) { 2585 reallocate(size); 2586 } 2587 return this; 2588 } 2589 2590 /** 2591 * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without 2592 * making extra copies. 2593 * 2594 * @param charBuffer CharBuffer to read. 2595 * @return The number of characters read. 2596 * @see #appendTo(Appendable) 2597 * @since 1.9 2598 */ 2599 public int readFrom(final CharBuffer charBuffer) { 2600 final int oldSize = size; 2601 final int remaining = charBuffer.remaining(); 2602 ensureCapacityInternal(size + remaining); 2603 charBuffer.get(buffer, size, remaining); 2604 size += remaining; 2605 return size - oldSize; 2606 } 2607 2608 /** 2609 * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without 2610 * making extra copies. 2611 * 2612 * @param readable object to read from 2613 * @return The number of characters read 2614 * @throws IOException if an I/O error occurs. 2615 * @see #appendTo(Appendable) 2616 */ 2617 public int readFrom(final Readable readable) throws IOException { 2618 if (readable instanceof Reader) { 2619 return readFrom((Reader) readable); 2620 } 2621 if (readable instanceof CharBuffer) { 2622 return readFrom((CharBuffer) readable); 2623 } 2624 final int oldSize = size; 2625 while (true) { 2626 ensureCapacityInternal(size + 1); 2627 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); 2628 final int read = readable.read(buf); 2629 if (read == EOS) { 2630 break; 2631 } 2632 size += read; 2633 } 2634 return size - oldSize; 2635 } 2636 2637 /** 2638 * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without 2639 * making extra copies. 2640 * 2641 * @param reader Reader to read. 2642 * @return The number of characters read or -1 if we reached the end of stream. 2643 * @throws IOException if an I/O error occurs. 2644 * @see #appendTo(Appendable) 2645 * @since 1.9 2646 */ 2647 public int readFrom(final Reader reader) throws IOException { 2648 final int oldSize = size; 2649 ensureCapacityInternal(size + 1); 2650 int readCount = reader.read(buffer, size, buffer.length - size); 2651 if (readCount == EOS) { 2652 return EOS; 2653 } 2654 do { 2655 size += readCount; 2656 ensureCapacityInternal(size + 1); 2657 readCount = reader.read(buffer, size, buffer.length - size); 2658 } while (readCount != EOS); 2659 return size - oldSize; 2660 } 2661 2662 /** 2663 * If possible, reads {@code count} chars from the provided {@link Reader} directly into underlying character buffer 2664 * without making extra copies. 2665 * 2666 * @param reader Reader to read. 2667 * @param count The maximum characters to read, a value <= 0 returns 0. 2668 * @return The number of characters read. If less than {@code count}, then we've reached the end-of-stream, or -1 if 2669 * we reached the end of stream. 2670 * @throws IOException if an I/O error occurs. 2671 * @see #appendTo(Appendable) 2672 * @since 1.9 2673 */ 2674 public int readFrom(final Reader reader, final int count) throws IOException { 2675 if (count <= 0) { 2676 return 0; 2677 } 2678 final int oldSize = size; 2679 ensureCapacityInternal(size + count); 2680 int target = count; 2681 int readCount = reader.read(buffer, size, target); 2682 if (readCount == EOS) { 2683 return EOS; 2684 } 2685 do { 2686 target -= readCount; 2687 size += readCount; 2688 readCount = reader.read(buffer, size, target); 2689 } while (target > 0 && readCount != EOS); 2690 return size - oldSize; 2691 } 2692 2693 /** 2694 * Reallocates the buffer to the new length. 2695 * 2696 * @param newLength the length of the copy to be returned 2697 */ 2698 private void reallocate(final int newLength) { 2699 this.buffer = Arrays.copyOf(buffer, newLength); 2700 this.reallocations++; 2701 } 2702 2703 /** 2704 * Replaces a portion of the string builder with another string. The length of the inserted string does not have to 2705 * match the removed length. 2706 * 2707 * @param startIndex the start index, inclusive, must be valid 2708 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2709 * @param replaceStr the string to replace with, null means delete range 2710 * @return this, to enable chaining 2711 * @throws IndexOutOfBoundsException if the index is invalid 2712 */ 2713 public TextStringBuilder replace(final int startIndex, int endIndex, final String replaceStr) { 2714 endIndex = validateRange(startIndex, endIndex); 2715 final int insertLen = replaceStr == null ? 0 : replaceStr.length(); 2716 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); 2717 return this; 2718 } 2719 2720 /** 2721 * Advanced search and replaces within the builder using a matcher. 2722 * <p> 2723 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2724 * occurrences where the character 'a' is followed by a number. 2725 * </p> 2726 * 2727 * @param matcher the matcher to use to find the deletion, null causes no action 2728 * @param replaceStr the string to replace the match with, null is a delete 2729 * @param startIndex the start index, inclusive, must be valid 2730 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2731 * @param replaceCount the number of times to replace, -1 for replace all 2732 * @return this, to enable chaining 2733 * @throws IndexOutOfBoundsException if start index is invalid 2734 */ 2735 public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex, 2736 int endIndex, final int replaceCount) { 2737 endIndex = validateRange(startIndex, endIndex); 2738 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); 2739 } 2740 2741 /** 2742 * Replaces the search character with the replace character throughout the builder. 2743 * 2744 * @param search the search character 2745 * @param replace the replace character 2746 * @return this, to enable chaining 2747 */ 2748 public TextStringBuilder replaceAll(final char search, final char replace) { 2749 if (search != replace) { 2750 for (int i = 0; i < size; i++) { 2751 if (buffer[i] == search) { 2752 buffer[i] = replace; 2753 } 2754 } 2755 } 2756 return this; 2757 } 2758 2759 /** 2760 * Replaces the search string with the replace string throughout the builder. 2761 * 2762 * @param searchStr the search string, null causes no action to occur 2763 * @param replaceStr the replace string, null is equivalent to an empty string 2764 * @return this, to enable chaining 2765 */ 2766 public TextStringBuilder replaceAll(final String searchStr, final String replaceStr) { 2767 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2768 if (searchLen > 0) { 2769 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2770 int index = indexOf(searchStr, 0); 2771 while (index >= 0) { 2772 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2773 index = indexOf(searchStr, index + replaceLen); 2774 } 2775 } 2776 return this; 2777 } 2778 2779 /** 2780 * Replaces all matches within the builder with the replace string. 2781 * <p> 2782 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all 2783 * occurrences where the character 'a' is followed by a number. 2784 * </p> 2785 * 2786 * @param matcher the matcher to use to find the deletion, null causes no action 2787 * @param replaceStr the replace string, null is equivalent to an empty string 2788 * @return this, to enable chaining 2789 */ 2790 public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) { 2791 return replace(matcher, replaceStr, 0, size, -1); 2792 } 2793 2794 /** 2795 * Replaces the first instance of the search character with the replace character in the builder. 2796 * 2797 * @param search the search character 2798 * @param replace the replace character 2799 * @return this, to enable chaining 2800 */ 2801 public TextStringBuilder replaceFirst(final char search, final char replace) { 2802 if (search != replace) { 2803 for (int i = 0; i < size; i++) { 2804 if (buffer[i] == search) { 2805 buffer[i] = replace; 2806 break; 2807 } 2808 } 2809 } 2810 return this; 2811 } 2812 2813 /** 2814 * Replaces the first instance of the search string with the replace string. 2815 * 2816 * @param searchStr the search string, null causes no action to occur 2817 * @param replaceStr the replace string, null is equivalent to an empty string 2818 * @return this, to enable chaining 2819 */ 2820 public TextStringBuilder replaceFirst(final String searchStr, final String replaceStr) { 2821 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2822 if (searchLen > 0) { 2823 final int index = indexOf(searchStr, 0); 2824 if (index >= 0) { 2825 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2826 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2827 } 2828 } 2829 return this; 2830 } 2831 2832 /** 2833 * Replaces the first match within the builder with the replace string. 2834 * <p> 2835 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where 2836 * the character 'a' is followed by a number. 2837 * </p> 2838 * 2839 * @param matcher the matcher to use to find the deletion, null causes no action 2840 * @param replaceStr the replace string, null is equivalent to an empty string 2841 * @return this, to enable chaining 2842 */ 2843 public TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) { 2844 return replace(matcher, replaceStr, 0, size, 1); 2845 } 2846 2847 /** 2848 * Internal method to delete a range without validation. 2849 * 2850 * @param startIndex the start index, must be valid 2851 * @param endIndex the end index (exclusive), must be valid 2852 * @param removeLen the length to remove (endIndex - startIndex), must be valid 2853 * @param insertStr the string to replace with, null means delete range 2854 * @param insertLen the length of the insert string, must be valid 2855 * @throws IndexOutOfBoundsException if any index is invalid 2856 */ 2857 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, 2858 final int insertLen) { 2859 final int newSize = size - removeLen + insertLen; 2860 if (insertLen != removeLen) { 2861 ensureCapacityInternal(newSize); 2862 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); 2863 size = newSize; 2864 } 2865 if (insertLen > 0) { 2866 insertStr.getChars(0, insertLen, buffer, startIndex); 2867 } 2868 } 2869 2870 /** 2871 * Replaces within the builder using a matcher. 2872 * <p> 2873 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2874 * occurrences where the character 'a' is followed by a number. 2875 * </p> 2876 * 2877 * @param matcher the matcher to use to find the deletion, null causes no action 2878 * @param replaceStr the string to replace the match with, null is a delete 2879 * @param from the start index, must be valid 2880 * @param to the end index (exclusive), must be valid 2881 * @param replaceCount the number of times to replace, -1 for replace all 2882 * @return this, to enable chaining 2883 * @throws IndexOutOfBoundsException if any index is invalid 2884 */ 2885 private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to, 2886 int replaceCount) { 2887 if (matcher == null || size == 0) { 2888 return this; 2889 } 2890 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2891 for (int i = from; i < to && replaceCount != 0; i++) { 2892 final char[] buf = buffer; 2893 final int removeLen = matcher.isMatch(buf, i, from, to); 2894 if (removeLen > 0) { 2895 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); 2896 to = to - removeLen + replaceLen; 2897 i = i + replaceLen - 1; 2898 if (replaceCount > 0) { 2899 replaceCount--; 2900 } 2901 } 2902 } 2903 return this; 2904 } 2905 2906 /** 2907 * Resizes the buffer to at least the size specified. 2908 * 2909 * @param minCapacity the minimum required capacity 2910 * @throws OutOfMemoryError if the {@code minCapacity} is negative 2911 */ 2912 private void resizeBuffer(final int minCapacity) { 2913 // Overflow-conscious code treats the min and new capacity as unsigned. 2914 final int oldCapacity = buffer.length; 2915 int newCapacity = oldCapacity * 2; 2916 if (Integer.compareUnsigned(newCapacity, minCapacity) < 0) { 2917 newCapacity = minCapacity; 2918 } 2919 if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) { 2920 newCapacity = createPositiveCapacity(minCapacity); 2921 } 2922 reallocate(newCapacity); 2923 } 2924 2925 /** 2926 * Reverses the string builder placing each character in the opposite index. 2927 * 2928 * @return this, to enable chaining 2929 */ 2930 public TextStringBuilder reverse() { 2931 if (size == 0) { 2932 return this; 2933 } 2934 2935 final int half = size / 2; 2936 final char[] buf = buffer; 2937 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) { 2938 final char swap = buf[leftIdx]; 2939 buf[leftIdx] = buf[rightIdx]; 2940 buf[rightIdx] = swap; 2941 } 2942 return this; 2943 } 2944 2945 /** 2946 * Extracts the rightmost characters from the string builder without throwing an exception. 2947 * <p> 2948 * This method extracts the right {@code length} characters from the builder. If this many characters are not 2949 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2950 * </p> 2951 * 2952 * @param length the number of characters to extract, negative returns empty string 2953 * @return The new string 2954 */ 2955 public String rightString(final int length) { 2956 if (length <= 0) { 2957 return StringUtils.EMPTY; 2958 } 2959 if (length >= size) { 2960 return new String(buffer, 0, size); 2961 } 2962 return new String(buffer, size - length, length); 2963 } 2964 2965 /** 2966 * Clears and sets this builder to the given value. 2967 * 2968 * @see #charAt(int) 2969 * @see #deleteCharAt(int) 2970 * @param str the new value. 2971 * @return this, to enable chaining 2972 * @since 1.9 2973 */ 2974 public TextStringBuilder set(final CharSequence str) { 2975 clear(); 2976 append(str); 2977 return this; 2978 } 2979 2980 /** 2981 * Sets the character at the specified index. 2982 * 2983 * @see #charAt(int) 2984 * @see #deleteCharAt(int) 2985 * @param index the index to set 2986 * @param ch the new character 2987 * @return this, to enable chaining 2988 * @throws IndexOutOfBoundsException if the index is invalid 2989 */ 2990 public TextStringBuilder setCharAt(final int index, final char ch) { 2991 validateIndex(index); 2992 buffer[index] = ch; 2993 return this; 2994 } 2995 2996 /** 2997 * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero. 2998 * 2999 * @param length the length to set to, must be zero or positive 3000 * @return this, to enable chaining 3001 * @throws IndexOutOfBoundsException if the length is negative 3002 */ 3003 public TextStringBuilder setLength(final int length) { 3004 if (length < 0) { 3005 throw new StringIndexOutOfBoundsException(length); 3006 } 3007 if (length < size) { 3008 size = length; 3009 } else if (length > size) { 3010 ensureCapacityInternal(length); 3011 final int oldEnd = size; 3012 size = length; 3013 Arrays.fill(buffer, oldEnd, length, '\0'); 3014 } 3015 return this; 3016 } 3017 3018 /** 3019 * Sets the text to be appended when {@link #appendNewLine() new line} is called. 3020 * 3021 * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}. 3022 * @return this instance. 3023 */ 3024 public TextStringBuilder setNewLineText(final String newLine) { 3025 this.newLine = newLine; 3026 return this; 3027 } 3028 3029 /** 3030 * Sets the text to be appended when null is added. 3031 * 3032 * @param nullText the null text, null means no append 3033 * @return this, to enable chaining 3034 */ 3035 public TextStringBuilder setNullText(String nullText) { 3036 if (nullText != null && nullText.isEmpty()) { 3037 nullText = null; 3038 } 3039 this.nullText = nullText; 3040 return this; 3041 } 3042 3043 /** 3044 * Gets the length of the string builder. 3045 * <p> 3046 * This method is the same as {@link #length()} and is provided to match the API of Collections. 3047 * </p> 3048 * 3049 * @return The length 3050 */ 3051 public int size() { 3052 return size; 3053 } 3054 3055 /** 3056 * Checks whether this builder starts with the specified string. 3057 * <p> 3058 * Note that this method handles null input quietly, unlike String. 3059 * </p> 3060 * 3061 * @param str the string to search for, null returns false 3062 * @return true if the builder starts with the string 3063 */ 3064 public boolean startsWith(final String str) { 3065 if (str == null) { 3066 return false; 3067 } 3068 final int len = str.length(); 3069 if (len == 0) { 3070 return true; 3071 } 3072 if (len > size) { 3073 return false; 3074 } 3075 for (int i = 0; i < len; i++) { 3076 if (buffer[i] != str.charAt(i)) { 3077 return false; 3078 } 3079 } 3080 return true; 3081 } 3082 3083 /** 3084 * {@inheritDoc} 3085 */ 3086 @Override 3087 public CharSequence subSequence(final int startIndex, final int endIndex) { 3088 if (startIndex < 0) { 3089 throw new StringIndexOutOfBoundsException(startIndex); 3090 } 3091 if (endIndex > size) { 3092 throw new StringIndexOutOfBoundsException(endIndex); 3093 } 3094 if (startIndex > endIndex) { 3095 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 3096 } 3097 return substring(startIndex, endIndex); 3098 } 3099 3100 /** 3101 * Extracts a portion of this string builder as a string. 3102 * 3103 * @param start the start index, inclusive, must be valid 3104 * @return The new string 3105 * @throws IndexOutOfBoundsException if the index is invalid 3106 */ 3107 public String substring(final int start) { 3108 return substring(start, size); 3109 } 3110 3111 /** 3112 * Extracts a portion of this string builder as a string. 3113 * <p> 3114 * Note: This method treats an endIndex greater than the length of the builder as equal to the length of the 3115 * builder, and continues without error, unlike StringBuffer or String. 3116 * </p> 3117 * 3118 * @param startIndex the start index, inclusive, must be valid 3119 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3120 * @return The new string 3121 * @throws IndexOutOfBoundsException if the index is invalid 3122 */ 3123 public String substring(final int startIndex, int endIndex) { 3124 endIndex = validateRange(startIndex, endIndex); 3125 return new String(buffer, startIndex, endIndex - startIndex); 3126 } 3127 3128 /** 3129 * Copies the builder's character array into a new character array. 3130 * 3131 * @return a new array that represents the contents of the builder 3132 */ 3133 public char[] toCharArray() { 3134 return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size); 3135 } 3136 3137 /** 3138 * Copies part of the builder's character array into a new character array. 3139 * 3140 * @param startIndex the start index, inclusive, must be valid 3141 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3142 * @return a new array that holds part of the contents of the builder 3143 * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than 3144 * size is valid) 3145 */ 3146 public char[] toCharArray(final int startIndex, int endIndex) { 3147 endIndex = validateRange(startIndex, endIndex); 3148 final int len = endIndex - startIndex; 3149 return len == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOfRange(buffer, startIndex, endIndex); 3150 } 3151 3152 /** 3153 * Gets a String version of the string builder, creating a new instance each time the method is called. 3154 * <p> 3155 * Note that unlike StringBuffer, the string version returned is independent of the string builder. 3156 * </p> 3157 * 3158 * @return The builder as a String 3159 */ 3160 @Override 3161 public String toString() { 3162 return new String(buffer, 0, size); 3163 } 3164 3165 /** 3166 * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called. 3167 * 3168 * @return The builder as a StringBuffer 3169 */ 3170 public StringBuffer toStringBuffer() { 3171 return new StringBuffer(size).append(buffer, 0, size); 3172 } 3173 3174 /** 3175 * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called. 3176 * 3177 * @return The builder as a StringBuilder 3178 */ 3179 public StringBuilder toStringBuilder() { 3180 return new StringBuilder(size).append(buffer, 0, size); 3181 } 3182 3183 /** 3184 * Trims the builder by removing characters less than or equal to a space from the beginning and end. 3185 * 3186 * @return this, to enable chaining 3187 */ 3188 public TextStringBuilder trim() { 3189 if (size == 0) { 3190 return this; 3191 } 3192 int len = size; 3193 final char[] buf = buffer; 3194 int pos = 0; 3195 while (pos < len && buf[pos] <= SPACE) { 3196 pos++; 3197 } 3198 while (pos < len && buf[len - 1] <= SPACE) { 3199 len--; 3200 } 3201 if (len < size) { 3202 delete(len, size); 3203 } 3204 if (pos > 0) { 3205 delete(0, pos); 3206 } 3207 return this; 3208 } 3209 3210 /** 3211 * Validates that an index is in the range {@code 0 <= index <= size}. 3212 * 3213 * @param index the index to test. 3214 * @throws IndexOutOfBoundsException Thrown when the index is not the range {@code 0 <= index <= size}. 3215 */ 3216 protected void validateIndex(final int index) { 3217 if (index < 0 || index >= size) { 3218 throw new StringIndexOutOfBoundsException(index); 3219 } 3220 } 3221 3222 /** 3223 * Validates parameters defining a range of the builder. 3224 * 3225 * @param startIndex the start index, inclusive, must be valid 3226 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3227 * @return A valid end index. 3228 * @throws StringIndexOutOfBoundsException if the index is invalid 3229 */ 3230 protected int validateRange(final int startIndex, int endIndex) { 3231 if (startIndex < 0) { 3232 throw new StringIndexOutOfBoundsException(startIndex); 3233 } 3234 if (endIndex > size) { 3235 endIndex = size; 3236 } 3237 if (startIndex > endIndex) { 3238 throw new StringIndexOutOfBoundsException("end < start"); 3239 } 3240 return endIndex; 3241 } 3242 3243 }