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