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