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