1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.text; 18 19 import java.io.IOException; 20 import java.io.Reader; 21 import java.io.Serializable; 22 import java.io.Writer; 23 import java.nio.CharBuffer; 24 import java.util.Arrays; 25 import java.util.Iterator; 26 import java.util.List; 27 import java.util.Objects; 28 29 import org.apache.commons.lang3.ArrayUtils; 30 import org.apache.commons.lang3.StringUtils; 31 import org.apache.commons.text.matcher.StringMatcher; 32 33 /** 34 * Builds a string from constituent parts providing a more flexible and powerful API than {@link StringBuffer} and 35 * {@link StringBuilder}. 36 * <p> 37 * The main differences from StringBuffer/StringBuilder are: 38 * </p> 39 * <ul> 40 * <li>Not synchronized</li> 41 * <li>Not final</li> 42 * <li>Subclasses have direct access to character array</li> 43 * <li>Additional methods 44 * <ul> 45 * <li>appendWithSeparators - adds an array of values, with a separator</li> 46 * <li>appendPadding - adds a length padding characters</li> 47 * <li>appendFixedLength - adds a fixed width field to the builder</li> 48 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li> 49 * <li>delete - delete char or string</li> 50 * <li>replace - search and replace for a char or string</li> 51 * <li>leftString/rightString/midString - substring without exceptions</li> 52 * <li>contains - whether the builder contains a char or string</li> 53 * <li>size/clear/isEmpty - collections style API methods</li> 54 * </ul> 55 * </li> 56 * <li>Views 57 * <ul> 58 * <li>asTokenizer - uses the internal buffer as the source of a StrTokenizer</li> 59 * <li>asReader - uses the internal buffer as the source of a Reader</li> 60 * <li>asWriter - allows a Writer to write directly to the internal buffer</li> 61 * </ul> 62 * </li> 63 * </ul> 64 * <p> 65 * The aim has been to provide an API that mimics very closely what StringBuffer provides, but with additional methods. 66 * It should be noted that some edge cases, with invalid indices or null input, have been altered - see individual 67 * methods. The biggest of these changes is that by default, null will not output the text 'null'. This can be 68 * controlled by a property, {@link #setNullText(String)}. 69 * </p> 70 * <p> 71 * This class is called {@code TextStringBuilder} instead of {@code StringBuilder} to avoid clashing with 72 * {@link StringBuilder}. 73 * </p> 74 * 75 * @since 1.3 76 */ 77 public class TextStringBuilder implements CharSequence, Appendable, Serializable, Builder<String> { 78 79 /** 80 * Inner class to allow StrBuilder to operate as a reader. 81 */ 82 final class TextStringBuilderReader extends Reader { 83 84 /** The last mark position. */ 85 private int mark; 86 87 /** The current stream position. */ 88 private int pos; 89 90 /** 91 * Default constructor. 92 */ 93 TextStringBuilderReader() { 94 } 95 96 /** {@inheritDoc} */ 97 @Override 98 public void close() { 99 // do nothing 100 } 101 102 /** {@inheritDoc} */ 103 @Override 104 public void mark(final int readAheadLimit) { 105 mark = pos; 106 } 107 108 /** {@inheritDoc} */ 109 @Override 110 public boolean markSupported() { 111 return true; 112 } 113 114 /** {@inheritDoc} */ 115 @Override 116 public int read() { 117 if (!ready()) { 118 return -1; 119 } 120 return charAt(pos++); 121 } 122 123 /** {@inheritDoc} */ 124 @Override 125 public int read(final char[] b, final int off, int len) { 126 if (off < 0 || len < 0 || off > b.length || off + len > b.length || off + len < 0) { 127 throw new IndexOutOfBoundsException(); 128 } 129 if (len == 0) { 130 return 0; 131 } 132 if (pos >= size()) { 133 return -1; 134 } 135 if (pos + len > size()) { 136 len = size() - pos; 137 } 138 TextStringBuilder.this.getChars(pos, pos + len, b, off); 139 pos += len; 140 return len; 141 } 142 143 /** {@inheritDoc} */ 144 @Override 145 public boolean ready() { 146 return pos < size(); 147 } 148 149 /** {@inheritDoc} */ 150 @Override 151 public void reset() { 152 pos = mark; 153 } 154 155 /** {@inheritDoc} */ 156 @Override 157 public long skip(long n) { 158 if (pos + n > size()) { 159 n = size() - pos; 160 } 161 if (n < 0) { 162 return 0; 163 } 164 pos = Math.addExact(pos, Math.toIntExact(n)); 165 return n; 166 } 167 } 168 169 /** 170 * Inner class to allow StrBuilder to operate as a tokenizer. 171 */ 172 final class TextStringBuilderTokenizer extends StringTokenizer { 173 174 /** 175 * Default constructor. 176 */ 177 TextStringBuilderTokenizer() { 178 } 179 180 /** {@inheritDoc} */ 181 @Override 182 public String getContent() { 183 final String str = super.getContent(); 184 if (str == null) { 185 return TextStringBuilder.this.toString(); 186 } 187 return str; 188 } 189 190 /** {@inheritDoc} */ 191 @Override 192 protected List<String> tokenize(final char[] chars, final int offset, final int count) { 193 if (chars == null) { 194 return super.tokenize(getBuffer(), 0, TextStringBuilder.this.size()); 195 } 196 return super.tokenize(chars, offset, count); 197 } 198 } 199 200 /** 201 * Inner class to allow StrBuilder to operate as a writer. 202 */ 203 final class TextStringBuilderWriter extends Writer { 204 205 /** 206 * Default constructor. 207 */ 208 TextStringBuilderWriter() { 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 public void close() { 214 // do nothing 215 } 216 217 /** {@inheritDoc} */ 218 @Override 219 public void flush() { 220 // do nothing 221 } 222 223 /** {@inheritDoc} */ 224 @Override 225 public void write(final char[] cbuf) { 226 TextStringBuilder.this.append(cbuf); 227 } 228 229 /** {@inheritDoc} */ 230 @Override 231 public void write(final char[] cbuf, final int off, final int len) { 232 TextStringBuilder.this.append(cbuf, off, len); 233 } 234 235 /** {@inheritDoc} */ 236 @Override 237 public void write(final int c) { 238 TextStringBuilder.this.append((char) c); 239 } 240 241 /** {@inheritDoc} */ 242 @Override 243 public void write(final String str) { 244 TextStringBuilder.this.append(str); 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 public void write(final String str, final int off, final int len) { 250 TextStringBuilder.this.append(str, off, len); 251 } 252 } 253 254 /** The space character. */ 255 private static final char SPACE = ' '; 256 257 /** 258 * The extra capacity for new builders. 259 */ 260 static final int CAPACITY = 32; 261 262 /** 263 * End-Of-Stream. 264 */ 265 private static final int EOS = -1; 266 267 /** 268 * The size of the string {@code "false"}. 269 */ 270 private static final int FALSE_STRING_SIZE = Boolean.FALSE.toString().length(); 271 272 /** 273 * Required for serialization support. 274 * 275 * @see java.io.Serializable 276 */ 277 private static final long serialVersionUID = 1L; 278 279 /** 280 * The size of the string {@code "true"}. 281 */ 282 private static final int TRUE_STRING_SIZE = Boolean.TRUE.toString().length(); 283 284 /** 285 * The maximum size buffer to allocate. 286 * 287 * <p>This is set to the same size used in the JDK {@link java.util.ArrayList}:</p> 288 * <blockquote> 289 * Some VMs reserve some header words in an array. 290 * Attempts to allocate larger arrays may result in 291 * OutOfMemoryError: Requested array size exceeds VM limit. 292 * </blockquote> 293 */ 294 private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; 295 296 /** 297 * Creates a positive capacity at least as large the minimum required capacity. 298 * If the minimum capacity is negative then this throws an OutOfMemoryError as no array 299 * can be allocated. 300 * 301 * @param minCapacity the minimum capacity 302 * @return the capacity 303 * @throws OutOfMemoryError if the {@code minCapacity} is negative 304 */ 305 private static int createPositiveCapacity(final int minCapacity) { 306 if (minCapacity < 0) { 307 // overflow 308 throw new OutOfMemoryError("Unable to allocate array size: " + Integer.toUnsignedString(minCapacity)); 309 } 310 // This is called when we require buffer expansion to a very big array. 311 // Use the conservative maximum buffer size if possible, otherwise the biggest required. 312 // 313 // Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE. 314 // This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full 315 // Integer.MAX_VALUE length array. 316 // The result is that we may have to allocate an array of this size more than once if 317 // the capacity must be expanded again. 318 return Math.max(minCapacity, MAX_BUFFER_SIZE); 319 } 320 321 /** 322 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this 323 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to 324 * be initialized without copying the input array. 325 * 326 * @param initialBuffer The initial array that will back the new builder. 327 * @return A new instance. 328 * @since 1.9 329 */ 330 public static TextStringBuilder wrap(final char[] initialBuffer) { 331 Objects.requireNonNull(initialBuffer, "initialBuffer"); 332 return new TextStringBuilder(initialBuffer, initialBuffer.length); 333 } 334 335 /** 336 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this 337 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to 338 * be initialized without copying the input array. 339 * 340 * @param initialBuffer The initial array that will back the new builder. 341 * @param length The length of the subarray to be used; must be non-negative and no larger than 342 * {@code initialBuffer.length}. The new builder's size will be set to {@code length}. 343 * @return A new instance. 344 * @since 1.9 345 */ 346 public static TextStringBuilder wrap(final char[] initialBuffer, final int length) { 347 return new TextStringBuilder(initialBuffer, length); 348 } 349 350 /** Internal data storage. */ 351 private char[] buffer; 352 353 /** 354 * The new line, {@code null} means use the system default from {@link System#lineSeparator()}. 355 */ 356 private String newLine; 357 358 /** The null text. */ 359 private String nullText; 360 361 /** Incremented when the buffer is reallocated. */ 362 private int reallocations; 363 364 /** Current size of the buffer. */ 365 private int size; 366 367 /** 368 * Constructs an empty builder with an initial capacity of 32 characters. 369 */ 370 public TextStringBuilder() { 371 this(CAPACITY); 372 } 373 374 /** 375 * Constructs an instance from a reference to a character array. 376 * 377 * @param initialBuffer a reference to a character array, must not be null. 378 * @param length The length of the subarray to be used; must be non-negative and no larger than 379 * {@code initialBuffer.length}. The new builder's size will be set to {@code length}. 380 * @throws NullPointerException If {@code initialBuffer} is null. 381 * @throws IllegalArgumentException if {@code length} is bad. 382 */ 383 private TextStringBuilder(final char[] initialBuffer, final int length) { 384 this.buffer = Objects.requireNonNull(initialBuffer, "initialBuffer"); 385 if (length < 0 || length > initialBuffer.length) { 386 throw new IllegalArgumentException("initialBuffer.length=" + initialBuffer.length + ", length=" + length); 387 } 388 this.size = length; 389 } 390 391 /** 392 * Constructs an instance from a character sequence, allocating 32 extra characters for growth. 393 * 394 * @param seq the string to copy, null treated as blank string 395 * @since 1.9 396 */ 397 public TextStringBuilder(final CharSequence seq) { 398 this(StringUtils.length(seq) + CAPACITY); 399 if (seq != null) { 400 append(seq); 401 } 402 } 403 404 /** 405 * Constructs an instance with the specified initial capacity. 406 * 407 * @param initialCapacity the initial capacity, zero or less will be converted to 32 408 */ 409 public TextStringBuilder(final int initialCapacity) { 410 buffer = new char[initialCapacity <= 0 ? CAPACITY : initialCapacity]; 411 } 412 413 /** 414 * Constructs an instance from a string, allocating 32 extra characters for growth. 415 * 416 * @param str the string to copy, null treated as blank string 417 */ 418 public TextStringBuilder(final String str) { 419 this(StringUtils.length(str) + CAPACITY); 420 if (str != null) { 421 append(str); 422 } 423 } 424 425 /** 426 * Appends a boolean value to the string builder. 427 * 428 * @param value the value to append 429 * @return this, to enable chaining 430 */ 431 public TextStringBuilder append(final boolean value) { 432 if (value) { 433 ensureCapacityInternal(size + TRUE_STRING_SIZE); 434 appendTrue(size); 435 } else { 436 ensureCapacityInternal(size + FALSE_STRING_SIZE); 437 appendFalse(size); 438 } 439 return this; 440 } 441 442 /** 443 * Appends a char value to the string builder. 444 * 445 * @param ch the value to append 446 * @return this, to enable chaining 447 */ 448 @Override 449 public TextStringBuilder append(final char ch) { 450 final int len = length(); 451 ensureCapacityInternal(len + 1); 452 buffer[size++] = ch; 453 return this; 454 } 455 456 /** 457 * Appends a char array to the string builder. Appending null will call {@link #appendNull()}. 458 * 459 * @param chars the char array to append 460 * @return this, to enable chaining 461 */ 462 public TextStringBuilder append(final char[] chars) { 463 if (chars == null) { 464 return appendNull(); 465 } 466 final int strLen = chars.length; 467 if (strLen > 0) { 468 final int len = length(); 469 ensureCapacityInternal(len + strLen); 470 System.arraycopy(chars, 0, buffer, len, strLen); 471 size += strLen; 472 } 473 return this; 474 } 475 476 /** 477 * Appends a char array to the string builder. Appending null will call {@link #appendNull()}. 478 * 479 * @param chars the char array to append 480 * @param startIndex the start index, inclusive, must be valid 481 * @param length the length to append, must be valid 482 * @return this, to enable chaining 483 * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the 484 * range {@code 0 <= startIndex <= chars.length} 485 * @throws StringIndexOutOfBoundsException if {@code length < 0} 486 * @throws StringIndexOutOfBoundsException if {@code startIndex + length > chars.length} 487 */ 488 public TextStringBuilder append(final char[] chars, final int startIndex, final int length) { 489 if (chars == null) { 490 return appendNull(); 491 } 492 if (startIndex < 0 || startIndex > chars.length) { 493 throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length); 494 } 495 if (length < 0 || startIndex + length > chars.length) { 496 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 497 } 498 if (length > 0) { 499 final int len = length(); 500 ensureCapacityInternal(len + length); 501 System.arraycopy(chars, startIndex, buffer, len, length); 502 size += length; 503 } 504 return this; 505 } 506 507 /** 508 * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}. 509 * 510 * @param str the char buffer to append 511 * @return this, to enable chaining 512 */ 513 public TextStringBuilder append(final CharBuffer str) { 514 return append(str, 0, StringUtils.length(str)); 515 } 516 517 /** 518 * Appends the contents of a char buffer to this string builder. Appending null will call {@link #appendNull()}. 519 * 520 * @param buf the char buffer to append 521 * @param startIndex the start index, inclusive, must be valid 522 * @param length the length to append, must be valid 523 * @return this, to enable chaining 524 */ 525 public TextStringBuilder append(final CharBuffer buf, final int startIndex, final int length) { 526 if (buf == null) { 527 return appendNull(); 528 } 529 if (buf.hasArray()) { 530 final int totalLength = buf.remaining(); 531 if (startIndex < 0 || startIndex > totalLength) { 532 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 533 } 534 if (length < 0 || startIndex + length > totalLength) { 535 throw new StringIndexOutOfBoundsException("length must be valid"); 536 } 537 final int len = length(); 538 ensureCapacityInternal(len + length); 539 System.arraycopy(buf.array(), buf.arrayOffset() + buf.position() + startIndex, buffer, len, length); 540 size += length; 541 } else { 542 append(buf.toString(), startIndex, length); 543 } 544 return this; 545 } 546 547 /** 548 * Appends a CharSequence to this string builder. Appending null will call {@link #appendNull()}. 549 * 550 * @param seq the CharSequence to append 551 * @return this, to enable chaining 552 */ 553 @Override 554 public TextStringBuilder append(final CharSequence seq) { 555 if (seq == null) { 556 return appendNull(); 557 } 558 if (seq instanceof TextStringBuilder) { 559 return append((TextStringBuilder) seq); 560 } 561 if (seq instanceof StringBuilder) { 562 return append((StringBuilder) seq); 563 } 564 if (seq instanceof StringBuffer) { 565 return append((StringBuffer) seq); 566 } 567 if (seq instanceof CharBuffer) { 568 return append((CharBuffer) seq); 569 } 570 return append(seq.toString()); 571 } 572 573 /** 574 * Appends part of a CharSequence to this string builder. Appending null will call {@link #appendNull()}. 575 * 576 * @param seq the CharSequence to append 577 * @param startIndex the start index, inclusive, must be valid 578 * @param endIndex the end index, exclusive, must be valid 579 * @return this, to enable chaining 580 */ 581 @Override 582 public TextStringBuilder append(final CharSequence seq, final int startIndex, final int endIndex) { 583 if (seq == null) { 584 return appendNull(); 585 } 586 if (endIndex <= 0) { 587 throw new StringIndexOutOfBoundsException("endIndex must be valid"); 588 } 589 if (startIndex >= endIndex) { 590 throw new StringIndexOutOfBoundsException("endIndex must be greater than startIndex"); 591 } 592 return append(seq.toString(), startIndex, endIndex - startIndex); 593 } 594 595 /** 596 * Appends a double value to the string builder using {@code String.valueOf}. 597 * 598 * @param value the value to append 599 * @return this, to enable chaining 600 */ 601 public TextStringBuilder append(final double value) { 602 return append(String.valueOf(value)); 603 } 604 605 /** 606 * Appends a float value to the string builder using {@code String.valueOf}. 607 * 608 * @param value the value to append 609 * @return this, to enable chaining 610 */ 611 public TextStringBuilder append(final float value) { 612 return append(String.valueOf(value)); 613 } 614 615 /** 616 * Appends an int value to the string builder using {@code String.valueOf}. 617 * 618 * @param value the value to append 619 * @return this, to enable chaining 620 */ 621 public TextStringBuilder append(final int value) { 622 return append(String.valueOf(value)); 623 } 624 625 /** 626 * Appends a long value to the string builder using {@code String.valueOf}. 627 * 628 * @param value the value to append 629 * @return this, to enable chaining 630 */ 631 public TextStringBuilder append(final long value) { 632 return append(String.valueOf(value)); 633 } 634 635 /** 636 * Appends an object to this string builder. Appending null will call {@link #appendNull()}. 637 * 638 * @param obj the object to append 639 * @return this, to enable chaining 640 */ 641 public TextStringBuilder append(final Object obj) { 642 if (obj == null) { 643 return appendNull(); 644 } 645 if (obj instanceof CharSequence) { 646 return append((CharSequence) obj); 647 } 648 return append(obj.toString()); 649 } 650 651 /** 652 * Appends a string to this string builder. Appending null will call {@link #appendNull()}. 653 * 654 * @param str the string to append 655 * @return this, to enable chaining 656 */ 657 public TextStringBuilder append(final String str) { 658 return append(str, 0, StringUtils.length(str)); 659 } 660 661 /** 662 * Appends part of a string to this string builder. Appending null will call {@link #appendNull()}. 663 * 664 * @param str the string to append 665 * @param startIndex the start index, inclusive, must be valid 666 * @param length the length to append, must be valid 667 * @return this, to enable chaining 668 * @throws StringIndexOutOfBoundsException if {@code startIndex} is not in the 669 * range {@code 0 <= startIndex <= str.length()} 670 * @throws StringIndexOutOfBoundsException if {@code length < 0} 671 * @throws StringIndexOutOfBoundsException if {@code startIndex + length > str.length()} 672 */ 673 public TextStringBuilder append(final String str, final int startIndex, final int length) { 674 if (str == null) { 675 return appendNull(); 676 } 677 if (startIndex < 0 || startIndex > str.length()) { 678 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 679 } 680 if (length < 0 || startIndex + length > str.length()) { 681 throw new StringIndexOutOfBoundsException("length must be valid"); 682 } 683 if (length > 0) { 684 final int len = length(); 685 ensureCapacityInternal(len + length); 686 str.getChars(startIndex, startIndex + length, buffer, len); 687 size += length; 688 } 689 return this; 690 } 691 692 /** 693 * Calls {@link String#format(String, Object...)} and appends the result. 694 * 695 * @param format the format string 696 * @param objs the objects to use in the format string 697 * @return {@code this} to enable chaining 698 * @see String#format(String, Object...) 699 */ 700 public TextStringBuilder append(final String format, final Object... objs) { 701 return append(String.format(format, objs)); 702 } 703 704 /** 705 * Appends a string buffer to this string builder. Appending null will call {@link #appendNull()}. 706 * 707 * @param str the string buffer to append 708 * @return this, to enable chaining 709 */ 710 public TextStringBuilder append(final StringBuffer str) { 711 return append(str, 0, StringUtils.length(str)); 712 } 713 714 /** 715 * Appends part of a string buffer to this string builder. Appending null will call {@link #appendNull()}. 716 * 717 * @param str the string to append 718 * @param startIndex the start index, inclusive, must be valid 719 * @param length the length to append, must be valid 720 * @return this, to enable chaining 721 */ 722 public TextStringBuilder append(final StringBuffer str, final int startIndex, final int length) { 723 if (str == null) { 724 return appendNull(); 725 } 726 if (startIndex < 0 || startIndex > str.length()) { 727 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 728 } 729 if (length < 0 || startIndex + length > str.length()) { 730 throw new StringIndexOutOfBoundsException("length must be valid"); 731 } 732 if (length > 0) { 733 final int len = length(); 734 ensureCapacityInternal(len + length); 735 str.getChars(startIndex, startIndex + length, buffer, len); 736 size += length; 737 } 738 return this; 739 } 740 741 /** 742 * Appends a StringBuilder to this string builder. Appending null will call {@link #appendNull()}. 743 * 744 * @param str the StringBuilder to append 745 * @return this, to enable chaining 746 */ 747 public TextStringBuilder append(final StringBuilder str) { 748 return append(str, 0, StringUtils.length(str)); 749 } 750 751 /** 752 * Appends part of a StringBuilder to this string builder. Appending null will call {@link #appendNull()}. 753 * 754 * @param str the StringBuilder to append 755 * @param startIndex the start index, inclusive, must be valid 756 * @param length the length to append, must be valid 757 * @return this, to enable chaining 758 */ 759 public TextStringBuilder append(final StringBuilder str, final int startIndex, final int length) { 760 if (str == null) { 761 return appendNull(); 762 } 763 if (startIndex < 0 || startIndex > str.length()) { 764 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 765 } 766 if (length < 0 || startIndex + length > str.length()) { 767 throw new StringIndexOutOfBoundsException("length must be valid"); 768 } 769 if (length > 0) { 770 final int len = length(); 771 ensureCapacityInternal(len + length); 772 str.getChars(startIndex, startIndex + length, buffer, len); 773 size += length; 774 } 775 return this; 776 } 777 778 /** 779 * Appends another string builder to this string builder. Appending null will call {@link #appendNull()}. 780 * 781 * @param str the string builder to append 782 * @return this, to enable chaining 783 */ 784 public TextStringBuilder append(final TextStringBuilder str) { 785 return append(str, 0, StringUtils.length(str)); 786 } 787 788 /** 789 * Appends part of a string builder to this string builder. Appending null will call {@link #appendNull()}. 790 * 791 * @param str the string to append 792 * @param startIndex the start index, inclusive, must be valid 793 * @param length the length to append, must be valid 794 * @return this, to enable chaining 795 */ 796 public TextStringBuilder append(final TextStringBuilder str, final int startIndex, final int length) { 797 if (str == null) { 798 return appendNull(); 799 } 800 if (startIndex < 0 || startIndex > str.length()) { 801 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 802 } 803 if (length < 0 || startIndex + length > str.length()) { 804 throw new StringIndexOutOfBoundsException("length must be valid"); 805 } 806 if (length > 0) { 807 final int len = length(); 808 ensureCapacityInternal(len + length); 809 str.getChars(startIndex, startIndex + length, buffer, len); 810 size += length; 811 } 812 return this; 813 } 814 815 /** 816 * Appends each item in an iterable to the builder without any separators. Appending a null iterable will have no 817 * effect. Each object is appended using {@link #append(Object)}. 818 * 819 * @param iterable the iterable to append 820 * @return this, to enable chaining 821 */ 822 public TextStringBuilder appendAll(final Iterable<?> iterable) { 823 if (iterable != null) { 824 iterable.forEach(this::append); 825 } 826 return this; 827 } 828 829 /** 830 * Appends each item in an iterator to the builder without any separators. Appending a null iterator will have no 831 * effect. Each object is appended using {@link #append(Object)}. 832 * 833 * @param it the iterator to append 834 * @return this, to enable chaining 835 */ 836 public TextStringBuilder appendAll(final Iterator<?> it) { 837 if (it != null) { 838 it.forEachRemaining(this::append); 839 } 840 return this; 841 } 842 843 /** 844 * Appends each item in an array to the builder without any separators. Appending a null array will have no effect. 845 * Each object is appended using {@link #append(Object)}. 846 * 847 * @param <T> the element type 848 * @param array the array to append 849 * @return this, to enable chaining 850 */ 851 public <T> TextStringBuilder appendAll(@SuppressWarnings("unchecked") final T... array) { 852 /* 853 * @SuppressWarnings used to hide warning about vararg usage. We cannot use @SafeVarargs, since this method is 854 * not final. Using @SuppressWarnings is fine, because it isn't inherited by subclasses, so each subclass must 855 * vouch for itself whether its use of 'array' is safe. 856 */ 857 if (array != null && array.length > 0) { 858 for (final Object element : array) { 859 append(element); 860 } 861 } 862 return this; 863 } 864 865 /** Appends {@code "false"}. */ 866 private void appendFalse(int index) { 867 buffer[index++] = 'f'; 868 buffer[index++] = 'a'; 869 buffer[index++] = 'l'; 870 buffer[index++] = 's'; 871 buffer[index] = 'e'; 872 size += FALSE_STRING_SIZE; 873 } 874 875 /** 876 * Appends an object to the builder padding on the left to a fixed width. The {@code String.valueOf} of the 877 * {@code int} value is used. If the formatted value is larger than the length, the left hand side is lost. 878 * 879 * @param value the value to append 880 * @param width the fixed field width, zero or negative has no effect 881 * @param padChar the pad character to use 882 * @return this, to enable chaining 883 */ 884 public TextStringBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) { 885 return appendFixedWidthPadLeft(String.valueOf(value), width, padChar); 886 } 887 888 /** 889 * Appends an object to the builder padding on the left to a fixed width. The {@code toString} of the object is 890 * used. If the object is larger than the length, the left hand side is lost. If the object is null, the null text 891 * value is used. 892 * 893 * @param obj the object to append, null uses null text 894 * @param width the fixed field width, zero or negative has no effect 895 * @param padChar the pad character to use 896 * @return this, to enable chaining 897 */ 898 public TextStringBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) { 899 if (width > 0) { 900 ensureCapacityInternal(size + width); 901 String str = Objects.toString(obj, getNullText()); 902 if (str == null) { 903 str = StringUtils.EMPTY; 904 } 905 final int strLen = str.length(); 906 if (strLen >= width) { 907 str.getChars(strLen - width, strLen, buffer, size); 908 } else { 909 final int padLen = width - strLen; 910 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 len = size - strLen + 1; 2132 outer: for (int i = startIndex; i < len; i++) { 2133 for (int j = 0; j < strLen; j++) { 2134 if (str.charAt(j) != thisBuf[i + j]) { 2135 continue outer; 2136 } 2137 } 2138 return i; 2139 } 2140 return StringUtils.INDEX_NOT_FOUND; 2141 } 2142 2143 /** 2144 * Searches the string builder using the matcher to find the first match. 2145 * <p> 2146 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2147 * character 'a' followed by a number. 2148 * </p> 2149 * 2150 * @param matcher the matcher to use, null returns -1 2151 * @return The first index matched, or -1 if not found 2152 */ 2153 public int indexOf(final StringMatcher matcher) { 2154 return indexOf(matcher, 0); 2155 } 2156 2157 /** 2158 * Searches the string builder using the matcher to find the first match searching from the given index. 2159 * <p> 2160 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2161 * character 'a' followed by a number. 2162 * </p> 2163 * 2164 * @param matcher the matcher to use, null returns -1 2165 * @param startIndex the index to start at, invalid index rounded to edge 2166 * @return The first index matched, or -1 if not found 2167 */ 2168 public int indexOf(final StringMatcher matcher, int startIndex) { 2169 startIndex = Math.max(0, startIndex); 2170 if (matcher == null || startIndex >= size) { 2171 return StringUtils.INDEX_NOT_FOUND; 2172 } 2173 final int len = size; 2174 final char[] buf = buffer; 2175 for (int i = startIndex; i < len; i++) { 2176 if (matcher.isMatch(buf, i, startIndex, len) > 0) { 2177 return i; 2178 } 2179 } 2180 return StringUtils.INDEX_NOT_FOUND; 2181 } 2182 2183 /** 2184 * Inserts the value into this builder. 2185 * 2186 * @param index the index to add at, must be valid 2187 * @param value the value to insert 2188 * @return this, to enable chaining 2189 * @throws IndexOutOfBoundsException if the index is invalid 2190 */ 2191 public TextStringBuilder insert(final int index, final boolean value) { 2192 validateIndex(index); 2193 if (value) { 2194 ensureCapacityInternal(size + TRUE_STRING_SIZE); 2195 System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index); 2196 appendTrue(index); 2197 } else { 2198 ensureCapacityInternal(size + FALSE_STRING_SIZE); 2199 System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index); 2200 appendFalse(index); 2201 } 2202 return this; 2203 } 2204 2205 /** 2206 * Inserts the value into this builder. 2207 * 2208 * @param index the index to add at, must be valid 2209 * @param value the value to insert 2210 * @return this, to enable chaining 2211 * @throws IndexOutOfBoundsException if the index is invalid 2212 */ 2213 public TextStringBuilder insert(final int index, final char value) { 2214 validateIndex(index); 2215 ensureCapacityInternal(size + 1); 2216 System.arraycopy(buffer, index, buffer, index + 1, size - index); 2217 buffer[index] = value; 2218 size++; 2219 return this; 2220 } 2221 2222 /** 2223 * Inserts the character array into this builder. Inserting null will use the stored null text value. 2224 * 2225 * @param index the index to add at, must be valid 2226 * @param chars the char array to insert 2227 * @return this, to enable chaining 2228 * @throws IndexOutOfBoundsException if the index is invalid 2229 */ 2230 public TextStringBuilder insert(final int index, final char[] chars) { 2231 validateIndex(index); 2232 if (chars == null) { 2233 return insert(index, nullText); 2234 } 2235 final int len = chars.length; 2236 if (len > 0) { 2237 ensureCapacityInternal(size + len); 2238 System.arraycopy(buffer, index, buffer, index + len, size - index); 2239 System.arraycopy(chars, 0, buffer, index, len); 2240 size += len; 2241 } 2242 return this; 2243 } 2244 2245 /** 2246 * Inserts part of the character array into this builder. Inserting null will use the stored null text value. 2247 * 2248 * @param index the index to add at, must be valid 2249 * @param chars the char array to insert 2250 * @param offset the offset into the character array to start at, must be valid 2251 * @param length the length of the character array part to copy, must be positive 2252 * @return this, to enable chaining 2253 * @throws IndexOutOfBoundsException if any index is invalid 2254 */ 2255 public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) { 2256 validateIndex(index); 2257 if (chars == null) { 2258 return insert(index, nullText); 2259 } 2260 if (offset < 0 || offset > chars.length) { 2261 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); 2262 } 2263 if (length < 0 || offset + length > chars.length) { 2264 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 2265 } 2266 if (length > 0) { 2267 ensureCapacityInternal(size + length); 2268 System.arraycopy(buffer, index, buffer, index + length, size - index); 2269 System.arraycopy(chars, offset, buffer, index, length); 2270 size += length; 2271 } 2272 return this; 2273 } 2274 2275 /** 2276 * Inserts the value into this builder. 2277 * 2278 * @param index the index to add at, must be valid 2279 * @param value the value to insert 2280 * @return this, to enable chaining 2281 * @throws IndexOutOfBoundsException if the index is invalid 2282 */ 2283 public TextStringBuilder insert(final int index, final double value) { 2284 return insert(index, String.valueOf(value)); 2285 } 2286 2287 /** 2288 * Inserts the value into this builder. 2289 * 2290 * @param index the index to add at, must be valid 2291 * @param value the value to insert 2292 * @return this, to enable chaining 2293 * @throws IndexOutOfBoundsException if the index is invalid 2294 */ 2295 public TextStringBuilder insert(final int index, final float value) { 2296 return insert(index, String.valueOf(value)); 2297 } 2298 2299 /** 2300 * Inserts the value into this builder. 2301 * 2302 * @param index the index to add at, must be valid 2303 * @param value the value to insert 2304 * @return this, to enable chaining 2305 * @throws IndexOutOfBoundsException if the index is invalid 2306 */ 2307 public TextStringBuilder insert(final int index, final int value) { 2308 return insert(index, String.valueOf(value)); 2309 } 2310 2311 /** 2312 * Inserts the value into this builder. 2313 * 2314 * @param index the index to add at, must be valid 2315 * @param value the value to insert 2316 * @return this, to enable chaining 2317 * @throws IndexOutOfBoundsException if the index is invalid 2318 */ 2319 public TextStringBuilder insert(final int index, final long value) { 2320 return insert(index, String.valueOf(value)); 2321 } 2322 2323 /** 2324 * Inserts the string representation of an object into this builder. Inserting null will use the stored null text 2325 * value. 2326 * 2327 * @param index the index to add at, must be valid 2328 * @param obj the object to insert 2329 * @return this, to enable chaining 2330 * @throws IndexOutOfBoundsException if the index is invalid 2331 */ 2332 public TextStringBuilder insert(final int index, final Object obj) { 2333 if (obj == null) { 2334 return insert(index, nullText); 2335 } 2336 return insert(index, obj.toString()); 2337 } 2338 2339 /** 2340 * Inserts the string into this builder. Inserting null will use the stored null text value. 2341 * 2342 * @param index the index to add at, must be valid 2343 * @param str the string to insert 2344 * @return this, to enable chaining 2345 * @throws IndexOutOfBoundsException if the index is invalid 2346 */ 2347 public TextStringBuilder insert(final int index, String str) { 2348 validateIndex(index); 2349 if (str == null) { 2350 str = nullText; 2351 } 2352 if (str != null) { 2353 final int strLen = str.length(); 2354 if (strLen > 0) { 2355 final int newSize = size + strLen; 2356 ensureCapacityInternal(newSize); 2357 System.arraycopy(buffer, index, buffer, index + strLen, size - index); 2358 size = newSize; 2359 str.getChars(0, strLen, buffer, index); 2360 } 2361 } 2362 return this; 2363 } 2364 2365 /** 2366 * Checks is the string builder is empty (convenience Collections API style method). 2367 * <p> 2368 * This method is the same as checking {@link #length()} and is provided to match the API of Collections. 2369 * </p> 2370 * 2371 * @return {@code true} if the size is {@code 0}. 2372 */ 2373 public boolean isEmpty() { 2374 return size == 0; 2375 } 2376 2377 /** 2378 * Checks is the string builder is not empty. 2379 * <p> 2380 * This method is the same as checking {@link #length()}. 2381 * </p> 2382 * 2383 * @return {@code true} if the size is not {@code 0}. 2384 * @since 1.9 2385 */ 2386 public boolean isNotEmpty() { 2387 return size != 0; 2388 } 2389 2390 /** 2391 * Gets whether the internal buffer has been reallocated. 2392 * 2393 * @return Whether the internal buffer has been reallocated. 2394 * @since 1.9 2395 */ 2396 public boolean isReallocated() { 2397 return reallocations > 0; 2398 } 2399 2400 /** 2401 * Searches the string builder to find the last reference to the specified char. 2402 * 2403 * @param ch the character to find 2404 * @return The last index of the character, or -1 if not found 2405 */ 2406 public int lastIndexOf(final char ch) { 2407 return lastIndexOf(ch, size - 1); 2408 } 2409 2410 /** 2411 * Searches the string builder to find the last reference to the specified char. 2412 * 2413 * @param ch the character to find 2414 * @param startIndex the index to start at, invalid index rounded to edge 2415 * @return The last index of the character, or -1 if not found 2416 */ 2417 public int lastIndexOf(final char ch, int startIndex) { 2418 startIndex = startIndex >= size ? size - 1 : startIndex; 2419 if (startIndex < 0) { 2420 return StringUtils.INDEX_NOT_FOUND; 2421 } 2422 for (int i = startIndex; i >= 0; i--) { 2423 if (buffer[i] == ch) { 2424 return i; 2425 } 2426 } 2427 return StringUtils.INDEX_NOT_FOUND; 2428 } 2429 2430 /** 2431 * Searches the string builder to find the last reference to the specified string. 2432 * <p> 2433 * Note that a null input string will return -1, whereas the JDK throws an exception. 2434 * </p> 2435 * 2436 * @param str the string to find, null returns -1 2437 * @return The last index of the string, or -1 if not found 2438 */ 2439 public int lastIndexOf(final String str) { 2440 return lastIndexOf(str, size - 1); 2441 } 2442 2443 /** 2444 * Searches the string builder to find the last reference to the specified string starting searching from the given 2445 * index. 2446 * <p> 2447 * Note that a null input string will return -1, whereas the JDK throws an exception. 2448 * </p> 2449 * 2450 * @param str the string to find, null returns -1 2451 * @param startIndex the index to start at, invalid index rounded to edge 2452 * @return The last index of the string, or -1 if not found 2453 */ 2454 public int lastIndexOf(final String str, int startIndex) { 2455 startIndex = startIndex >= size ? size - 1 : startIndex; 2456 if (str == null || startIndex < 0) { 2457 return StringUtils.INDEX_NOT_FOUND; 2458 } 2459 final int strLen = str.length(); 2460 if (strLen > 0 && strLen <= size) { 2461 if (strLen == 1) { 2462 return lastIndexOf(str.charAt(0), startIndex); 2463 } 2464 2465 outer: for (int i = startIndex - strLen + 1; i >= 0; i--) { 2466 for (int j = 0; j < strLen; j++) { 2467 if (str.charAt(j) != buffer[i + j]) { 2468 continue outer; 2469 } 2470 } 2471 return i; 2472 } 2473 2474 } else if (strLen == 0) { 2475 return startIndex; 2476 } 2477 return StringUtils.INDEX_NOT_FOUND; 2478 } 2479 2480 /** 2481 * Searches the string builder using the matcher to find the last match. 2482 * <p> 2483 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2484 * character 'a' followed by a number. 2485 * </p> 2486 * 2487 * @param matcher the matcher to use, null returns -1 2488 * @return The last index matched, or -1 if not found 2489 */ 2490 public int lastIndexOf(final StringMatcher matcher) { 2491 return lastIndexOf(matcher, size); 2492 } 2493 2494 /** 2495 * Searches the string builder using the matcher to find the last match searching from the given index. 2496 * <p> 2497 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2498 * character 'a' followed by a number. 2499 * </p> 2500 * 2501 * @param matcher the matcher to use, null returns -1 2502 * @param startIndex the index to start at, invalid index rounded to edge 2503 * @return The last index matched, or -1 if not found 2504 */ 2505 public int lastIndexOf(final StringMatcher matcher, int startIndex) { 2506 startIndex = startIndex >= size ? size - 1 : startIndex; 2507 if (matcher == null || startIndex < 0) { 2508 return StringUtils.INDEX_NOT_FOUND; 2509 } 2510 final char[] buf = buffer; 2511 final int endIndex = startIndex + 1; 2512 for (int i = startIndex; i >= 0; i--) { 2513 if (matcher.isMatch(buf, i, 0, endIndex) > 0) { 2514 return i; 2515 } 2516 } 2517 return StringUtils.INDEX_NOT_FOUND; 2518 } 2519 2520 /** 2521 * Extracts the leftmost characters from the string builder without throwing an exception. 2522 * <p> 2523 * This method extracts the left {@code length} characters from the builder. If this many characters are not 2524 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2525 * </p> 2526 * 2527 * @param length the number of characters to extract, negative returns empty string 2528 * @return The new string 2529 */ 2530 public String leftString(final int length) { 2531 if (length <= 0) { 2532 return StringUtils.EMPTY; 2533 } 2534 if (length >= size) { 2535 return new String(buffer, 0, size); 2536 } 2537 return new String(buffer, 0, length); 2538 } 2539 2540 /** 2541 * Gets the length of the string builder. 2542 * 2543 * @return The length 2544 */ 2545 @Override 2546 public int length() { 2547 return size; 2548 } 2549 2550 /** 2551 * Extracts some characters from the middle of the string builder without throwing an exception. 2552 * <p> 2553 * This method extracts {@code length} characters from the builder at the specified index. If the index is negative 2554 * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the 2555 * length is negative, the empty string is returned. If insufficient characters are available in the builder, as 2556 * much as possible is returned. Thus the returned string may be shorter than the length requested. 2557 * </p> 2558 * 2559 * @param index the index to start at, negative means zero 2560 * @param length the number of characters to extract, negative returns empty string 2561 * @return The new string 2562 */ 2563 public String midString(int index, final int length) { 2564 if (index < 0) { 2565 index = 0; 2566 } 2567 if (length <= 0 || index >= size) { 2568 return StringUtils.EMPTY; 2569 } 2570 if (size <= index + length) { 2571 return new String(buffer, index, size - index); 2572 } 2573 return new String(buffer, index, length); 2574 } 2575 2576 /** 2577 * Minimizes the capacity to the actual length of the string. 2578 * 2579 * @return this, to enable chaining 2580 */ 2581 public TextStringBuilder minimizeCapacity() { 2582 if (buffer.length > size) { 2583 reallocate(size); 2584 } 2585 return this; 2586 } 2587 2588 /** 2589 * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without 2590 * making extra copies. 2591 * 2592 * @param charBuffer CharBuffer to read. 2593 * @return The number of characters read. 2594 * @see #appendTo(Appendable) 2595 * @since 1.9 2596 */ 2597 public int readFrom(final CharBuffer charBuffer) { 2598 final int oldSize = size; 2599 final int remaining = charBuffer.remaining(); 2600 ensureCapacityInternal(size + remaining); 2601 charBuffer.get(buffer, size, remaining); 2602 size += remaining; 2603 return size - oldSize; 2604 } 2605 2606 /** 2607 * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without 2608 * making extra copies. 2609 * 2610 * @param readable object to read from 2611 * @return The number of characters read 2612 * @throws IOException if an I/O error occurs. 2613 * @see #appendTo(Appendable) 2614 */ 2615 public int readFrom(final Readable readable) throws IOException { 2616 if (readable instanceof Reader) { 2617 return readFrom((Reader) readable); 2618 } 2619 if (readable instanceof CharBuffer) { 2620 return readFrom((CharBuffer) readable); 2621 } 2622 final int oldSize = size; 2623 while (true) { 2624 ensureCapacityInternal(size + 1); 2625 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); 2626 final int read = readable.read(buf); 2627 if (read == EOS) { 2628 break; 2629 } 2630 size += read; 2631 } 2632 return size - oldSize; 2633 } 2634 2635 /** 2636 * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without 2637 * making extra copies. 2638 * 2639 * @param reader Reader to read. 2640 * @return The number of characters read or -1 if we reached the end of stream. 2641 * @throws IOException if an I/O error occurs. 2642 * @see #appendTo(Appendable) 2643 * @since 1.9 2644 */ 2645 public int readFrom(final Reader reader) throws IOException { 2646 final int oldSize = size; 2647 ensureCapacityInternal(size + 1); 2648 int readCount = reader.read(buffer, size, buffer.length - size); 2649 if (readCount == EOS) { 2650 return EOS; 2651 } 2652 do { 2653 size += readCount; 2654 ensureCapacityInternal(size + 1); 2655 readCount = reader.read(buffer, size, buffer.length - size); 2656 } while (readCount != EOS); 2657 return size - oldSize; 2658 } 2659 2660 /** 2661 * If possible, reads {@code count} chars from the provided {@link Reader} directly into underlying character buffer 2662 * without making extra copies. 2663 * 2664 * @param reader Reader to read. 2665 * @param count The maximum characters to read, a value <= 0 returns 0. 2666 * @return The number of characters read. If less than {@code count}, then we've reached the end-of-stream, or -1 if 2667 * we reached the end of stream. 2668 * @throws IOException if an I/O error occurs. 2669 * @see #appendTo(Appendable) 2670 * @since 1.9 2671 */ 2672 public int readFrom(final Reader reader, final int count) throws IOException { 2673 if (count <= 0) { 2674 return 0; 2675 } 2676 final int oldSize = size; 2677 ensureCapacityInternal(size + count); 2678 int target = count; 2679 int readCount = reader.read(buffer, size, target); 2680 if (readCount == EOS) { 2681 return EOS; 2682 } 2683 do { 2684 target -= readCount; 2685 size += readCount; 2686 readCount = reader.read(buffer, size, target); 2687 } while (target > 0 && readCount != EOS); 2688 return size - oldSize; 2689 } 2690 2691 /** 2692 * Reallocates the buffer to the new length. 2693 * 2694 * @param newLength the length of the copy to be returned 2695 */ 2696 private void reallocate(final int newLength) { 2697 this.buffer = Arrays.copyOf(buffer, newLength); 2698 this.reallocations++; 2699 } 2700 2701 /** 2702 * Replaces a portion of the string builder with another string. The length of the inserted string does not have to 2703 * match the removed length. 2704 * 2705 * @param startIndex the start index, inclusive, must be valid 2706 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2707 * @param replaceStr the string to replace with, null means delete range 2708 * @return this, to enable chaining 2709 * @throws IndexOutOfBoundsException if the index is invalid 2710 */ 2711 public TextStringBuilder replace(final int startIndex, int endIndex, final String replaceStr) { 2712 endIndex = validateRange(startIndex, endIndex); 2713 final int insertLen = replaceStr == null ? 0 : replaceStr.length(); 2714 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); 2715 return this; 2716 } 2717 2718 /** 2719 * Advanced search and replaces within the builder using a matcher. 2720 * <p> 2721 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2722 * occurrences where the character 'a' is followed by a number. 2723 * </p> 2724 * 2725 * @param matcher the matcher to use to find the deletion, null causes no action 2726 * @param replaceStr the string to replace the match with, null is a delete 2727 * @param startIndex the start index, inclusive, must be valid 2728 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2729 * @param replaceCount the number of times to replace, -1 for replace all 2730 * @return this, to enable chaining 2731 * @throws IndexOutOfBoundsException if start index is invalid 2732 */ 2733 public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex, 2734 int endIndex, final int replaceCount) { 2735 endIndex = validateRange(startIndex, endIndex); 2736 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); 2737 } 2738 2739 /** 2740 * Replaces the search character with the replace character throughout the builder. 2741 * 2742 * @param search the search character 2743 * @param replace the replace character 2744 * @return this, to enable chaining 2745 */ 2746 public TextStringBuilder replaceAll(final char search, final char replace) { 2747 if (search != replace) { 2748 for (int i = 0; i < size; i++) { 2749 if (buffer[i] == search) { 2750 buffer[i] = replace; 2751 } 2752 } 2753 } 2754 return this; 2755 } 2756 2757 /** 2758 * Replaces the search string with the replace string throughout the builder. 2759 * 2760 * @param searchStr the search string, null causes no action to occur 2761 * @param replaceStr the replace string, null is equivalent to an empty string 2762 * @return this, to enable chaining 2763 */ 2764 public TextStringBuilder replaceAll(final String searchStr, final String replaceStr) { 2765 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2766 if (searchLen > 0) { 2767 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2768 int index = indexOf(searchStr, 0); 2769 while (index >= 0) { 2770 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2771 index = indexOf(searchStr, index + replaceLen); 2772 } 2773 } 2774 return this; 2775 } 2776 2777 /** 2778 * Replaces all matches within the builder with the replace string. 2779 * <p> 2780 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all 2781 * occurrences where the character 'a' is followed by a number. 2782 * </p> 2783 * 2784 * @param matcher the matcher to use to find the deletion, null causes no action 2785 * @param replaceStr the replace string, null is equivalent to an empty string 2786 * @return this, to enable chaining 2787 */ 2788 public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) { 2789 return replace(matcher, replaceStr, 0, size, -1); 2790 } 2791 2792 /** 2793 * Replaces the first instance of the search character with the replace character in the builder. 2794 * 2795 * @param search the search character 2796 * @param replace the replace character 2797 * @return this, to enable chaining 2798 */ 2799 public TextStringBuilder replaceFirst(final char search, final char replace) { 2800 if (search != replace) { 2801 for (int i = 0; i < size; i++) { 2802 if (buffer[i] == search) { 2803 buffer[i] = replace; 2804 break; 2805 } 2806 } 2807 } 2808 return this; 2809 } 2810 2811 /** 2812 * Replaces the first instance of the search string with the replace string. 2813 * 2814 * @param searchStr the search string, null causes no action to occur 2815 * @param replaceStr the replace string, null is equivalent to an empty string 2816 * @return this, to enable chaining 2817 */ 2818 public TextStringBuilder replaceFirst(final String searchStr, final String replaceStr) { 2819 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2820 if (searchLen > 0) { 2821 final int index = indexOf(searchStr, 0); 2822 if (index >= 0) { 2823 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2824 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2825 } 2826 } 2827 return this; 2828 } 2829 2830 /** 2831 * Replaces the first match within the builder with the replace string. 2832 * <p> 2833 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where 2834 * the character 'a' is followed by a number. 2835 * </p> 2836 * 2837 * @param matcher the matcher to use to find the deletion, null causes no action 2838 * @param replaceStr the replace string, null is equivalent to an empty string 2839 * @return this, to enable chaining 2840 */ 2841 public TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) { 2842 return replace(matcher, replaceStr, 0, size, 1); 2843 } 2844 2845 /** 2846 * Internal method to delete a range without validation. 2847 * 2848 * @param startIndex the start index, must be valid 2849 * @param endIndex the end index (exclusive), must be valid 2850 * @param removeLen the length to remove (endIndex - startIndex), must be valid 2851 * @param insertStr the string to replace with, null means delete range 2852 * @param insertLen the length of the insert string, must be valid 2853 * @throws IndexOutOfBoundsException if any index is invalid 2854 */ 2855 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, 2856 final int insertLen) { 2857 final int newSize = size - removeLen + insertLen; 2858 if (insertLen != removeLen) { 2859 ensureCapacityInternal(newSize); 2860 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); 2861 size = newSize; 2862 } 2863 if (insertLen > 0) { 2864 insertStr.getChars(0, insertLen, buffer, startIndex); 2865 } 2866 } 2867 2868 /** 2869 * Replaces within the builder using a matcher. 2870 * <p> 2871 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2872 * occurrences where the character 'a' is followed by a number. 2873 * </p> 2874 * 2875 * @param matcher the matcher to use to find the deletion, null causes no action 2876 * @param replaceStr the string to replace the match with, null is a delete 2877 * @param from the start index, must be valid 2878 * @param to the end index (exclusive), must be valid 2879 * @param replaceCount the number of times to replace, -1 for replace all 2880 * @return this, to enable chaining 2881 * @throws IndexOutOfBoundsException if any index is invalid 2882 */ 2883 private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to, 2884 int replaceCount) { 2885 if (matcher == null || size == 0) { 2886 return this; 2887 } 2888 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2889 for (int i = from; i < to && replaceCount != 0; i++) { 2890 final char[] buf = buffer; 2891 final int removeLen = matcher.isMatch(buf, i, from, to); 2892 if (removeLen > 0) { 2893 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); 2894 to = to - removeLen + replaceLen; 2895 i = i + replaceLen - 1; 2896 if (replaceCount > 0) { 2897 replaceCount--; 2898 } 2899 } 2900 } 2901 return this; 2902 } 2903 2904 /** 2905 * Resizes the buffer to at least the size specified. 2906 * 2907 * @param minCapacity the minimum required capacity 2908 * @throws OutOfMemoryError if the {@code minCapacity} is negative 2909 */ 2910 private void resizeBuffer(final int minCapacity) { 2911 // Overflow-conscious code treats the min and new capacity as unsigned. 2912 final int oldCapacity = buffer.length; 2913 int newCapacity = oldCapacity * 2; 2914 if (Integer.compareUnsigned(newCapacity, minCapacity) < 0) { 2915 newCapacity = minCapacity; 2916 } 2917 if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) { 2918 newCapacity = createPositiveCapacity(minCapacity); 2919 } 2920 reallocate(newCapacity); 2921 } 2922 2923 /** 2924 * Reverses the string builder placing each character in the opposite index. 2925 * 2926 * @return this, to enable chaining 2927 */ 2928 public TextStringBuilder reverse() { 2929 if (size == 0) { 2930 return this; 2931 } 2932 2933 final int half = size / 2; 2934 final char[] buf = buffer; 2935 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) { 2936 final char swap = buf[leftIdx]; 2937 buf[leftIdx] = buf[rightIdx]; 2938 buf[rightIdx] = swap; 2939 } 2940 return this; 2941 } 2942 2943 /** 2944 * Extracts the rightmost characters from the string builder without throwing an exception. 2945 * <p> 2946 * This method extracts the right {@code length} characters from the builder. If this many characters are not 2947 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2948 * </p> 2949 * 2950 * @param length the number of characters to extract, negative returns empty string 2951 * @return The new string 2952 */ 2953 public String rightString(final int length) { 2954 if (length <= 0) { 2955 return StringUtils.EMPTY; 2956 } 2957 if (length >= size) { 2958 return new String(buffer, 0, size); 2959 } 2960 return new String(buffer, size - length, length); 2961 } 2962 2963 /** 2964 * Clears and sets this builder to the given value. 2965 * 2966 * @see #charAt(int) 2967 * @see #deleteCharAt(int) 2968 * @param str the new value. 2969 * @return this, to enable chaining 2970 * @since 1.9 2971 */ 2972 public TextStringBuilder set(final CharSequence str) { 2973 clear(); 2974 append(str); 2975 return this; 2976 } 2977 2978 /** 2979 * Sets the character at the specified index. 2980 * 2981 * @see #charAt(int) 2982 * @see #deleteCharAt(int) 2983 * @param index the index to set 2984 * @param ch the new character 2985 * @return this, to enable chaining 2986 * @throws IndexOutOfBoundsException if the index is invalid 2987 */ 2988 public TextStringBuilder setCharAt(final int index, final char ch) { 2989 validateIndex(index); 2990 buffer[index] = ch; 2991 return this; 2992 } 2993 2994 /** 2995 * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero. 2996 * 2997 * @param length the length to set to, must be zero or positive 2998 * @return this, to enable chaining 2999 * @throws IndexOutOfBoundsException if the length is negative 3000 */ 3001 public TextStringBuilder setLength(final int length) { 3002 if (length < 0) { 3003 throw new StringIndexOutOfBoundsException(length); 3004 } 3005 if (length < size) { 3006 size = length; 3007 } else if (length > size) { 3008 ensureCapacityInternal(length); 3009 final int oldEnd = size; 3010 size = length; 3011 Arrays.fill(buffer, oldEnd, length, '\0'); 3012 } 3013 return this; 3014 } 3015 3016 /** 3017 * Sets the text to be appended when {@link #appendNewLine() new line} is called. 3018 * 3019 * @param newLine the new line text, {@code null} means use the system default from {@link System#lineSeparator()}. 3020 * @return this instance. 3021 */ 3022 public TextStringBuilder setNewLineText(final String newLine) { 3023 this.newLine = newLine; 3024 return this; 3025 } 3026 3027 /** 3028 * Sets the text to be appended when null is added. 3029 * 3030 * @param nullText the null text, null means no append 3031 * @return this, to enable chaining 3032 */ 3033 public TextStringBuilder setNullText(String nullText) { 3034 if (nullText != null && nullText.isEmpty()) { 3035 nullText = null; 3036 } 3037 this.nullText = nullText; 3038 return this; 3039 } 3040 3041 /** 3042 * Gets the length of the string builder. 3043 * <p> 3044 * This method is the same as {@link #length()} and is provided to match the API of Collections. 3045 * </p> 3046 * 3047 * @return The length 3048 */ 3049 public int size() { 3050 return size; 3051 } 3052 3053 /** 3054 * Checks whether this builder starts with the specified string. 3055 * <p> 3056 * Note that this method handles null input quietly, unlike String. 3057 * </p> 3058 * 3059 * @param str the string to search for, null returns false 3060 * @return true if the builder starts with the string 3061 */ 3062 public boolean startsWith(final String str) { 3063 if (str == null) { 3064 return false; 3065 } 3066 final int len = str.length(); 3067 if (len == 0) { 3068 return true; 3069 } 3070 if (len > size) { 3071 return false; 3072 } 3073 for (int i = 0; i < len; i++) { 3074 if (buffer[i] != str.charAt(i)) { 3075 return false; 3076 } 3077 } 3078 return true; 3079 } 3080 3081 /** 3082 * {@inheritDoc} 3083 */ 3084 @Override 3085 public CharSequence subSequence(final int startIndex, final int endIndex) { 3086 if (startIndex < 0) { 3087 throw new StringIndexOutOfBoundsException(startIndex); 3088 } 3089 if (endIndex > size) { 3090 throw new StringIndexOutOfBoundsException(endIndex); 3091 } 3092 if (startIndex > endIndex) { 3093 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 3094 } 3095 return substring(startIndex, endIndex); 3096 } 3097 3098 /** 3099 * Extracts a portion of this string builder as a string. 3100 * 3101 * @param start the start index, inclusive, must be valid 3102 * @return The new string 3103 * @throws IndexOutOfBoundsException if the index is invalid 3104 */ 3105 public String substring(final int start) { 3106 return substring(start, size); 3107 } 3108 3109 /** 3110 * Extracts a portion of this string builder as a string. 3111 * <p> 3112 * Note: This method treats an endIndex greater than the length of the builder as equal to the length of the 3113 * builder, and continues without error, unlike StringBuffer or String. 3114 * </p> 3115 * 3116 * @param startIndex the start index, inclusive, must be valid 3117 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3118 * @return The new string 3119 * @throws IndexOutOfBoundsException if the index is invalid 3120 */ 3121 public String substring(final int startIndex, int endIndex) { 3122 endIndex = validateRange(startIndex, endIndex); 3123 return new String(buffer, startIndex, endIndex - startIndex); 3124 } 3125 3126 /** 3127 * Copies the builder's character array into a new character array. 3128 * 3129 * @return a new array that represents the contents of the builder 3130 */ 3131 public char[] toCharArray() { 3132 return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size); 3133 } 3134 3135 /** 3136 * Copies part of the builder's character array into a new character array. 3137 * 3138 * @param startIndex the start index, inclusive, must be valid 3139 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3140 * @return a new array that holds part of the contents of the builder 3141 * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than 3142 * size is valid) 3143 */ 3144 public char[] toCharArray(final int startIndex, int endIndex) { 3145 endIndex = validateRange(startIndex, endIndex); 3146 final int len = endIndex - startIndex; 3147 return len == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOfRange(buffer, startIndex, endIndex); 3148 } 3149 3150 /** 3151 * Gets a String version of the string builder, creating a new instance each time the method is called. 3152 * <p> 3153 * Note that unlike StringBuffer, the string version returned is independent of the string builder. 3154 * </p> 3155 * 3156 * @return The builder as a String 3157 */ 3158 @Override 3159 public String toString() { 3160 return new String(buffer, 0, size); 3161 } 3162 3163 /** 3164 * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called. 3165 * 3166 * @return The builder as a StringBuffer 3167 */ 3168 public StringBuffer toStringBuffer() { 3169 return new StringBuffer(size).append(buffer, 0, size); 3170 } 3171 3172 /** 3173 * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called. 3174 * 3175 * @return The builder as a StringBuilder 3176 */ 3177 public StringBuilder toStringBuilder() { 3178 return new StringBuilder(size).append(buffer, 0, size); 3179 } 3180 3181 /** 3182 * Trims the builder by removing characters less than or equal to a space from the beginning and end. 3183 * 3184 * @return this, to enable chaining 3185 */ 3186 public TextStringBuilder trim() { 3187 if (size == 0) { 3188 return this; 3189 } 3190 int len = size; 3191 final char[] buf = buffer; 3192 int pos = 0; 3193 while (pos < len && buf[pos] <= SPACE) { 3194 pos++; 3195 } 3196 while (pos < len && buf[len - 1] <= SPACE) { 3197 len--; 3198 } 3199 if (len < size) { 3200 delete(len, size); 3201 } 3202 if (pos > 0) { 3203 delete(0, pos); 3204 } 3205 return this; 3206 } 3207 3208 /** 3209 * Validates that an index is in the range {@code 0 <= index <= size}. 3210 * 3211 * @param index the index to test. 3212 * @throws IndexOutOfBoundsException Thrown when the index is not the range {@code 0 <= index <= size}. 3213 */ 3214 protected void validateIndex(final int index) { 3215 if (index < 0 || index >= size) { 3216 throw new StringIndexOutOfBoundsException(index); 3217 } 3218 } 3219 3220 /** 3221 * Validates parameters defining a range of the builder. 3222 * 3223 * @param startIndex the start index, inclusive, must be valid 3224 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3225 * @return A valid end index. 3226 * @throws StringIndexOutOfBoundsException if the index is invalid 3227 */ 3228 protected int validateRange(final int startIndex, int endIndex) { 3229 if (startIndex < 0) { 3230 throw new StringIndexOutOfBoundsException(startIndex); 3231 } 3232 if (endIndex > size) { 3233 endIndex = size; 3234 } 3235 if (startIndex > endIndex) { 3236 throw new StringIndexOutOfBoundsException("end < start"); 3237 } 3238 return endIndex; 3239 } 3240 3241 }