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