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