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 final 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 final class TextStringBuilderTokenizer extends StringTokenizer { 173 174 /** 175 * Default constructor. 176 */ 177 TextStringBuilderTokenizer() { 178 } 179 180 /** {@inheritDoc} */ 181 @Override 182 public String getContent() { 183 final String str = super.getContent(); 184 if (str == null) { 185 return TextStringBuilder.this.toString(); 186 } 187 return str; 188 } 189 190 /** {@inheritDoc} */ 191 @Override 192 protected List<String> tokenize(final char[] chars, final int offset, final int count) { 193 if (chars == null) { 194 return super.tokenize(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 final class TextStringBuilderWriter extends Writer { 204 205 /** 206 * Default constructor. 207 */ 208 TextStringBuilderWriter() { 209 } 210 211 /** {@inheritDoc} */ 212 @Override 213 public void close() { 214 // do nothing 215 } 216 217 /** {@inheritDoc} */ 218 @Override 219 public void flush() { 220 // do nothing 221 } 222 223 /** {@inheritDoc} */ 224 @Override 225 public void write(final char[] cbuf) { 226 TextStringBuilder.this.append(cbuf); 227 } 228 229 /** {@inheritDoc} */ 230 @Override 231 public void write(final char[] cbuf, final int off, final int len) { 232 TextStringBuilder.this.append(cbuf, off, len); 233 } 234 235 /** {@inheritDoc} */ 236 @Override 237 public void write(final int c) { 238 TextStringBuilder.this.append((char) c); 239 } 240 241 /** {@inheritDoc} */ 242 @Override 243 public void write(final String str) { 244 TextStringBuilder.this.append(str); 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 public void write(final String str, final int off, final int len) { 250 TextStringBuilder.this.append(str, off, len); 251 } 252 } 253 254 /** The space character. */ 255 private static final char SPACE = ' '; 256 257 /** 258 * The extra capacity for new builders. 259 */ 260 static final int CAPACITY = 32; 261 262 /** 263 * End-Of-Stream. 264 */ 265 private static final int EOS = -1; 266 267 /** 268 * The size of the string {@code "false"}. 269 */ 270 private static final int FALSE_STRING_SIZE = Boolean.FALSE.toString().length(); 271 272 /** 273 * Required for serialization support. 274 * 275 * @see java.io.Serializable 276 */ 277 private static final long serialVersionUID = 1L; 278 279 /** 280 * The size of the string {@code "true"}. 281 */ 282 private static final int TRUE_STRING_SIZE = Boolean.TRUE.toString().length(); 283 284 /** 285 * The maximum size buffer to allocate. 286 * 287 * <p>This is set to the same size used in the JDK {@link java.util.ArrayList}:</p> 288 * <blockquote> 289 * Some VMs reserve some header words in an array. 290 * Attempts to allocate larger arrays may result in 291 * OutOfMemoryError: Requested array size exceeds VM limit. 292 * </blockquote> 293 */ 294 private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; 295 296 /** 297 * Creates a positive capacity at least as large the minimum required capacity. 298 * If the minimum capacity is negative then this throws an OutOfMemoryError as no array 299 * can be allocated. 300 * 301 * @param minCapacity the minimum capacity 302 * @return the capacity 303 * @throws OutOfMemoryError if the {@code minCapacity} is negative 304 */ 305 private static int createPositiveCapacity(final int minCapacity) { 306 if (minCapacity < 0) { 307 // overflow 308 throw new OutOfMemoryError("Unable to allocate array size: " + Integer.toUnsignedString(minCapacity)); 309 } 310 // This is called when we require buffer expansion to a very big array. 311 // Use the conservative maximum buffer size if possible, otherwise the biggest required. 312 // 313 // Note: In this situation JDK 1.8 java.util.ArrayList returns Integer.MAX_VALUE. 314 // This excludes some VMs that can exceed MAX_BUFFER_SIZE but not allocate a full 315 // Integer.MAX_VALUE length array. 316 // The result is that we may have to allocate an array of this size more than once if 317 // the capacity must be expanded again. 318 return Math.max(minCapacity, MAX_BUFFER_SIZE); 319 } 320 321 /** 322 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this 323 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to 324 * be initialized without copying the input array. 325 * 326 * @param initialBuffer The initial array that will back the new builder. 327 * @return A new instance. 328 * @since 1.9 329 */ 330 public static TextStringBuilder wrap(final char[] initialBuffer) { 331 Objects.requireNonNull(initialBuffer, "initialBuffer"); 332 return new TextStringBuilder(initialBuffer, initialBuffer.length); 333 } 334 335 /** 336 * Constructs an instance from a reference to a character array. Changes to the input chars are reflected in this 337 * instance until the internal buffer needs to be reallocated. Using a reference to an array allows the instance to 338 * be initialized without copying the input array. 339 * 340 * @param initialBuffer The initial array that will back the new builder. 341 * @param length The length of the subarray to be used; must be non-negative and no larger than 342 * {@code initialBuffer.length}. The new builder's size will be set to {@code length}. 343 * @return A new instance. 344 * @since 1.9 345 */ 346 public static TextStringBuilder wrap(final char[] initialBuffer, final int length) { 347 return new TextStringBuilder(initialBuffer, length); 348 } 349 350 /** Internal data storage. */ 351 private char[] buffer; 352 353 /** 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 * Converts this instance to a String. 1552 * 1553 * @return This instance as a String 1554 * @see #toString() 1555 * @deprecated Use {@link #get()}. 1556 */ 1557 @Deprecated 1558 @Override 1559 public String build() { 1560 return toString(); 1561 } 1562 1563 /** 1564 * Gets the current size of the internal character array buffer. 1565 * 1566 * @return The capacity 1567 */ 1568 public int capacity() { 1569 return buffer.length; 1570 } 1571 1572 /** 1573 * Gets the character at the specified index. 1574 * 1575 * @see #setCharAt(int, char) 1576 * @see #deleteCharAt(int) 1577 * @param index the index to retrieve, must be valid 1578 * @return The character at the index 1579 * @throws IndexOutOfBoundsException if the index is invalid 1580 */ 1581 @Override 1582 public char charAt(final int index) { 1583 validateIndex(index); 1584 return buffer[index]; 1585 } 1586 1587 /** 1588 * Clears the string builder (convenience Collections API style method). 1589 * <p> 1590 * This method does not reduce the size of the internal character buffer. To do that, call {@code clear()} followed 1591 * by {@link #minimizeCapacity()}. 1592 * </p> 1593 * <p> 1594 * This method is the same as {@link #setLength(int)} called with zero and is provided to match the API of 1595 * Collections. 1596 * </p> 1597 * 1598 * @return this, to enable chaining 1599 */ 1600 public TextStringBuilder clear() { 1601 size = 0; 1602 return this; 1603 } 1604 1605 /** 1606 * Tests if the string builder contains the specified char. 1607 * 1608 * @param ch the character to find 1609 * @return true if the builder contains the character 1610 */ 1611 public boolean contains(final char ch) { 1612 final char[] thisBuf = buffer; 1613 for (int i = 0; i < this.size; i++) { 1614 if (thisBuf[i] == ch) { 1615 return true; 1616 } 1617 } 1618 return false; 1619 } 1620 1621 /** 1622 * Tests if the string builder contains the specified string. 1623 * 1624 * @param str the string to find 1625 * @return true if the builder contains the string 1626 */ 1627 public boolean contains(final String str) { 1628 return indexOf(str, 0) >= 0; 1629 } 1630 1631 /** 1632 * Tests if the string builder contains a string matched using the specified matcher. 1633 * <p> 1634 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to search for 1635 * the character 'a' followed by a number. 1636 * </p> 1637 * 1638 * @param matcher the matcher to use, null returns -1 1639 * @return true if the matcher finds a match in the builder 1640 */ 1641 public boolean contains(final StringMatcher matcher) { 1642 return indexOf(matcher, 0) >= 0; 1643 } 1644 1645 /** 1646 * Deletes the characters between the two specified indices. 1647 * 1648 * @param startIndex the start index, inclusive, must be valid 1649 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 1650 * @return this, to enable chaining 1651 * @throws IndexOutOfBoundsException if the index is invalid 1652 */ 1653 public TextStringBuilder delete(final int startIndex, final int endIndex) { 1654 final int actualEndIndex = validateRange(startIndex, endIndex); 1655 final int len = actualEndIndex - startIndex; 1656 if (len > 0) { 1657 deleteImpl(startIndex, actualEndIndex, len); 1658 } 1659 return this; 1660 } 1661 1662 /** 1663 * Deletes the character wherever it occurs in the builder. 1664 * 1665 * @param ch the character to delete 1666 * @return this, to enable chaining 1667 */ 1668 public TextStringBuilder deleteAll(final char ch) { 1669 for (int i = 0; i < size; i++) { 1670 if (buffer[i] == ch) { 1671 final int start = i; 1672 while (++i < size) { 1673 if (buffer[i] != ch) { 1674 break; 1675 } 1676 } 1677 final int len = i - start; 1678 deleteImpl(start, i, len); 1679 i -= len; 1680 } 1681 } 1682 return this; 1683 } 1684 1685 /** 1686 * Deletes the string wherever it occurs in the builder. 1687 * 1688 * @param str the string to delete, null causes no action 1689 * @return this, to enable chaining 1690 */ 1691 public TextStringBuilder deleteAll(final String str) { 1692 final int len = str == null ? 0 : str.length(); 1693 if (len > 0) { 1694 int index = indexOf(str, 0); 1695 while (index >= 0) { 1696 deleteImpl(index, index + len, len); 1697 index = indexOf(str, index); 1698 } 1699 } 1700 return this; 1701 } 1702 1703 /** 1704 * Deletes all parts of the builder that the matcher matches. 1705 * <p> 1706 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete all 1707 * occurrences where the character 'a' is followed by a number. 1708 * </p> 1709 * 1710 * @param matcher the matcher to use to find the deletion, null causes no action 1711 * @return this, to enable chaining 1712 */ 1713 public TextStringBuilder deleteAll(final StringMatcher matcher) { 1714 return replace(matcher, null, 0, size, -1); 1715 } 1716 1717 /** 1718 * Deletes the character at the specified index. 1719 * 1720 * @see #charAt(int) 1721 * @see #setCharAt(int, char) 1722 * @param index the index to delete 1723 * @return this, to enable chaining 1724 * @throws IndexOutOfBoundsException if the index is invalid 1725 */ 1726 public TextStringBuilder deleteCharAt(final int index) { 1727 validateIndex(index); 1728 deleteImpl(index, index + 1, 1); 1729 return this; 1730 } 1731 1732 /** 1733 * Deletes the character wherever it occurs in the builder. 1734 * 1735 * @param ch the character to delete 1736 * @return this, to enable chaining 1737 */ 1738 public TextStringBuilder deleteFirst(final char ch) { 1739 for (int i = 0; i < size; i++) { 1740 if (buffer[i] == ch) { 1741 deleteImpl(i, i + 1, 1); 1742 break; 1743 } 1744 } 1745 return this; 1746 } 1747 1748 /** 1749 * Deletes the string wherever it occurs in the builder. 1750 * 1751 * @param str the string to delete, null causes no action 1752 * @return this, to enable chaining 1753 */ 1754 public TextStringBuilder deleteFirst(final String str) { 1755 final int len = str == null ? 0 : str.length(); 1756 if (len > 0) { 1757 final int index = indexOf(str, 0); 1758 if (index >= 0) { 1759 deleteImpl(index, index + len, len); 1760 } 1761 } 1762 return this; 1763 } 1764 1765 /** 1766 * Deletes the first match within the builder using the specified matcher. 1767 * <p> 1768 * Matchers can be used to perform advanced deletion behavior. For example you could write a matcher to delete where 1769 * the character 'a' is followed by a number. 1770 * </p> 1771 * 1772 * @param matcher the matcher to use to find the deletion, null causes no action 1773 * @return this, to enable chaining 1774 */ 1775 public TextStringBuilder deleteFirst(final StringMatcher matcher) { 1776 return replace(matcher, null, 0, size, 1); 1777 } 1778 1779 /** 1780 * Internal method to delete a range without validation. 1781 * 1782 * @param startIndex the start index, must be valid 1783 * @param endIndex the end index (exclusive), must be valid 1784 * @param len the length, must be valid 1785 * @throws IndexOutOfBoundsException if any index is invalid 1786 */ 1787 private void deleteImpl(final int startIndex, final int endIndex, final int len) { 1788 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); 1789 size -= len; 1790 } 1791 1792 /** 1793 * Gets the character at the specified index before deleting it. 1794 * 1795 * @see #charAt(int) 1796 * @see #deleteCharAt(int) 1797 * @param index the index to retrieve, must be valid 1798 * @return The character at the index 1799 * @throws IndexOutOfBoundsException if the index is invalid 1800 * @since 1.9 1801 */ 1802 public char drainChar(final int index) { 1803 validateIndex(index); 1804 final char c = buffer[index]; 1805 deleteCharAt(index); 1806 return c; 1807 } 1808 1809 /** 1810 * Drains (copies, then deletes) this character sequence into the specified array. This is equivalent to copying the 1811 * characters from this sequence into the target and then deleting those character from this sequence. 1812 * 1813 * @param startIndex first index to copy, inclusive. 1814 * @param endIndex last index to copy, exclusive. 1815 * @param target the target array, must not be {@code null}. 1816 * @param targetIndex the index to start copying in the target. 1817 * @return How many characters where copied (then deleted). If this builder is empty, return {@code 0}. 1818 * @since 1.9 1819 */ 1820 public int drainChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) { 1821 final int length = endIndex - startIndex; 1822 if (isEmpty() || length == 0 || target.length == 0) { 1823 return 0; 1824 } 1825 final int actualLen = Math.min(Math.min(size, length), target.length - targetIndex); 1826 getChars(startIndex, actualLen, target, targetIndex); 1827 delete(startIndex, actualLen); 1828 return actualLen; 1829 } 1830 1831 /** 1832 * Checks whether this builder ends with the specified string. 1833 * <p> 1834 * Note that this method handles null input quietly, unlike String. 1835 * </p> 1836 * 1837 * @param str the string to search for, null returns false 1838 * @return true if the builder ends with the string 1839 */ 1840 public boolean endsWith(final String str) { 1841 if (str == null) { 1842 return false; 1843 } 1844 final int len = str.length(); 1845 if (len == 0) { 1846 return true; 1847 } 1848 if (len > size) { 1849 return false; 1850 } 1851 int pos = size - len; 1852 for (int i = 0; i < len; i++, pos++) { 1853 if (buffer[pos] != str.charAt(i)) { 1854 return false; 1855 } 1856 } 1857 return true; 1858 } 1859 1860 /** 1861 * Tests the capacity and ensures that it is at least the size specified. 1862 * 1863 * <p> 1864 * Note: This method can be used to minimise memory reallocations during 1865 * repeated addition of values by pre-allocating the character buffer. 1866 * The method ignores a negative {@code capacity} argument. 1867 * </p> 1868 * 1869 * @param capacity the capacity to ensure 1870 * @return this, to enable chaining 1871 * @throws OutOfMemoryError if the capacity cannot be allocated 1872 */ 1873 public TextStringBuilder ensureCapacity(final int capacity) { 1874 if (capacity > 0) { 1875 ensureCapacityInternal(capacity); 1876 } 1877 return this; 1878 } 1879 1880 /** 1881 * Ensures that the buffer is at least the size specified. The {@code capacity} argument 1882 * is treated as an unsigned integer. 1883 * 1884 * <p> 1885 * This method will raise an {@link OutOfMemoryError} if the capacity is too large 1886 * for an array, or cannot be allocated. 1887 * </p> 1888 * 1889 * @param capacity the capacity to ensure 1890 * @throws OutOfMemoryError if the capacity cannot be allocated 1891 */ 1892 private void ensureCapacityInternal(final int capacity) { 1893 // Check for overflow of the current buffer. 1894 // Assumes capacity is an unsigned integer up to Integer.MAX_VALUE * 2 1895 // (the largest possible addition of two maximum length arrays). 1896 if (capacity - buffer.length > 0) { 1897 resizeBuffer(capacity); 1898 } 1899 } 1900 1901 /** 1902 * Tests the contents of this builder against another to see if they contain the same character content. 1903 * 1904 * @param obj the object to check, null returns false 1905 * @return true if the builders contain the same characters in the same order 1906 */ 1907 @Override 1908 public boolean equals(final Object obj) { 1909 return obj instanceof TextStringBuilder && equals((TextStringBuilder) obj); 1910 } 1911 1912 /** 1913 * Tests the contents of this builder against another to see if they contain the same character content. 1914 * 1915 * @param other the object to check, null returns false 1916 * @return true if the builders contain the same characters in the same order 1917 */ 1918 public boolean equals(final TextStringBuilder other) { 1919 if (this == other) { 1920 return true; 1921 } 1922 if (other == null) { 1923 return false; 1924 } 1925 if (this.size != other.size) { 1926 return false; 1927 } 1928 // Be aware not to use Arrays.equals(buffer, other.buffer) for equals() method 1929 // as length of the buffers may be different (TEXT-211) 1930 final char[] thisBuf = this.buffer; 1931 final char[] otherBuf = other.buffer; 1932 for (int i = size - 1; i >= 0; i--) { 1933 if (thisBuf[i] != otherBuf[i]) { 1934 return false; 1935 } 1936 } 1937 return true; 1938 } 1939 1940 /** 1941 * Tests the contents of this builder against another to see if they contain the same character content ignoring 1942 * case. 1943 * 1944 * @param other the object to check, null returns false 1945 * @return true if the builders contain the same characters in the same order 1946 */ 1947 public boolean equalsIgnoreCase(final TextStringBuilder other) { 1948 if (this == other) { 1949 return true; 1950 } 1951 if (this.size != other.size) { 1952 return false; 1953 } 1954 final char[] thisBuf = this.buffer; 1955 final char[] otherBuf = other.buffer; 1956 for (int i = size - 1; i >= 0; i--) { 1957 final char c1 = thisBuf[i]; 1958 final char c2 = otherBuf[i]; 1959 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { 1960 return false; 1961 } 1962 } 1963 return true; 1964 } 1965 1966 /** 1967 * Converts this instance to a String. 1968 * 1969 * @return This instance as a String 1970 * @see #toString() 1971 * @since 1.12.0 1972 */ 1973 @Override 1974 public String get() { 1975 return toString(); 1976 } 1977 1978 /** 1979 * Gets a direct reference to internal storage, not for public consumption. 1980 */ 1981 char[] getBuffer() { 1982 return buffer; 1983 } 1984 1985 /** 1986 * Copies this character array into the specified array. 1987 * 1988 * @param target the target array, null will cause an array to be created 1989 * @return The input array, unless that was null or too small 1990 */ 1991 public char[] getChars(char[] target) { 1992 final int len = length(); 1993 if (target == null || target.length < len) { 1994 target = new char[len]; 1995 } 1996 System.arraycopy(buffer, 0, target, 0, len); 1997 return target; 1998 } 1999 2000 /** 2001 * Copies this character array into the specified array. 2002 * 2003 * @param startIndex first index to copy, inclusive, must be valid. 2004 * @param endIndex last index to copy, exclusive, must be valid. 2005 * @param target the target array, must not be null or too small. 2006 * @param targetIndex the index to start copying in target. 2007 * @throws NullPointerException if the array is null. 2008 * @throws IndexOutOfBoundsException if any index is invalid. 2009 */ 2010 public void getChars(final int startIndex, final int endIndex, final char[] target, final int targetIndex) { 2011 if (startIndex < 0) { 2012 throw new StringIndexOutOfBoundsException(startIndex); 2013 } 2014 if (endIndex < 0 || endIndex > length()) { 2015 throw new StringIndexOutOfBoundsException(endIndex); 2016 } 2017 if (startIndex > endIndex) { 2018 throw new StringIndexOutOfBoundsException("end < start"); 2019 } 2020 System.arraycopy(buffer, startIndex, target, targetIndex, endIndex - startIndex); 2021 } 2022 2023 /** 2024 * Gets the text to be appended when a new line is added. 2025 * 2026 * @return The new line text, null means use system default 2027 */ 2028 public String getNewLineText() { 2029 return newLine; 2030 } 2031 2032 /** 2033 * Gets the text to be appended when null is added. 2034 * 2035 * @return The null text, null means no append 2036 */ 2037 public String getNullText() { 2038 return nullText; 2039 } 2040 2041 /** 2042 * Gets a suitable hash code for this builder. 2043 * 2044 * @return a hash code 2045 */ 2046 @Override 2047 public int hashCode() { 2048 // no allocation 2049 final char[] buf = buffer; 2050 int result = 0; 2051 for (int i = 0; i < size; i++) { 2052 result = 31 * result + buf[i]; 2053 } 2054 return result; 2055 } 2056 2057 /** 2058 * Searches the string builder to find the first reference to the specified char. 2059 * 2060 * @param ch the character to find 2061 * @return The first index of the character, or -1 if not found 2062 */ 2063 public int indexOf(final char ch) { 2064 return indexOf(ch, 0); 2065 } 2066 2067 /** 2068 * Searches the string builder to find the first reference to the specified char. 2069 * 2070 * @param ch the character to find 2071 * @param startIndex the index to start at, invalid index rounded to edge 2072 * @return The first index of the character, or -1 if not found 2073 */ 2074 public int indexOf(final char ch, int startIndex) { 2075 startIndex = Math.max(0, startIndex); 2076 if (startIndex >= size) { 2077 return StringUtils.INDEX_NOT_FOUND; 2078 } 2079 final char[] thisBuf = buffer; 2080 for (int i = startIndex; i < size; i++) { 2081 if (thisBuf[i] == ch) { 2082 return i; 2083 } 2084 } 2085 return StringUtils.INDEX_NOT_FOUND; 2086 } 2087 2088 /** 2089 * Searches the string builder to find the first reference to the specified string. 2090 * <p> 2091 * Note that a null input string will return -1, whereas the JDK throws an exception. 2092 * </p> 2093 * 2094 * @param str the string to find, null returns -1 2095 * @return The first index of the string, or -1 if not found 2096 */ 2097 public int indexOf(final String str) { 2098 return indexOf(str, 0); 2099 } 2100 2101 /** 2102 * Searches the string builder to find the first reference to the specified string starting searching from the given 2103 * index. 2104 * <p> 2105 * Note that a null input string will return -1, whereas the JDK throws an exception. 2106 * </p> 2107 * 2108 * @param str the string to find, null returns -1 2109 * @param startIndex the index to start at, invalid index rounded to edge 2110 * @return The first index of the string, or -1 if not found 2111 */ 2112 public int indexOf(final String str, int startIndex) { 2113 startIndex = Math.max(0, startIndex); 2114 if (str == null || startIndex >= size) { 2115 return StringUtils.INDEX_NOT_FOUND; 2116 } 2117 final int strLen = str.length(); 2118 if (strLen == 1) { 2119 return indexOf(str.charAt(0), startIndex); 2120 } 2121 if (strLen == 0) { 2122 return startIndex; 2123 } 2124 if (strLen > size) { 2125 return StringUtils.INDEX_NOT_FOUND; 2126 } 2127 final char[] thisBuf = buffer; 2128 final int len = size - strLen + 1; 2129 outer: for (int i = startIndex; i < len; i++) { 2130 for (int j = 0; j < strLen; j++) { 2131 if (str.charAt(j) != thisBuf[i + j]) { 2132 continue outer; 2133 } 2134 } 2135 return i; 2136 } 2137 return StringUtils.INDEX_NOT_FOUND; 2138 } 2139 2140 /** 2141 * Searches the string builder using the matcher to find the first match. 2142 * <p> 2143 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2144 * character 'a' followed by a number. 2145 * </p> 2146 * 2147 * @param matcher the matcher to use, null returns -1 2148 * @return The first index matched, or -1 if not found 2149 */ 2150 public int indexOf(final StringMatcher matcher) { 2151 return indexOf(matcher, 0); 2152 } 2153 2154 /** 2155 * Searches the string builder using the matcher to find the first match searching from the given index. 2156 * <p> 2157 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2158 * character 'a' followed by a number. 2159 * </p> 2160 * 2161 * @param matcher the matcher to use, null returns -1 2162 * @param startIndex the index to start at, invalid index rounded to edge 2163 * @return The first index matched, or -1 if not found 2164 */ 2165 public int indexOf(final StringMatcher matcher, int startIndex) { 2166 startIndex = Math.max(0, startIndex); 2167 if (matcher == null || startIndex >= size) { 2168 return StringUtils.INDEX_NOT_FOUND; 2169 } 2170 final int len = size; 2171 final char[] buf = buffer; 2172 for (int i = startIndex; i < len; i++) { 2173 if (matcher.isMatch(buf, i, startIndex, len) > 0) { 2174 return i; 2175 } 2176 } 2177 return StringUtils.INDEX_NOT_FOUND; 2178 } 2179 2180 /** 2181 * Inserts the value into this builder. 2182 * 2183 * @param index the index to add at, must be valid 2184 * @param value the value to insert 2185 * @return this, to enable chaining 2186 * @throws IndexOutOfBoundsException if the index is invalid 2187 */ 2188 public TextStringBuilder insert(final int index, final boolean value) { 2189 validateIndex(index); 2190 if (value) { 2191 ensureCapacityInternal(size + TRUE_STRING_SIZE); 2192 System.arraycopy(buffer, index, buffer, index + TRUE_STRING_SIZE, size - index); 2193 appendTrue(index); 2194 } else { 2195 ensureCapacityInternal(size + FALSE_STRING_SIZE); 2196 System.arraycopy(buffer, index, buffer, index + FALSE_STRING_SIZE, size - index); 2197 appendFalse(index); 2198 } 2199 return this; 2200 } 2201 2202 /** 2203 * Inserts the value into this builder. 2204 * 2205 * @param index the index to add at, must be valid 2206 * @param value the value to insert 2207 * @return this, to enable chaining 2208 * @throws IndexOutOfBoundsException if the index is invalid 2209 */ 2210 public TextStringBuilder insert(final int index, final char value) { 2211 validateIndex(index); 2212 ensureCapacityInternal(size + 1); 2213 System.arraycopy(buffer, index, buffer, index + 1, size - index); 2214 buffer[index] = value; 2215 size++; 2216 return this; 2217 } 2218 2219 /** 2220 * Inserts the character array into this builder. Inserting null will use the stored null text value. 2221 * 2222 * @param index the index to add at, must be valid 2223 * @param chars the char array to insert 2224 * @return this, to enable chaining 2225 * @throws IndexOutOfBoundsException if the index is invalid 2226 */ 2227 public TextStringBuilder insert(final int index, final char[] chars) { 2228 validateIndex(index); 2229 if (chars == null) { 2230 return insert(index, nullText); 2231 } 2232 final int len = chars.length; 2233 if (len > 0) { 2234 ensureCapacityInternal(size + len); 2235 System.arraycopy(buffer, index, buffer, index + len, size - index); 2236 System.arraycopy(chars, 0, buffer, index, len); 2237 size += len; 2238 } 2239 return this; 2240 } 2241 2242 /** 2243 * Inserts part of the character array into this builder. Inserting null will use the stored null text value. 2244 * 2245 * @param index the index to add at, must be valid 2246 * @param chars the char array to insert 2247 * @param offset the offset into the character array to start at, must be valid 2248 * @param length the length of the character array part to copy, must be positive 2249 * @return this, to enable chaining 2250 * @throws IndexOutOfBoundsException if any index is invalid 2251 */ 2252 public TextStringBuilder insert(final int index, final char[] chars, final int offset, final int length) { 2253 validateIndex(index); 2254 if (chars == null) { 2255 return insert(index, nullText); 2256 } 2257 if (offset < 0 || offset > chars.length) { 2258 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); 2259 } 2260 if (length < 0 || offset + length > chars.length) { 2261 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 2262 } 2263 if (length > 0) { 2264 ensureCapacityInternal(size + length); 2265 System.arraycopy(buffer, index, buffer, index + length, size - index); 2266 System.arraycopy(chars, offset, buffer, index, length); 2267 size += length; 2268 } 2269 return this; 2270 } 2271 2272 /** 2273 * Inserts the value into this builder. 2274 * 2275 * @param index the index to add at, must be valid 2276 * @param value the value to insert 2277 * @return this, to enable chaining 2278 * @throws IndexOutOfBoundsException if the index is invalid 2279 */ 2280 public TextStringBuilder insert(final int index, final double value) { 2281 return insert(index, String.valueOf(value)); 2282 } 2283 2284 /** 2285 * Inserts the value into this builder. 2286 * 2287 * @param index the index to add at, must be valid 2288 * @param value the value to insert 2289 * @return this, to enable chaining 2290 * @throws IndexOutOfBoundsException if the index is invalid 2291 */ 2292 public TextStringBuilder insert(final int index, final float value) { 2293 return insert(index, String.valueOf(value)); 2294 } 2295 2296 /** 2297 * Inserts the value into this builder. 2298 * 2299 * @param index the index to add at, must be valid 2300 * @param value the value to insert 2301 * @return this, to enable chaining 2302 * @throws IndexOutOfBoundsException if the index is invalid 2303 */ 2304 public TextStringBuilder insert(final int index, final int value) { 2305 return insert(index, String.valueOf(value)); 2306 } 2307 2308 /** 2309 * Inserts the value into this builder. 2310 * 2311 * @param index the index to add at, must be valid 2312 * @param value the value to insert 2313 * @return this, to enable chaining 2314 * @throws IndexOutOfBoundsException if the index is invalid 2315 */ 2316 public TextStringBuilder insert(final int index, final long value) { 2317 return insert(index, String.valueOf(value)); 2318 } 2319 2320 /** 2321 * Inserts the string representation of an object into this builder. Inserting null will use the stored null text 2322 * value. 2323 * 2324 * @param index the index to add at, must be valid 2325 * @param obj the object to insert 2326 * @return this, to enable chaining 2327 * @throws IndexOutOfBoundsException if the index is invalid 2328 */ 2329 public TextStringBuilder insert(final int index, final Object obj) { 2330 if (obj == null) { 2331 return insert(index, nullText); 2332 } 2333 return insert(index, obj.toString()); 2334 } 2335 2336 /** 2337 * Inserts the string into this builder. Inserting null will use the stored null text value. 2338 * 2339 * @param index the index to add at, must be valid 2340 * @param str the string to insert 2341 * @return this, to enable chaining 2342 * @throws IndexOutOfBoundsException if the index is invalid 2343 */ 2344 public TextStringBuilder insert(final int index, String str) { 2345 validateIndex(index); 2346 if (str == null) { 2347 str = nullText; 2348 } 2349 if (str != null) { 2350 final int strLen = str.length(); 2351 if (strLen > 0) { 2352 final int newSize = size + strLen; 2353 ensureCapacityInternal(newSize); 2354 System.arraycopy(buffer, index, buffer, index + strLen, size - index); 2355 size = newSize; 2356 str.getChars(0, strLen, buffer, index); 2357 } 2358 } 2359 return this; 2360 } 2361 2362 /** 2363 * Checks is the string builder is empty (convenience Collections API style method). 2364 * <p> 2365 * This method is the same as checking {@link #length()} and is provided to match the API of Collections. 2366 * </p> 2367 * 2368 * @return {@code true} if the size is {@code 0}. 2369 */ 2370 public boolean isEmpty() { 2371 return size == 0; 2372 } 2373 2374 /** 2375 * Checks is the string builder is not empty. 2376 * <p> 2377 * This method is the same as checking {@link #length()}. 2378 * </p> 2379 * 2380 * @return {@code true} if the size is not {@code 0}. 2381 * @since 1.9 2382 */ 2383 public boolean isNotEmpty() { 2384 return size != 0; 2385 } 2386 2387 /** 2388 * Gets whether the internal buffer has been reallocated. 2389 * 2390 * @return Whether the internal buffer has been reallocated. 2391 * @since 1.9 2392 */ 2393 public boolean isReallocated() { 2394 return reallocations > 0; 2395 } 2396 2397 /** 2398 * Searches the string builder to find the last reference to the specified char. 2399 * 2400 * @param ch the character to find 2401 * @return The last index of the character, or -1 if not found 2402 */ 2403 public int lastIndexOf(final char ch) { 2404 return lastIndexOf(ch, size - 1); 2405 } 2406 2407 /** 2408 * Searches the string builder to find the last reference to the specified char. 2409 * 2410 * @param ch the character to find 2411 * @param startIndex the index to start at, invalid index rounded to edge 2412 * @return The last index of the character, or -1 if not found 2413 */ 2414 public int lastIndexOf(final char ch, int startIndex) { 2415 startIndex = startIndex >= size ? size - 1 : startIndex; 2416 if (startIndex < 0) { 2417 return StringUtils.INDEX_NOT_FOUND; 2418 } 2419 for (int i = startIndex; i >= 0; i--) { 2420 if (buffer[i] == ch) { 2421 return i; 2422 } 2423 } 2424 return StringUtils.INDEX_NOT_FOUND; 2425 } 2426 2427 /** 2428 * Searches the string builder to find the last reference to the specified string. 2429 * <p> 2430 * Note that a null input string will return -1, whereas the JDK throws an exception. 2431 * </p> 2432 * 2433 * @param str the string to find, null returns -1 2434 * @return The last index of the string, or -1 if not found 2435 */ 2436 public int lastIndexOf(final String str) { 2437 return lastIndexOf(str, size - 1); 2438 } 2439 2440 /** 2441 * Searches the string builder to find the last reference to the specified string starting searching from the given 2442 * index. 2443 * <p> 2444 * Note that a null input string will return -1, whereas the JDK throws an exception. 2445 * </p> 2446 * 2447 * @param str the string to find, null returns -1 2448 * @param startIndex the index to start at, invalid index rounded to edge 2449 * @return The last index of the string, or -1 if not found 2450 */ 2451 public int lastIndexOf(final String str, int startIndex) { 2452 startIndex = startIndex >= size ? size - 1 : startIndex; 2453 if (str == null || startIndex < 0) { 2454 return StringUtils.INDEX_NOT_FOUND; 2455 } 2456 final int strLen = str.length(); 2457 if (strLen > 0 && strLen <= size) { 2458 if (strLen == 1) { 2459 return lastIndexOf(str.charAt(0), startIndex); 2460 } 2461 2462 outer: for (int i = startIndex - strLen + 1; i >= 0; i--) { 2463 for (int j = 0; j < strLen; j++) { 2464 if (str.charAt(j) != buffer[i + j]) { 2465 continue outer; 2466 } 2467 } 2468 return i; 2469 } 2470 2471 } else if (strLen == 0) { 2472 return startIndex; 2473 } 2474 return StringUtils.INDEX_NOT_FOUND; 2475 } 2476 2477 /** 2478 * Searches the string builder using the matcher to find the last match. 2479 * <p> 2480 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2481 * character 'a' followed by a number. 2482 * </p> 2483 * 2484 * @param matcher the matcher to use, null returns -1 2485 * @return The last index matched, or -1 if not found 2486 */ 2487 public int lastIndexOf(final StringMatcher matcher) { 2488 return lastIndexOf(matcher, size); 2489 } 2490 2491 /** 2492 * Searches the string builder using the matcher to find the last match searching from the given index. 2493 * <p> 2494 * Matchers can be used to perform advanced searching behavior. For example you could write a matcher to find the 2495 * character 'a' followed by a number. 2496 * </p> 2497 * 2498 * @param matcher the matcher to use, null returns -1 2499 * @param startIndex the index to start at, invalid index rounded to edge 2500 * @return The last index matched, or -1 if not found 2501 */ 2502 public int lastIndexOf(final StringMatcher matcher, int startIndex) { 2503 startIndex = startIndex >= size ? size - 1 : startIndex; 2504 if (matcher == null || startIndex < 0) { 2505 return StringUtils.INDEX_NOT_FOUND; 2506 } 2507 final char[] buf = buffer; 2508 final int endIndex = startIndex + 1; 2509 for (int i = startIndex; i >= 0; i--) { 2510 if (matcher.isMatch(buf, i, 0, endIndex) > 0) { 2511 return i; 2512 } 2513 } 2514 return StringUtils.INDEX_NOT_FOUND; 2515 } 2516 2517 /** 2518 * Extracts the leftmost characters from the string builder without throwing an exception. 2519 * <p> 2520 * This method extracts the left {@code length} characters from the builder. If this many characters are not 2521 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2522 * </p> 2523 * 2524 * @param length the number of characters to extract, negative returns empty string 2525 * @return The new string 2526 */ 2527 public String leftString(final int length) { 2528 if (length <= 0) { 2529 return StringUtils.EMPTY; 2530 } 2531 if (length >= size) { 2532 return new String(buffer, 0, size); 2533 } 2534 return new String(buffer, 0, length); 2535 } 2536 2537 /** 2538 * Gets the length of the string builder. 2539 * 2540 * @return The length 2541 */ 2542 @Override 2543 public int length() { 2544 return size; 2545 } 2546 2547 /** 2548 * Extracts some characters from the middle of the string builder without throwing an exception. 2549 * <p> 2550 * This method extracts {@code length} characters from the builder at the specified index. If the index is negative 2551 * it is treated as zero. If the index is greater than the builder size, it is treated as the builder size. If the 2552 * length is negative, the empty string is returned. If insufficient characters are available in the builder, as 2553 * much as possible is returned. Thus the returned string may be shorter than the length requested. 2554 * </p> 2555 * 2556 * @param index the index to start at, negative means zero 2557 * @param length the number of characters to extract, negative returns empty string 2558 * @return The new string 2559 */ 2560 public String midString(int index, final int length) { 2561 if (index < 0) { 2562 index = 0; 2563 } 2564 if (length <= 0 || index >= size) { 2565 return StringUtils.EMPTY; 2566 } 2567 if (size <= index + length) { 2568 return new String(buffer, index, size - index); 2569 } 2570 return new String(buffer, index, length); 2571 } 2572 2573 /** 2574 * Minimizes the capacity to the actual length of the string. 2575 * 2576 * @return this, to enable chaining 2577 */ 2578 public TextStringBuilder minimizeCapacity() { 2579 if (buffer.length > size) { 2580 reallocate(size); 2581 } 2582 return this; 2583 } 2584 2585 /** 2586 * If possible, reads chars from the provided {@link CharBuffer} directly into underlying character buffer without 2587 * making extra copies. 2588 * 2589 * @param charBuffer CharBuffer to read. 2590 * @return The number of characters read. 2591 * 2592 * @see #appendTo(Appendable) 2593 * @since 1.9 2594 */ 2595 public int readFrom(final CharBuffer charBuffer) { 2596 final int oldSize = size; 2597 final int remaining = charBuffer.remaining(); 2598 ensureCapacityInternal(size + remaining); 2599 charBuffer.get(buffer, size, remaining); 2600 size += remaining; 2601 return size - oldSize; 2602 } 2603 2604 /** 2605 * If possible, reads all chars from the provided {@link Readable} directly into underlying character buffer without 2606 * making extra copies. 2607 * 2608 * @param readable object to read from 2609 * @return The number of characters read 2610 * @throws IOException if an I/O error occurs. 2611 * 2612 * @see #appendTo(Appendable) 2613 */ 2614 public int readFrom(final Readable readable) throws IOException { 2615 if (readable instanceof Reader) { 2616 return readFrom((Reader) readable); 2617 } 2618 if (readable instanceof CharBuffer) { 2619 return readFrom((CharBuffer) readable); 2620 } 2621 final int oldSize = size; 2622 while (true) { 2623 ensureCapacityInternal(size + 1); 2624 final CharBuffer buf = CharBuffer.wrap(buffer, size, buffer.length - size); 2625 final int read = readable.read(buf); 2626 if (read == EOS) { 2627 break; 2628 } 2629 size += read; 2630 } 2631 return size - oldSize; 2632 } 2633 2634 /** 2635 * If possible, reads all chars from the provided {@link Reader} directly into underlying character buffer without 2636 * making extra copies. 2637 * 2638 * @param reader Reader to read. 2639 * @return The number of characters read or -1 if we reached the end of stream. 2640 * @throws IOException if an I/O error occurs. 2641 * 2642 * @see #appendTo(Appendable) 2643 * @since 1.9 2644 */ 2645 public int readFrom(final Reader reader) throws IOException { 2646 final int oldSize = size; 2647 ensureCapacityInternal(size + 1); 2648 int readCount = reader.read(buffer, size, buffer.length - size); 2649 if (readCount == EOS) { 2650 return EOS; 2651 } 2652 do { 2653 size += readCount; 2654 ensureCapacityInternal(size + 1); 2655 readCount = reader.read(buffer, size, buffer.length - size); 2656 } while (readCount != EOS); 2657 return size - oldSize; 2658 } 2659 2660 /** 2661 * If possible, reads {@code count} chars from the provided {@link Reader} directly into underlying character buffer 2662 * without making extra copies. 2663 * 2664 * @param reader Reader to read. 2665 * @param count The maximum characters to read, a value <= 0 returns 0. 2666 * @return The number of characters read. If less than {@code count}, then we've reached the end-of-stream, or -1 if 2667 * we reached the end of stream. 2668 * @throws IOException if an I/O error occurs. 2669 * @see #appendTo(Appendable) 2670 * @since 1.9 2671 */ 2672 public int readFrom(final Reader reader, final int count) throws IOException { 2673 if (count <= 0) { 2674 return 0; 2675 } 2676 final int oldSize = size; 2677 ensureCapacityInternal(size + count); 2678 int target = count; 2679 int readCount = reader.read(buffer, size, target); 2680 if (readCount == EOS) { 2681 return EOS; 2682 } 2683 do { 2684 target -= readCount; 2685 size += readCount; 2686 readCount = reader.read(buffer, size, target); 2687 } while (target > 0 && readCount != EOS); 2688 return size - oldSize; 2689 } 2690 2691 /** 2692 * Reallocates the buffer to the new length. 2693 * 2694 * @param newLength the length of the copy to be returned 2695 */ 2696 private void reallocate(final int newLength) { 2697 this.buffer = Arrays.copyOf(buffer, newLength); 2698 this.reallocations++; 2699 } 2700 2701 /** 2702 * Replaces a portion of the string builder with another string. The length of the inserted string does not have to 2703 * match the removed length. 2704 * 2705 * @param startIndex the start index, inclusive, must be valid 2706 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2707 * @param replaceStr the string to replace with, null means delete range 2708 * @return this, to enable chaining 2709 * @throws IndexOutOfBoundsException if the index is invalid 2710 */ 2711 public TextStringBuilder replace(final int startIndex, int endIndex, final String replaceStr) { 2712 endIndex = validateRange(startIndex, endIndex); 2713 final int insertLen = replaceStr == null ? 0 : replaceStr.length(); 2714 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); 2715 return this; 2716 } 2717 2718 /** 2719 * Advanced search and replaces within the builder using a matcher. 2720 * <p> 2721 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2722 * occurrences where the character 'a' is followed by a number. 2723 * </p> 2724 * 2725 * @param matcher the matcher to use to find the deletion, null causes no action 2726 * @param replaceStr the string to replace the match with, null is a delete 2727 * @param startIndex the start index, inclusive, must be valid 2728 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 2729 * @param replaceCount the number of times to replace, -1 for replace all 2730 * @return this, to enable chaining 2731 * @throws IndexOutOfBoundsException if start index is invalid 2732 */ 2733 public TextStringBuilder replace(final StringMatcher matcher, final String replaceStr, final int startIndex, 2734 int endIndex, final int replaceCount) { 2735 endIndex = validateRange(startIndex, endIndex); 2736 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); 2737 } 2738 2739 /** 2740 * Replaces the search character with the replace character throughout the builder. 2741 * 2742 * @param search the search character 2743 * @param replace the replace character 2744 * @return this, to enable chaining 2745 */ 2746 public TextStringBuilder replaceAll(final char search, final char replace) { 2747 if (search != replace) { 2748 for (int i = 0; i < size; i++) { 2749 if (buffer[i] == search) { 2750 buffer[i] = replace; 2751 } 2752 } 2753 } 2754 return this; 2755 } 2756 2757 /** 2758 * Replaces the search string with the replace string throughout the builder. 2759 * 2760 * @param searchStr the search string, null causes no action to occur 2761 * @param replaceStr the replace string, null is equivalent to an empty string 2762 * @return this, to enable chaining 2763 */ 2764 public TextStringBuilder replaceAll(final String searchStr, final String replaceStr) { 2765 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2766 if (searchLen > 0) { 2767 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2768 int index = indexOf(searchStr, 0); 2769 while (index >= 0) { 2770 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2771 index = indexOf(searchStr, index + replaceLen); 2772 } 2773 } 2774 return this; 2775 } 2776 2777 /** 2778 * Replaces all matches within the builder with the replace string. 2779 * <p> 2780 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace all 2781 * occurrences where the character 'a' is followed by a number. 2782 * </p> 2783 * 2784 * @param matcher the matcher to use to find the deletion, null causes no action 2785 * @param replaceStr the replace string, null is equivalent to an empty string 2786 * @return this, to enable chaining 2787 */ 2788 public TextStringBuilder replaceAll(final StringMatcher matcher, final String replaceStr) { 2789 return replace(matcher, replaceStr, 0, size, -1); 2790 } 2791 2792 /** 2793 * Replaces the first instance of the search character with the replace character in the builder. 2794 * 2795 * @param search the search character 2796 * @param replace the replace character 2797 * @return this, to enable chaining 2798 */ 2799 public TextStringBuilder replaceFirst(final char search, final char replace) { 2800 if (search != replace) { 2801 for (int i = 0; i < size; i++) { 2802 if (buffer[i] == search) { 2803 buffer[i] = replace; 2804 break; 2805 } 2806 } 2807 } 2808 return this; 2809 } 2810 2811 /** 2812 * Replaces the first instance of the search string with the replace string. 2813 * 2814 * @param searchStr the search string, null causes no action to occur 2815 * @param replaceStr the replace string, null is equivalent to an empty string 2816 * @return this, to enable chaining 2817 */ 2818 public TextStringBuilder replaceFirst(final String searchStr, final String replaceStr) { 2819 final int searchLen = searchStr == null ? 0 : searchStr.length(); 2820 if (searchLen > 0) { 2821 final int index = indexOf(searchStr, 0); 2822 if (index >= 0) { 2823 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2824 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 2825 } 2826 } 2827 return this; 2828 } 2829 2830 /** 2831 * Replaces the first match within the builder with the replace string. 2832 * <p> 2833 * Matchers can be used to perform advanced replace behavior. For example you could write a matcher to replace where 2834 * the character 'a' is followed by a number. 2835 * </p> 2836 * 2837 * @param matcher the matcher to use to find the deletion, null causes no action 2838 * @param replaceStr the replace string, null is equivalent to an empty string 2839 * @return this, to enable chaining 2840 */ 2841 public TextStringBuilder replaceFirst(final StringMatcher matcher, final String replaceStr) { 2842 return replace(matcher, replaceStr, 0, size, 1); 2843 } 2844 2845 /** 2846 * Internal method to delete a range without validation. 2847 * 2848 * @param startIndex the start index, must be valid 2849 * @param endIndex the end index (exclusive), must be valid 2850 * @param removeLen the length to remove (endIndex - startIndex), must be valid 2851 * @param insertStr the string to replace with, null means delete range 2852 * @param insertLen the length of the insert string, must be valid 2853 * @throws IndexOutOfBoundsException if any index is invalid 2854 */ 2855 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, 2856 final int insertLen) { 2857 final int newSize = size - removeLen + insertLen; 2858 if (insertLen != removeLen) { 2859 ensureCapacityInternal(newSize); 2860 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); 2861 size = newSize; 2862 } 2863 if (insertLen > 0) { 2864 insertStr.getChars(0, insertLen, buffer, startIndex); 2865 } 2866 } 2867 2868 /** 2869 * Replaces within the builder using a matcher. 2870 * <p> 2871 * Matchers can be used to perform advanced behavior. For example you could write a matcher to delete all 2872 * occurrences where the character 'a' is followed by a number. 2873 * </p> 2874 * 2875 * @param matcher the matcher to use to find the deletion, null causes no action 2876 * @param replaceStr the string to replace the match with, null is a delete 2877 * @param from the start index, must be valid 2878 * @param to the end index (exclusive), must be valid 2879 * @param replaceCount the number of times to replace, -1 for replace all 2880 * @return this, to enable chaining 2881 * @throws IndexOutOfBoundsException if any index is invalid 2882 */ 2883 private TextStringBuilder replaceImpl(final StringMatcher matcher, final String replaceStr, final int from, int to, 2884 int replaceCount) { 2885 if (matcher == null || size == 0) { 2886 return this; 2887 } 2888 final int replaceLen = replaceStr == null ? 0 : replaceStr.length(); 2889 for (int i = from; i < to && replaceCount != 0; i++) { 2890 final char[] buf = buffer; 2891 final int removeLen = matcher.isMatch(buf, i, from, to); 2892 if (removeLen > 0) { 2893 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); 2894 to = to - removeLen + replaceLen; 2895 i = i + replaceLen - 1; 2896 if (replaceCount > 0) { 2897 replaceCount--; 2898 } 2899 } 2900 } 2901 return this; 2902 } 2903 2904 /** 2905 * Resizes the buffer to at least the size specified. 2906 * 2907 * @param minCapacity the minimum required capacity 2908 * @throws OutOfMemoryError if the {@code minCapacity} is negative 2909 */ 2910 private void resizeBuffer(final int minCapacity) { 2911 // Overflow-conscious code treats the min and new capacity as unsigned. 2912 final int oldCapacity = buffer.length; 2913 int newCapacity = oldCapacity * 2; 2914 if (Integer.compareUnsigned(newCapacity, minCapacity) < 0) { 2915 newCapacity = minCapacity; 2916 } 2917 if (Integer.compareUnsigned(newCapacity, MAX_BUFFER_SIZE) > 0) { 2918 newCapacity = createPositiveCapacity(minCapacity); 2919 } 2920 reallocate(newCapacity); 2921 } 2922 2923 /** 2924 * Reverses the string builder placing each character in the opposite index. 2925 * 2926 * @return this, to enable chaining 2927 */ 2928 public TextStringBuilder reverse() { 2929 if (size == 0) { 2930 return this; 2931 } 2932 2933 final int half = size / 2; 2934 final char[] buf = buffer; 2935 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++, rightIdx--) { 2936 final char swap = buf[leftIdx]; 2937 buf[leftIdx] = buf[rightIdx]; 2938 buf[rightIdx] = swap; 2939 } 2940 return this; 2941 } 2942 2943 /** 2944 * Extracts the rightmost characters from the string builder without throwing an exception. 2945 * <p> 2946 * This method extracts the right {@code length} characters from the builder. If this many characters are not 2947 * available, the whole builder is returned. Thus the returned string may be shorter than the length requested. 2948 * </p> 2949 * 2950 * @param length the number of characters to extract, negative returns empty string 2951 * @return The new string 2952 */ 2953 public String rightString(final int length) { 2954 if (length <= 0) { 2955 return StringUtils.EMPTY; 2956 } 2957 if (length >= size) { 2958 return new String(buffer, 0, size); 2959 } 2960 return new String(buffer, size - length, length); 2961 } 2962 2963 /** 2964 * Clears and sets this builder to the given value. 2965 * 2966 * @see #charAt(int) 2967 * @see #deleteCharAt(int) 2968 * @param str the new value. 2969 * @return this, to enable chaining 2970 * @since 1.9 2971 */ 2972 public TextStringBuilder set(final CharSequence str) { 2973 clear(); 2974 append(str); 2975 return this; 2976 } 2977 2978 /** 2979 * Sets the character at the specified index. 2980 * 2981 * @see #charAt(int) 2982 * @see #deleteCharAt(int) 2983 * @param index the index to set 2984 * @param ch the new character 2985 * @return this, to enable chaining 2986 * @throws IndexOutOfBoundsException if the index is invalid 2987 */ 2988 public TextStringBuilder setCharAt(final int index, final char ch) { 2989 validateIndex(index); 2990 buffer[index] = ch; 2991 return this; 2992 } 2993 2994 /** 2995 * Updates the length of the builder by either dropping the last characters or adding filler of Unicode zero. 2996 * 2997 * @param length the length to set to, must be zero or positive 2998 * @return this, to enable chaining 2999 * @throws IndexOutOfBoundsException if the length is negative 3000 */ 3001 public TextStringBuilder setLength(final int length) { 3002 if (length < 0) { 3003 throw new StringIndexOutOfBoundsException(length); 3004 } 3005 if (length < size) { 3006 size = length; 3007 } else if (length > size) { 3008 ensureCapacityInternal(length); 3009 final int oldEnd = size; 3010 size = length; 3011 Arrays.fill(buffer, oldEnd, length, '\0'); 3012 } 3013 return this; 3014 } 3015 3016 /** 3017 * Sets the text to be appended when a new line is added. 3018 * 3019 * @param newLine the new line text, null means use system default 3020 * @return this, to enable chaining 3021 */ 3022 public TextStringBuilder setNewLineText(final String newLine) { 3023 this.newLine = newLine; 3024 return this; 3025 } 3026 3027 /** 3028 * Sets the text to be appended when null is added. 3029 * 3030 * @param nullText the null text, null means no append 3031 * @return this, to enable chaining 3032 */ 3033 public TextStringBuilder setNullText(String nullText) { 3034 if (nullText != null && nullText.isEmpty()) { 3035 nullText = null; 3036 } 3037 this.nullText = nullText; 3038 return this; 3039 } 3040 3041 /** 3042 * Gets the length of the string builder. 3043 * <p> 3044 * This method is the same as {@link #length()} and is provided to match the API of Collections. 3045 * </p> 3046 * 3047 * @return The length 3048 */ 3049 public int size() { 3050 return size; 3051 } 3052 3053 /** 3054 * Checks whether this builder starts with the specified string. 3055 * <p> 3056 * Note that this method handles null input quietly, unlike String. 3057 * </p> 3058 * 3059 * @param str the string to search for, null returns false 3060 * @return true if the builder starts with the string 3061 */ 3062 public boolean startsWith(final String str) { 3063 if (str == null) { 3064 return false; 3065 } 3066 final int len = str.length(); 3067 if (len == 0) { 3068 return true; 3069 } 3070 if (len > size) { 3071 return false; 3072 } 3073 for (int i = 0; i < len; i++) { 3074 if (buffer[i] != str.charAt(i)) { 3075 return false; 3076 } 3077 } 3078 return true; 3079 } 3080 3081 /** 3082 * {@inheritDoc} 3083 */ 3084 @Override 3085 public CharSequence subSequence(final int startIndex, final int endIndex) { 3086 if (startIndex < 0) { 3087 throw new StringIndexOutOfBoundsException(startIndex); 3088 } 3089 if (endIndex > size) { 3090 throw new StringIndexOutOfBoundsException(endIndex); 3091 } 3092 if (startIndex > endIndex) { 3093 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 3094 } 3095 return substring(startIndex, endIndex); 3096 } 3097 3098 /** 3099 * Extracts a portion of this string builder as a string. 3100 * 3101 * @param start the start index, inclusive, must be valid 3102 * @return The new string 3103 * @throws IndexOutOfBoundsException if the index is invalid 3104 */ 3105 public String substring(final int start) { 3106 return substring(start, size); 3107 } 3108 3109 /** 3110 * Extracts a portion of this string builder as a string. 3111 * <p> 3112 * Note: This method treats an endIndex greater than the length of the builder as equal to the length of the 3113 * builder, and continues without error, unlike StringBuffer or String. 3114 * </p> 3115 * 3116 * @param startIndex the start index, inclusive, must be valid 3117 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3118 * @return The new string 3119 * @throws IndexOutOfBoundsException if the index is invalid 3120 */ 3121 public String substring(final int startIndex, int endIndex) { 3122 endIndex = validateRange(startIndex, endIndex); 3123 return new String(buffer, startIndex, endIndex - startIndex); 3124 } 3125 3126 /** 3127 * Copies the builder's character array into a new character array. 3128 * 3129 * @return a new array that represents the contents of the builder 3130 */ 3131 public char[] toCharArray() { 3132 return size == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOf(buffer, size); 3133 } 3134 3135 /** 3136 * Copies part of the builder's character array into a new character array. 3137 * 3138 * @param startIndex the start index, inclusive, must be valid 3139 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3140 * @return a new array that holds part of the contents of the builder 3141 * @throws IndexOutOfBoundsException if startIndex is invalid, or if endIndex is invalid (but endIndex greater than 3142 * size is valid) 3143 */ 3144 public char[] toCharArray(final int startIndex, int endIndex) { 3145 endIndex = validateRange(startIndex, endIndex); 3146 final int len = endIndex - startIndex; 3147 return len == 0 ? ArrayUtils.EMPTY_CHAR_ARRAY : Arrays.copyOfRange(buffer, startIndex, endIndex); 3148 } 3149 3150 /** 3151 * Gets a String version of the string builder, creating a new instance each time the method is called. 3152 * <p> 3153 * Note that unlike StringBuffer, the string version returned is independent of the string builder. 3154 * </p> 3155 * 3156 * @return The builder as a String 3157 */ 3158 @Override 3159 public String toString() { 3160 return new String(buffer, 0, size); 3161 } 3162 3163 /** 3164 * Gets a StringBuffer version of the string builder, creating a new instance each time the method is called. 3165 * 3166 * @return The builder as a StringBuffer 3167 */ 3168 public StringBuffer toStringBuffer() { 3169 return new StringBuffer(size).append(buffer, 0, size); 3170 } 3171 3172 /** 3173 * Gets a StringBuilder version of the string builder, creating a new instance each time the method is called. 3174 * 3175 * @return The builder as a StringBuilder 3176 */ 3177 public StringBuilder toStringBuilder() { 3178 return new StringBuilder(size).append(buffer, 0, size); 3179 } 3180 3181 /** 3182 * Trims the builder by removing characters less than or equal to a space from the beginning and end. 3183 * 3184 * @return this, to enable chaining 3185 */ 3186 public TextStringBuilder trim() { 3187 if (size == 0) { 3188 return this; 3189 } 3190 int len = size; 3191 final char[] buf = buffer; 3192 int pos = 0; 3193 while (pos < len && buf[pos] <= SPACE) { 3194 pos++; 3195 } 3196 while (pos < len && buf[len - 1] <= SPACE) { 3197 len--; 3198 } 3199 if (len < size) { 3200 delete(len, size); 3201 } 3202 if (pos > 0) { 3203 delete(0, pos); 3204 } 3205 return this; 3206 } 3207 3208 /** 3209 * Validates that an index is in the range {@code 0 <= index <= size}. 3210 * 3211 * @param index the index to test. 3212 * @throws IndexOutOfBoundsException Thrown when the index is not the range {@code 0 <= index <= size}. 3213 */ 3214 protected void validateIndex(final int index) { 3215 if (index < 0 || index >= size) { 3216 throw new StringIndexOutOfBoundsException(index); 3217 } 3218 } 3219 3220 /** 3221 * Validates parameters defining a range of the builder. 3222 * 3223 * @param startIndex the start index, inclusive, must be valid 3224 * @param endIndex the end index, exclusive, must be valid except that if too large it is treated as end of string 3225 * @return A valid end index. 3226 * @throws StringIndexOutOfBoundsException if the index is invalid 3227 */ 3228 protected int validateRange(final int startIndex, int endIndex) { 3229 if (startIndex < 0) { 3230 throw new StringIndexOutOfBoundsException(startIndex); 3231 } 3232 if (endIndex > size) { 3233 endIndex = size; 3234 } 3235 if (startIndex > endIndex) { 3236 throw new StringIndexOutOfBoundsException("end < start"); 3237 } 3238 return endIndex; 3239 } 3240 3241}