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