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