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