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 * <ul> 036 * <li>Not synchronized</li> 037 * <li>Not final</li> 038 * <li>Subclasses have direct access to character array</li> 039 * <li>Additional methods 040 * <ul> 041 * <li>appendWithSeparators - adds an array of values, with a separator</li> 042 * <li>appendPadding - adds a length padding characters</li> 043 * <li>appendFixedLength - adds a fixed width field to the builder</li> 044 * <li>toCharArray/getChars - simpler ways to get a range of the character array</li> 045 * <li>delete - delete char or string</li> 046 * <li>replace - search and replace for a char or string</li> 047 * <li>leftString/rightString/midString - substring without exceptions</li> 048 * <li>contains - whether the builder contains a char or string</li> 049 * <li>size/clear/isEmpty - collections style API methods</li> 050 * </ul> 051 * </li> 052 * </ul> 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 1557584 2014-01-12 18:26:49Z britter $ 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 * <pre> 1306 * for (int i = 0; i < list.size(); i++) { 1307 * appendSeparator(",", i); 1308 * append(list.get(i)); 1309 * } 1310 * </pre> 1311 * Note that for this simple example, you should use 1312 * {@link #appendWithSeparators(Iterable, String)}. 1313 * 1314 * @param separator the separator to use, null means no separator 1315 * @param loopIndex the loop index 1316 * @return this, to enable chaining 1317 * @since 2.3 1318 */ 1319 public StrBuilder appendSeparator(final String separator, final int loopIndex) { 1320 if (separator != null && loopIndex > 0) { 1321 append(separator); 1322 } 1323 return this; 1324 } 1325 1326 /** 1327 * Appends a separator to the builder if the loop index is greater than zero. 1328 * The separator is appended using {@link #append(char)}. 1329 * <p> 1330 * This method is useful for adding a separator each time around the 1331 * loop except the first. 1332 * <pre> 1333 * for (int i = 0; i < list.size(); i++) { 1334 * appendSeparator(",", i); 1335 * append(list.get(i)); 1336 * } 1337 * </pre> 1338 * Note that for this simple example, you should use 1339 * {@link #appendWithSeparators(Iterable, String)}. 1340 * 1341 * @param separator the separator to use 1342 * @param loopIndex the loop index 1343 * @return this, to enable chaining 1344 * @since 2.3 1345 */ 1346 public StrBuilder appendSeparator(final char separator, final int loopIndex) { 1347 if (loopIndex > 0) { 1348 append(separator); 1349 } 1350 return this; 1351 } 1352 1353 //----------------------------------------------------------------------- 1354 /** 1355 * Appends the pad character to the builder the specified number of times. 1356 * 1357 * @param length the length to append, negative means no append 1358 * @param padChar the character to append 1359 * @return this, to enable chaining 1360 */ 1361 public StrBuilder appendPadding(final int length, final char padChar) { 1362 if (length >= 0) { 1363 ensureCapacity(size + length); 1364 for (int i = 0; i < length; i++) { 1365 buffer[size++] = padChar; 1366 } 1367 } 1368 return this; 1369 } 1370 1371 //----------------------------------------------------------------------- 1372 /** 1373 * Appends an object to the builder padding on the left to a fixed width. 1374 * The <code>toString</code> of the object is used. 1375 * If the object is larger than the length, the left hand side is lost. 1376 * If the object is null, the null text value is used. 1377 * 1378 * @param obj the object to append, null uses null text 1379 * @param width the fixed field width, zero or negative has no effect 1380 * @param padChar the pad character to use 1381 * @return this, to enable chaining 1382 */ 1383 public StrBuilder appendFixedWidthPadLeft(final Object obj, final int width, final char padChar) { 1384 if (width > 0) { 1385 ensureCapacity(size + width); 1386 String str = (obj == null ? getNullText() : obj.toString()); 1387 if (str == null) { 1388 str = ""; 1389 } 1390 final int strLen = str.length(); 1391 if (strLen >= width) { 1392 str.getChars(strLen - width, strLen, buffer, size); 1393 } else { 1394 final int padLen = width - strLen; 1395 for (int i = 0; i < padLen; i++) { 1396 buffer[size + i] = padChar; 1397 } 1398 str.getChars(0, strLen, buffer, size + padLen); 1399 } 1400 size += width; 1401 } 1402 return this; 1403 } 1404 1405 /** 1406 * Appends an object to the builder padding on the left to a fixed width. 1407 * The <code>String.valueOf</code> of the <code>int</code> value is used. 1408 * If the formatted value is larger than the length, the left hand side is lost. 1409 * 1410 * @param value the value to append 1411 * @param width the fixed field width, zero or negative has no effect 1412 * @param padChar the pad character to use 1413 * @return this, to enable chaining 1414 */ 1415 public StrBuilder appendFixedWidthPadLeft(final int value, final int width, final char padChar) { 1416 return appendFixedWidthPadLeft(String.valueOf(value), width, padChar); 1417 } 1418 1419 /** 1420 * Appends an object to the builder padding on the right to a fixed length. 1421 * The <code>toString</code> of the object is used. 1422 * If the object is larger than the length, the right hand side is lost. 1423 * If the object is null, null text value is used. 1424 * 1425 * @param obj the object to append, null uses null text 1426 * @param width the fixed field width, zero or negative has no effect 1427 * @param padChar the pad character to use 1428 * @return this, to enable chaining 1429 */ 1430 public StrBuilder appendFixedWidthPadRight(final Object obj, final int width, final char padChar) { 1431 if (width > 0) { 1432 ensureCapacity(size + width); 1433 String str = (obj == null ? getNullText() : obj.toString()); 1434 if (str == null) { 1435 str = ""; 1436 } 1437 final int strLen = str.length(); 1438 if (strLen >= width) { 1439 str.getChars(0, width, buffer, size); 1440 } else { 1441 final int padLen = width - strLen; 1442 str.getChars(0, strLen, buffer, size); 1443 for (int i = 0; i < padLen; i++) { 1444 buffer[size + strLen + i] = padChar; 1445 } 1446 } 1447 size += width; 1448 } 1449 return this; 1450 } 1451 1452 /** 1453 * Appends an object to the builder padding on the right to a fixed length. 1454 * The <code>String.valueOf</code> of the <code>int</code> value is used. 1455 * If the object is larger than the length, the right hand side is lost. 1456 * 1457 * @param value the value to append 1458 * @param width the fixed field width, zero or negative has no effect 1459 * @param padChar the pad character to use 1460 * @return this, to enable chaining 1461 */ 1462 public StrBuilder appendFixedWidthPadRight(final int value, final int width, final char padChar) { 1463 return appendFixedWidthPadRight(String.valueOf(value), width, padChar); 1464 } 1465 1466 //----------------------------------------------------------------------- 1467 /** 1468 * Inserts the string representation of an object into this builder. 1469 * Inserting null will use the stored null text value. 1470 * 1471 * @param index the index to add at, must be valid 1472 * @param obj the object to insert 1473 * @return this, to enable chaining 1474 * @throws IndexOutOfBoundsException if the index is invalid 1475 */ 1476 public StrBuilder insert(final int index, final Object obj) { 1477 if (obj == null) { 1478 return insert(index, nullText); 1479 } 1480 return insert(index, obj.toString()); 1481 } 1482 1483 /** 1484 * Inserts the string into this builder. 1485 * Inserting null will use the stored null text value. 1486 * 1487 * @param index the index to add at, must be valid 1488 * @param str the string to insert 1489 * @return this, to enable chaining 1490 * @throws IndexOutOfBoundsException if the index is invalid 1491 */ 1492 public StrBuilder insert(final int index, String str) { 1493 validateIndex(index); 1494 if (str == null) { 1495 str = nullText; 1496 } 1497 if (str != null) { 1498 final int strLen = str.length(); 1499 if (strLen > 0) { 1500 final int newSize = size + strLen; 1501 ensureCapacity(newSize); 1502 System.arraycopy(buffer, index, buffer, index + strLen, size - index); 1503 size = newSize; 1504 str.getChars(0, strLen, buffer, index); 1505 } 1506 } 1507 return this; 1508 } 1509 1510 /** 1511 * Inserts the character array into this builder. 1512 * Inserting null will use the stored null text value. 1513 * 1514 * @param index the index to add at, must be valid 1515 * @param chars the char array to insert 1516 * @return this, to enable chaining 1517 * @throws IndexOutOfBoundsException if the index is invalid 1518 */ 1519 public StrBuilder insert(final int index, final char chars[]) { 1520 validateIndex(index); 1521 if (chars == null) { 1522 return insert(index, nullText); 1523 } 1524 final int len = chars.length; 1525 if (len > 0) { 1526 ensureCapacity(size + len); 1527 System.arraycopy(buffer, index, buffer, index + len, size - index); 1528 System.arraycopy(chars, 0, buffer, index, len); 1529 size += len; 1530 } 1531 return this; 1532 } 1533 1534 /** 1535 * Inserts part of the character array into this builder. 1536 * Inserting null will use the stored null text value. 1537 * 1538 * @param index the index to add at, must be valid 1539 * @param chars the char array to insert 1540 * @param offset the offset into the character array to start at, must be valid 1541 * @param length the length of the character array part to copy, must be positive 1542 * @return this, to enable chaining 1543 * @throws IndexOutOfBoundsException if any index is invalid 1544 */ 1545 public StrBuilder insert(final int index, final char chars[], final int offset, final int length) { 1546 validateIndex(index); 1547 if (chars == null) { 1548 return insert(index, nullText); 1549 } 1550 if (offset < 0 || offset > chars.length) { 1551 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); 1552 } 1553 if (length < 0 || offset + length > chars.length) { 1554 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 1555 } 1556 if (length > 0) { 1557 ensureCapacity(size + length); 1558 System.arraycopy(buffer, index, buffer, index + length, size - index); 1559 System.arraycopy(chars, offset, buffer, index, length); 1560 size += length; 1561 } 1562 return this; 1563 } 1564 1565 /** 1566 * Inserts the value into this builder. 1567 * 1568 * @param index the index to add at, must be valid 1569 * @param value the value to insert 1570 * @return this, to enable chaining 1571 * @throws IndexOutOfBoundsException if the index is invalid 1572 */ 1573 public StrBuilder insert(int index, final boolean value) { 1574 validateIndex(index); 1575 if (value) { 1576 ensureCapacity(size + 4); 1577 System.arraycopy(buffer, index, buffer, index + 4, size - index); 1578 buffer[index++] = 't'; 1579 buffer[index++] = 'r'; 1580 buffer[index++] = 'u'; 1581 buffer[index] = 'e'; 1582 size += 4; 1583 } else { 1584 ensureCapacity(size + 5); 1585 System.arraycopy(buffer, index, buffer, index + 5, size - index); 1586 buffer[index++] = 'f'; 1587 buffer[index++] = 'a'; 1588 buffer[index++] = 'l'; 1589 buffer[index++] = 's'; 1590 buffer[index] = 'e'; 1591 size += 5; 1592 } 1593 return this; 1594 } 1595 1596 /** 1597 * Inserts the value into this builder. 1598 * 1599 * @param index the index to add at, must be valid 1600 * @param value the value to insert 1601 * @return this, to enable chaining 1602 * @throws IndexOutOfBoundsException if the index is invalid 1603 */ 1604 public StrBuilder insert(final int index, final char value) { 1605 validateIndex(index); 1606 ensureCapacity(size + 1); 1607 System.arraycopy(buffer, index, buffer, index + 1, size - index); 1608 buffer[index] = value; 1609 size++; 1610 return this; 1611 } 1612 1613 /** 1614 * Inserts the value into this builder. 1615 * 1616 * @param index the index to add at, must be valid 1617 * @param value the value to insert 1618 * @return this, to enable chaining 1619 * @throws IndexOutOfBoundsException if the index is invalid 1620 */ 1621 public StrBuilder insert(final int index, final int value) { 1622 return insert(index, String.valueOf(value)); 1623 } 1624 1625 /** 1626 * Inserts the value into this builder. 1627 * 1628 * @param index the index to add at, must be valid 1629 * @param value the value to insert 1630 * @return this, to enable chaining 1631 * @throws IndexOutOfBoundsException if the index is invalid 1632 */ 1633 public StrBuilder insert(final int index, final long value) { 1634 return insert(index, String.valueOf(value)); 1635 } 1636 1637 /** 1638 * Inserts the value into this builder. 1639 * 1640 * @param index the index to add at, must be valid 1641 * @param value the value to insert 1642 * @return this, to enable chaining 1643 * @throws IndexOutOfBoundsException if the index is invalid 1644 */ 1645 public StrBuilder insert(final int index, final float value) { 1646 return insert(index, String.valueOf(value)); 1647 } 1648 1649 /** 1650 * Inserts the value into this builder. 1651 * 1652 * @param index the index to add at, must be valid 1653 * @param value the value to insert 1654 * @return this, to enable chaining 1655 * @throws IndexOutOfBoundsException if the index is invalid 1656 */ 1657 public StrBuilder insert(final int index, final double value) { 1658 return insert(index, String.valueOf(value)); 1659 } 1660 1661 //----------------------------------------------------------------------- 1662 /** 1663 * Internal method to delete a range without validation. 1664 * 1665 * @param startIndex the start index, must be valid 1666 * @param endIndex the end index (exclusive), must be valid 1667 * @param len the length, must be valid 1668 * @throws IndexOutOfBoundsException if any index is invalid 1669 */ 1670 private void deleteImpl(final int startIndex, final int endIndex, final int len) { 1671 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); 1672 size -= len; 1673 } 1674 1675 /** 1676 * Deletes the characters between the two specified indices. 1677 * 1678 * @param startIndex the start index, inclusive, must be valid 1679 * @param endIndex the end index, exclusive, must be valid except 1680 * that if too large it is treated as end of string 1681 * @return this, to enable chaining 1682 * @throws IndexOutOfBoundsException if the index is invalid 1683 */ 1684 public StrBuilder delete(final int startIndex, int endIndex) { 1685 endIndex = validateRange(startIndex, endIndex); 1686 final int len = endIndex - startIndex; 1687 if (len > 0) { 1688 deleteImpl(startIndex, endIndex, len); 1689 } 1690 return this; 1691 } 1692 1693 //----------------------------------------------------------------------- 1694 /** 1695 * Deletes the character wherever it occurs in the builder. 1696 * 1697 * @param ch the character to delete 1698 * @return this, to enable chaining 1699 */ 1700 public StrBuilder deleteAll(final char ch) { 1701 for (int i = 0; i < size; i++) { 1702 if (buffer[i] == ch) { 1703 final int start = i; 1704 while (++i < size) { 1705 if (buffer[i] != ch) { 1706 break; 1707 } 1708 } 1709 final int len = i - start; 1710 deleteImpl(start, i, len); 1711 i -= len; 1712 } 1713 } 1714 return this; 1715 } 1716 1717 /** 1718 * Deletes the character wherever it occurs in the builder. 1719 * 1720 * @param ch the character to delete 1721 * @return this, to enable chaining 1722 */ 1723 public StrBuilder deleteFirst(final char ch) { 1724 for (int i = 0; i < size; i++) { 1725 if (buffer[i] == ch) { 1726 deleteImpl(i, i + 1, 1); 1727 break; 1728 } 1729 } 1730 return this; 1731 } 1732 1733 //----------------------------------------------------------------------- 1734 /** 1735 * Deletes the string wherever it occurs in the builder. 1736 * 1737 * @param str the string to delete, null causes no action 1738 * @return this, to enable chaining 1739 */ 1740 public StrBuilder deleteAll(final String str) { 1741 final int len = (str == null ? 0 : str.length()); 1742 if (len > 0) { 1743 int index = indexOf(str, 0); 1744 while (index >= 0) { 1745 deleteImpl(index, index + len, len); 1746 index = indexOf(str, index); 1747 } 1748 } 1749 return this; 1750 } 1751 1752 /** 1753 * Deletes the string wherever it occurs in the builder. 1754 * 1755 * @param str the string to delete, null causes no action 1756 * @return this, to enable chaining 1757 */ 1758 public StrBuilder deleteFirst(final String str) { 1759 final int len = (str == null ? 0 : str.length()); 1760 if (len > 0) { 1761 final int index = indexOf(str, 0); 1762 if (index >= 0) { 1763 deleteImpl(index, index + len, len); 1764 } 1765 } 1766 return this; 1767 } 1768 1769 //----------------------------------------------------------------------- 1770 /** 1771 * Deletes all parts of the builder that the matcher matches. 1772 * <p> 1773 * Matchers can be used to perform advanced deletion behaviour. 1774 * For example you could write a matcher to delete all occurrences 1775 * where the character 'a' is followed by a number. 1776 * 1777 * @param matcher the matcher to use to find the deletion, null causes no action 1778 * @return this, to enable chaining 1779 */ 1780 public StrBuilder deleteAll(final StrMatcher matcher) { 1781 return replace(matcher, null, 0, size, -1); 1782 } 1783 1784 /** 1785 * Deletes the first match within the builder using the specified matcher. 1786 * <p> 1787 * Matchers can be used to perform advanced deletion behaviour. 1788 * For example you could write a matcher to delete 1789 * where the character 'a' is followed by a number. 1790 * 1791 * @param matcher the matcher to use to find the deletion, null causes no action 1792 * @return this, to enable chaining 1793 */ 1794 public StrBuilder deleteFirst(final StrMatcher matcher) { 1795 return replace(matcher, null, 0, size, 1); 1796 } 1797 1798 //----------------------------------------------------------------------- 1799 /** 1800 * Internal method to delete a range without validation. 1801 * 1802 * @param startIndex the start index, must be valid 1803 * @param endIndex the end index (exclusive), must be valid 1804 * @param removeLen the length to remove (endIndex - startIndex), must be valid 1805 * @param insertStr the string to replace with, null means delete range 1806 * @param insertLen the length of the insert string, must be valid 1807 * @throws IndexOutOfBoundsException if any index is invalid 1808 */ 1809 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) { 1810 final int newSize = size - removeLen + insertLen; 1811 if (insertLen != removeLen) { 1812 ensureCapacity(newSize); 1813 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); 1814 size = newSize; 1815 } 1816 if (insertLen > 0) { 1817 insertStr.getChars(0, insertLen, buffer, startIndex); 1818 } 1819 } 1820 1821 /** 1822 * Replaces a portion of the string builder with another string. 1823 * The length of the inserted string does not have to match the removed length. 1824 * 1825 * @param startIndex the start index, inclusive, must be valid 1826 * @param endIndex the end index, exclusive, must be valid except 1827 * that if too large it is treated as end of string 1828 * @param replaceStr the string to replace with, null means delete range 1829 * @return this, to enable chaining 1830 * @throws IndexOutOfBoundsException if the index is invalid 1831 */ 1832 public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) { 1833 endIndex = validateRange(startIndex, endIndex); 1834 final int insertLen = (replaceStr == null ? 0 : replaceStr.length()); 1835 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); 1836 return this; 1837 } 1838 1839 //----------------------------------------------------------------------- 1840 /** 1841 * Replaces the search character with the replace character 1842 * throughout the builder. 1843 * 1844 * @param search the search character 1845 * @param replace the replace character 1846 * @return this, to enable chaining 1847 */ 1848 public StrBuilder replaceAll(final char search, final char replace) { 1849 if (search != replace) { 1850 for (int i = 0; i < size; i++) { 1851 if (buffer[i] == search) { 1852 buffer[i] = replace; 1853 } 1854 } 1855 } 1856 return this; 1857 } 1858 1859 /** 1860 * Replaces the first instance of the search character with the 1861 * replace character in the builder. 1862 * 1863 * @param search the search character 1864 * @param replace the replace character 1865 * @return this, to enable chaining 1866 */ 1867 public StrBuilder replaceFirst(final char search, final char replace) { 1868 if (search != replace) { 1869 for (int i = 0; i < size; i++) { 1870 if (buffer[i] == search) { 1871 buffer[i] = replace; 1872 break; 1873 } 1874 } 1875 } 1876 return this; 1877 } 1878 1879 //----------------------------------------------------------------------- 1880 /** 1881 * Replaces the search string with the replace string throughout the builder. 1882 * 1883 * @param searchStr the search string, null causes no action to occur 1884 * @param replaceStr the replace string, null is equivalent to an empty string 1885 * @return this, to enable chaining 1886 */ 1887 public StrBuilder replaceAll(final String searchStr, final String replaceStr) { 1888 final int searchLen = (searchStr == null ? 0 : searchStr.length()); 1889 if (searchLen > 0) { 1890 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); 1891 int index = indexOf(searchStr, 0); 1892 while (index >= 0) { 1893 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 1894 index = indexOf(searchStr, index + replaceLen); 1895 } 1896 } 1897 return this; 1898 } 1899 1900 /** 1901 * Replaces the first instance of the search string with the replace string. 1902 * 1903 * @param searchStr the search string, null causes no action to occur 1904 * @param replaceStr the replace string, null is equivalent to an empty string 1905 * @return this, to enable chaining 1906 */ 1907 public StrBuilder replaceFirst(final String searchStr, final String replaceStr) { 1908 final int searchLen = (searchStr == null ? 0 : searchStr.length()); 1909 if (searchLen > 0) { 1910 final int index = indexOf(searchStr, 0); 1911 if (index >= 0) { 1912 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); 1913 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 1914 } 1915 } 1916 return this; 1917 } 1918 1919 //----------------------------------------------------------------------- 1920 /** 1921 * Replaces all matches within the builder with the replace string. 1922 * <p> 1923 * Matchers can be used to perform advanced replace behaviour. 1924 * For example you could write a matcher to replace all occurrences 1925 * where the character 'a' is followed by a number. 1926 * 1927 * @param matcher the matcher to use to find the deletion, null causes no action 1928 * @param replaceStr the replace string, null is equivalent to an empty string 1929 * @return this, to enable chaining 1930 */ 1931 public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) { 1932 return replace(matcher, replaceStr, 0, size, -1); 1933 } 1934 1935 /** 1936 * Replaces the first match within the builder with the replace string. 1937 * <p> 1938 * Matchers can be used to perform advanced replace behaviour. 1939 * For example you could write a matcher to replace 1940 * where the character 'a' is followed by a number. 1941 * 1942 * @param matcher the matcher to use to find the deletion, null causes no action 1943 * @param replaceStr the replace string, null is equivalent to an empty string 1944 * @return this, to enable chaining 1945 */ 1946 public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) { 1947 return replace(matcher, replaceStr, 0, size, 1); 1948 } 1949 1950 // ----------------------------------------------------------------------- 1951 /** 1952 * Advanced search and replaces within the builder using a matcher. 1953 * <p> 1954 * Matchers can be used to perform advanced behaviour. 1955 * For example you could write a matcher to delete all occurrences 1956 * where the character 'a' is followed by a number. 1957 * 1958 * @param matcher the matcher to use to find the deletion, null causes no action 1959 * @param replaceStr the string to replace the match with, null is a delete 1960 * @param startIndex the start index, inclusive, must be valid 1961 * @param endIndex the end index, exclusive, must be valid except 1962 * that if too large it is treated as end of string 1963 * @param replaceCount the number of times to replace, -1 for replace all 1964 * @return this, to enable chaining 1965 * @throws IndexOutOfBoundsException if start index is invalid 1966 */ 1967 public StrBuilder replace( 1968 final StrMatcher matcher, final String replaceStr, 1969 final int startIndex, int endIndex, final int replaceCount) { 1970 endIndex = validateRange(startIndex, endIndex); 1971 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); 1972 } 1973 1974 /** 1975 * Replaces within the builder using a matcher. 1976 * <p> 1977 * Matchers can be used to perform advanced behaviour. 1978 * For example you could write a matcher to delete all occurrences 1979 * where the character 'a' is followed by a number. 1980 * 1981 * @param matcher the matcher to use to find the deletion, null causes no action 1982 * @param replaceStr the string to replace the match with, null is a delete 1983 * @param from the start index, must be valid 1984 * @param to the end index (exclusive), must be valid 1985 * @param replaceCount the number of times to replace, -1 for replace all 1986 * @return this, to enable chaining 1987 * @throws IndexOutOfBoundsException if any index is invalid 1988 */ 1989 private StrBuilder replaceImpl( 1990 final StrMatcher matcher, final String replaceStr, 1991 final int from, int to, int replaceCount) { 1992 if (matcher == null || size == 0) { 1993 return this; 1994 } 1995 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); 1996 final char[] buf = buffer; 1997 for (int i = from; i < to && replaceCount != 0; i++) { 1998 final int removeLen = matcher.isMatch(buf, i, from, to); 1999 if (removeLen > 0) { 2000 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); 2001 to = to - removeLen + replaceLen; 2002 i = i + replaceLen - 1; 2003 if (replaceCount > 0) { 2004 replaceCount--; 2005 } 2006 } 2007 } 2008 return this; 2009 } 2010 2011 //----------------------------------------------------------------------- 2012 /** 2013 * Reverses the string builder placing each character in the opposite index. 2014 * 2015 * @return this, to enable chaining 2016 */ 2017 public StrBuilder reverse() { 2018 if (size == 0) { 2019 return this; 2020 } 2021 2022 final int half = size / 2; 2023 final char[] buf = buffer; 2024 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) { 2025 final char swap = buf[leftIdx]; 2026 buf[leftIdx] = buf[rightIdx]; 2027 buf[rightIdx] = swap; 2028 } 2029 return this; 2030 } 2031 2032 //----------------------------------------------------------------------- 2033 /** 2034 * Trims the builder by removing characters less than or equal to a space 2035 * from the beginning and end. 2036 * 2037 * @return this, to enable chaining 2038 */ 2039 public StrBuilder trim() { 2040 if (size == 0) { 2041 return this; 2042 } 2043 int len = size; 2044 final char[] buf = buffer; 2045 int pos = 0; 2046 while (pos < len && buf[pos] <= ' ') { 2047 pos++; 2048 } 2049 while (pos < len && buf[len - 1] <= ' ') { 2050 len--; 2051 } 2052 if (len < size) { 2053 delete(len, size); 2054 } 2055 if (pos > 0) { 2056 delete(0, pos); 2057 } 2058 return this; 2059 } 2060 2061 //----------------------------------------------------------------------- 2062 /** 2063 * Checks whether this builder starts with the specified string. 2064 * <p> 2065 * Note that this method handles null input quietly, unlike String. 2066 * 2067 * @param str the string to search for, null returns false 2068 * @return true if the builder starts with the string 2069 */ 2070 public boolean startsWith(final String str) { 2071 if (str == null) { 2072 return false; 2073 } 2074 final int len = str.length(); 2075 if (len == 0) { 2076 return true; 2077 } 2078 if (len > size) { 2079 return false; 2080 } 2081 for (int i = 0; i < len; i++) { 2082 if (buffer[i] != str.charAt(i)) { 2083 return false; 2084 } 2085 } 2086 return true; 2087 } 2088 2089 /** 2090 * Checks whether this builder ends with the specified string. 2091 * <p> 2092 * Note that this method handles null input quietly, unlike String. 2093 * 2094 * @param str the string to search for, null returns false 2095 * @return true if the builder ends with the string 2096 */ 2097 public boolean endsWith(final String str) { 2098 if (str == null) { 2099 return false; 2100 } 2101 final int len = str.length(); 2102 if (len == 0) { 2103 return true; 2104 } 2105 if (len > size) { 2106 return false; 2107 } 2108 int pos = size - len; 2109 for (int i = 0; i < len; i++,pos++) { 2110 if (buffer[pos] != str.charAt(i)) { 2111 return false; 2112 } 2113 } 2114 return true; 2115 } 2116 2117 //----------------------------------------------------------------------- 2118 /** 2119 * {@inheritDoc} 2120 * @since 3.0 2121 */ 2122 @Override 2123 public CharSequence subSequence(final int startIndex, final int endIndex) { 2124 if (startIndex < 0) { 2125 throw new StringIndexOutOfBoundsException(startIndex); 2126 } 2127 if (endIndex > size) { 2128 throw new StringIndexOutOfBoundsException(endIndex); 2129 } 2130 if (startIndex > endIndex) { 2131 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 2132 } 2133 return substring(startIndex, endIndex); 2134 } 2135 2136 /** 2137 * Extracts a portion of this string builder as a string. 2138 * 2139 * @param start the start index, inclusive, must be valid 2140 * @return the new string 2141 * @throws IndexOutOfBoundsException if the index is invalid 2142 */ 2143 public String substring(final int start) { 2144 return substring(start, size); 2145 } 2146 2147 /** 2148 * Extracts a portion of this string builder as a string. 2149 * <p> 2150 * Note: This method treats an endIndex greater than the length of the 2151 * builder as equal to the length of the builder, and continues 2152 * without error, unlike StringBuffer or String. 2153 * 2154 * @param startIndex the start index, inclusive, must be valid 2155 * @param endIndex the end index, exclusive, must be valid except 2156 * that if too large it is treated as end of string 2157 * @return the new string 2158 * @throws IndexOutOfBoundsException if the index is invalid 2159 */ 2160 public String substring(final int startIndex, int endIndex) { 2161 endIndex = validateRange(startIndex, endIndex); 2162 return new String(buffer, startIndex, endIndex - startIndex); 2163 } 2164 2165 /** 2166 * Extracts the leftmost characters from the string builder without 2167 * throwing an exception. 2168 * <p> 2169 * This method extracts the left <code>length</code> characters from 2170 * the builder. If this many characters are not available, the whole 2171 * builder is returned. Thus the returned string may be shorter than the 2172 * length requested. 2173 * 2174 * @param length the number of characters to extract, negative returns empty string 2175 * @return the new string 2176 */ 2177 public String leftString(final int length) { 2178 if (length <= 0) { 2179 return ""; 2180 } else if (length >= size) { 2181 return new String(buffer, 0, size); 2182 } else { 2183 return new String(buffer, 0, length); 2184 } 2185 } 2186 2187 /** 2188 * Extracts the rightmost characters from the string builder without 2189 * throwing an exception. 2190 * <p> 2191 * This method extracts the right <code>length</code> characters from 2192 * the builder. If this many characters are not available, the whole 2193 * builder is returned. Thus the returned string may be shorter than the 2194 * length requested. 2195 * 2196 * @param length the number of characters to extract, negative returns empty string 2197 * @return the new string 2198 */ 2199 public String rightString(final int length) { 2200 if (length <= 0) { 2201 return ""; 2202 } else if (length >= size) { 2203 return new String(buffer, 0, size); 2204 } else { 2205 return new String(buffer, size - length, length); 2206 } 2207 } 2208 2209 /** 2210 * Extracts some characters from the middle of the string builder without 2211 * throwing an exception. 2212 * <p> 2213 * This method extracts <code>length</code> characters from the builder 2214 * at the specified index. 2215 * If the index is negative it is treated as zero. 2216 * If the index is greater than the builder size, it is treated as the builder size. 2217 * If the length is negative, the empty string is returned. 2218 * If insufficient characters are available in the builder, as much as possible is returned. 2219 * Thus the returned string may be shorter than the length requested. 2220 * 2221 * @param index the index to start at, negative means zero 2222 * @param length the number of characters to extract, negative returns empty string 2223 * @return the new string 2224 */ 2225 public String midString(int index, final int length) { 2226 if (index < 0) { 2227 index = 0; 2228 } 2229 if (length <= 0 || index >= size) { 2230 return ""; 2231 } 2232 if (size <= index + length) { 2233 return new String(buffer, index, size - index); 2234 } 2235 return new String(buffer, index, length); 2236 } 2237 2238 //----------------------------------------------------------------------- 2239 /** 2240 * Checks if the string builder contains the specified char. 2241 * 2242 * @param ch the character to find 2243 * @return true if the builder contains the character 2244 */ 2245 public boolean contains(final char ch) { 2246 final char[] thisBuf = buffer; 2247 for (int i = 0; i < this.size; i++) { 2248 if (thisBuf[i] == ch) { 2249 return true; 2250 } 2251 } 2252 return false; 2253 } 2254 2255 /** 2256 * Checks if the string builder contains the specified string. 2257 * 2258 * @param str the string to find 2259 * @return true if the builder contains the string 2260 */ 2261 public boolean contains(final String str) { 2262 return indexOf(str, 0) >= 0; 2263 } 2264 2265 /** 2266 * Checks if the string builder contains a string matched using the 2267 * specified matcher. 2268 * <p> 2269 * Matchers can be used to perform advanced searching behaviour. 2270 * For example you could write a matcher to search for the character 2271 * 'a' followed by a number. 2272 * 2273 * @param matcher the matcher to use, null returns -1 2274 * @return true if the matcher finds a match in the builder 2275 */ 2276 public boolean contains(final StrMatcher matcher) { 2277 return indexOf(matcher, 0) >= 0; 2278 } 2279 2280 //----------------------------------------------------------------------- 2281 /** 2282 * Searches the string builder to find the first reference to the specified char. 2283 * 2284 * @param ch the character to find 2285 * @return the first index of the character, or -1 if not found 2286 */ 2287 public int indexOf(final char ch) { 2288 return indexOf(ch, 0); 2289 } 2290 2291 /** 2292 * Searches the string builder to find the first reference to the specified char. 2293 * 2294 * @param ch the character to find 2295 * @param startIndex the index to start at, invalid index rounded to edge 2296 * @return the first index of the character, or -1 if not found 2297 */ 2298 public int indexOf(final char ch, int startIndex) { 2299 startIndex = (startIndex < 0 ? 0 : startIndex); 2300 if (startIndex >= size) { 2301 return -1; 2302 } 2303 final char[] thisBuf = buffer; 2304 for (int i = startIndex; i < size; i++) { 2305 if (thisBuf[i] == ch) { 2306 return i; 2307 } 2308 } 2309 return -1; 2310 } 2311 2312 /** 2313 * Searches the string builder to find the first reference to the specified string. 2314 * <p> 2315 * Note that a null input string will return -1, whereas the JDK throws an exception. 2316 * 2317 * @param str the string to find, null returns -1 2318 * @return the first index of the string, or -1 if not found 2319 */ 2320 public int indexOf(final String str) { 2321 return indexOf(str, 0); 2322 } 2323 2324 /** 2325 * Searches the string builder to find the first reference to the specified 2326 * string starting searching from the given index. 2327 * <p> 2328 * Note that a null input string will return -1, whereas the JDK throws an exception. 2329 * 2330 * @param str the string to find, null returns -1 2331 * @param startIndex the index to start at, invalid index rounded to edge 2332 * @return the first index of the string, or -1 if not found 2333 */ 2334 public int indexOf(final String str, int startIndex) { 2335 startIndex = (startIndex < 0 ? 0 : startIndex); 2336 if (str == null || startIndex >= size) { 2337 return -1; 2338 } 2339 final int strLen = str.length(); 2340 if (strLen == 1) { 2341 return indexOf(str.charAt(0), startIndex); 2342 } 2343 if (strLen == 0) { 2344 return startIndex; 2345 } 2346 if (strLen > size) { 2347 return -1; 2348 } 2349 final char[] thisBuf = buffer; 2350 final int len = size - strLen + 1; 2351 outer: 2352 for (int i = startIndex; i < len; i++) { 2353 for (int j = 0; j < strLen; j++) { 2354 if (str.charAt(j) != thisBuf[i + j]) { 2355 continue outer; 2356 } 2357 } 2358 return i; 2359 } 2360 return -1; 2361 } 2362 2363 /** 2364 * Searches the string builder using the matcher to find the first match. 2365 * <p> 2366 * Matchers can be used to perform advanced searching behaviour. 2367 * For example you could write a matcher to find the character 'a' 2368 * followed by a number. 2369 * 2370 * @param matcher the matcher to use, null returns -1 2371 * @return the first index matched, or -1 if not found 2372 */ 2373 public int indexOf(final StrMatcher matcher) { 2374 return indexOf(matcher, 0); 2375 } 2376 2377 /** 2378 * Searches the string builder using the matcher to find the first 2379 * match searching from the given index. 2380 * <p> 2381 * Matchers can be used to perform advanced searching behaviour. 2382 * For example you could write a matcher to find the character 'a' 2383 * followed by a number. 2384 * 2385 * @param matcher the matcher to use, null returns -1 2386 * @param startIndex the index to start at, invalid index rounded to edge 2387 * @return the first index matched, or -1 if not found 2388 */ 2389 public int indexOf(final StrMatcher matcher, int startIndex) { 2390 startIndex = (startIndex < 0 ? 0 : startIndex); 2391 if (matcher == null || startIndex >= size) { 2392 return -1; 2393 } 2394 final int len = size; 2395 final char[] buf = buffer; 2396 for (int i = startIndex; i < len; i++) { 2397 if (matcher.isMatch(buf, i, startIndex, len) > 0) { 2398 return i; 2399 } 2400 } 2401 return -1; 2402 } 2403 2404 //----------------------------------------------------------------------- 2405 /** 2406 * Searches the string builder to find the last reference to the specified char. 2407 * 2408 * @param ch the character to find 2409 * @return the last index of the character, or -1 if not found 2410 */ 2411 public int lastIndexOf(final char ch) { 2412 return lastIndexOf(ch, size - 1); 2413 } 2414 2415 /** 2416 * Searches the string builder to find the last reference to the specified char. 2417 * 2418 * @param ch the character to find 2419 * @param startIndex the index to start at, invalid index rounded to edge 2420 * @return the last index of the character, or -1 if not found 2421 */ 2422 public int lastIndexOf(final char ch, int startIndex) { 2423 startIndex = (startIndex >= size ? size - 1 : startIndex); 2424 if (startIndex < 0) { 2425 return -1; 2426 } 2427 for (int i = startIndex; i >= 0; i--) { 2428 if (buffer[i] == ch) { 2429 return i; 2430 } 2431 } 2432 return -1; 2433 } 2434 2435 /** 2436 * Searches the string builder to find the last reference to the specified string. 2437 * <p> 2438 * Note that a null input string will return -1, whereas the JDK throws an exception. 2439 * 2440 * @param str the string to find, null returns -1 2441 * @return the last index of the string, or -1 if not found 2442 */ 2443 public int lastIndexOf(final String str) { 2444 return lastIndexOf(str, size - 1); 2445 } 2446 2447 /** 2448 * Searches the string builder to find the last reference to the specified 2449 * string starting searching from the given index. 2450 * <p> 2451 * Note that a null input string will return -1, whereas the JDK throws an exception. 2452 * 2453 * @param str the string to find, null returns -1 2454 * @param startIndex the index to start at, invalid index rounded to edge 2455 * @return the last index of the string, or -1 if not found 2456 */ 2457 public int lastIndexOf(final String str, int startIndex) { 2458 startIndex = (startIndex >= size ? size - 1 : startIndex); 2459 if (str == null || startIndex < 0) { 2460 return -1; 2461 } 2462 final int strLen = str.length(); 2463 if (strLen > 0 && strLen <= size) { 2464 if (strLen == 1) { 2465 return lastIndexOf(str.charAt(0), startIndex); 2466 } 2467 2468 outer: 2469 for (int i = startIndex - strLen + 1; i >= 0; i--) { 2470 for (int j = 0; j < strLen; j++) { 2471 if (str.charAt(j) != buffer[i + j]) { 2472 continue outer; 2473 } 2474 } 2475 return i; 2476 } 2477 2478 } else if (strLen == 0) { 2479 return startIndex; 2480 } 2481 return -1; 2482 } 2483 2484 /** 2485 * Searches the string builder using the matcher to find the last match. 2486 * <p> 2487 * Matchers can be used to perform advanced searching behaviour. 2488 * For example you could write a matcher to find the character 'a' 2489 * followed by a number. 2490 * 2491 * @param matcher the matcher to use, null returns -1 2492 * @return the last index matched, or -1 if not found 2493 */ 2494 public int lastIndexOf(final StrMatcher matcher) { 2495 return lastIndexOf(matcher, size); 2496 } 2497 2498 /** 2499 * Searches the string builder using the matcher to find the last 2500 * match searching from the given index. 2501 * <p> 2502 * Matchers can be used to perform advanced searching behaviour. 2503 * For example you could write a matcher to find the character 'a' 2504 * followed by a number. 2505 * 2506 * @param matcher the matcher to use, null returns -1 2507 * @param startIndex the index to start at, invalid index rounded to edge 2508 * @return the last index matched, or -1 if not found 2509 */ 2510 public int lastIndexOf(final StrMatcher matcher, int startIndex) { 2511 startIndex = (startIndex >= size ? size - 1 : startIndex); 2512 if (matcher == null || startIndex < 0) { 2513 return -1; 2514 } 2515 final char[] buf = buffer; 2516 final int endIndex = startIndex + 1; 2517 for (int i = startIndex; i >= 0; i--) { 2518 if (matcher.isMatch(buf, i, 0, endIndex) > 0) { 2519 return i; 2520 } 2521 } 2522 return -1; 2523 } 2524 2525 //----------------------------------------------------------------------- 2526 /** 2527 * Creates a tokenizer that can tokenize the contents of this builder. 2528 * <p> 2529 * This method allows the contents of this builder to be tokenized. 2530 * The tokenizer will be setup by default to tokenize on space, tab, 2531 * newline and formfeed (as per StringTokenizer). These values can be 2532 * changed on the tokenizer class, before retrieving the tokens. 2533 * <p> 2534 * The returned tokenizer is linked to this builder. You may intermix 2535 * calls to the buider and tokenizer within certain limits, however 2536 * there is no synchronization. Once the tokenizer has been used once, 2537 * it must be {@link StrTokenizer#reset() reset} to pickup the latest 2538 * changes in the builder. For example: 2539 * <pre> 2540 * StrBuilder b = new StrBuilder(); 2541 * b.append("a b "); 2542 * StrTokenizer t = b.asTokenizer(); 2543 * String[] tokens1 = t.getTokenArray(); // returns a,b 2544 * b.append("c d "); 2545 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored) 2546 * t.reset(); // reset causes builder changes to be picked up 2547 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d 2548 * </pre> 2549 * In addition to simply intermixing appends and tokenization, you can also 2550 * call the set methods on the tokenizer to alter how it tokenizes. Just 2551 * remember to call reset when you want to pickup builder changes. 2552 * <p> 2553 * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])} 2554 * with a non-null value will break the link with the builder. 2555 * 2556 * @return a tokenizer that is linked to this builder 2557 */ 2558 public StrTokenizer asTokenizer() { 2559 return new StrBuilderTokenizer(); 2560 } 2561 2562 //----------------------------------------------------------------------- 2563 /** 2564 * Gets the contents of this builder as a Reader. 2565 * <p> 2566 * This method allows the contents of the builder to be read 2567 * using any standard method that expects a Reader. 2568 * <p> 2569 * To use, simply create a <code>StrBuilder</code>, populate it with 2570 * data, call <code>asReader</code>, and then read away. 2571 * <p> 2572 * The internal character array is shared between the builder and the reader. 2573 * This allows you to append to the builder after creating the reader, 2574 * and the changes will be picked up. 2575 * Note however, that no synchronization occurs, so you must perform 2576 * all operations with the builder and the reader in one thread. 2577 * <p> 2578 * The returned reader supports marking, and ignores the flush method. 2579 * 2580 * @return a reader that reads from this builder 2581 */ 2582 public Reader asReader() { 2583 return new StrBuilderReader(); 2584 } 2585 2586 //----------------------------------------------------------------------- 2587 /** 2588 * Gets this builder as a Writer that can be written to. 2589 * <p> 2590 * This method allows you to populate the contents of the builder 2591 * using any standard method that takes a Writer. 2592 * <p> 2593 * To use, simply create a <code>StrBuilder</code>, 2594 * call <code>asWriter</code>, and populate away. The data is available 2595 * at any time using the methods of the <code>StrBuilder</code>. 2596 * <p> 2597 * The internal character array is shared between the builder and the writer. 2598 * This allows you to intermix calls that append to the builder and 2599 * write using the writer and the changes will be occur correctly. 2600 * Note however, that no synchronization occurs, so you must perform 2601 * all operations with the builder and the writer in one thread. 2602 * <p> 2603 * The returned writer ignores the close and flush methods. 2604 * 2605 * @return a writer that populates this builder 2606 */ 2607 public Writer asWriter() { 2608 return new StrBuilderWriter(); 2609 } 2610 2611 //----------------------------------------------------------------------- 2612// /** 2613// * Gets a String version of the string builder by calling the internal 2614// * constructor of String by reflection. 2615// * <p> 2616// * WARNING: You must not use the StrBuilder after calling this method 2617// * as the buffer is now shared with the String object. To ensure this, 2618// * the internal character array is set to null, so you will get 2619// * NullPointerExceptions on all method calls. 2620// * 2621// * @return the builder as a String 2622// */ 2623// public String toSharedString() { 2624// try { 2625// Constructor con = String.class.getDeclaredConstructor( 2626// new Class[] {int.class, int.class, char[].class}); 2627// con.setAccessible(true); 2628// char[] buffer = buf; 2629// buf = null; 2630// size = -1; 2631// nullText = null; 2632// return (String) con.newInstance( 2633// new Object[] {Integer.valueOf(0), Integer.valueOf(size), buffer}); 2634// 2635// } catch (Exception ex) { 2636// ex.printStackTrace(); 2637// throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage()); 2638// } 2639// } 2640 2641 //----------------------------------------------------------------------- 2642 /** 2643 * Checks the contents of this builder against another to see if they 2644 * contain the same character content ignoring case. 2645 * 2646 * @param other the object to check, null returns false 2647 * @return true if the builders contain the same characters in the same order 2648 */ 2649 public boolean equalsIgnoreCase(final StrBuilder other) { 2650 if (this == other) { 2651 return true; 2652 } 2653 if (this.size != other.size) { 2654 return false; 2655 } 2656 final char thisBuf[] = this.buffer; 2657 final char otherBuf[] = other.buffer; 2658 for (int i = size - 1; i >= 0; i--) { 2659 final char c1 = thisBuf[i]; 2660 final char c2 = otherBuf[i]; 2661 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { 2662 return false; 2663 } 2664 } 2665 return true; 2666 } 2667 2668 /** 2669 * Checks the contents of this builder against another to see if they 2670 * contain the same character content. 2671 * 2672 * @param other the object to check, null returns false 2673 * @return true if the builders contain the same characters in the same order 2674 */ 2675 public boolean equals(final StrBuilder other) { 2676 if (this == other) { 2677 return true; 2678 } 2679 if (this.size != other.size) { 2680 return false; 2681 } 2682 final char thisBuf[] = this.buffer; 2683 final char otherBuf[] = other.buffer; 2684 for (int i = size - 1; i >= 0; i--) { 2685 if (thisBuf[i] != otherBuf[i]) { 2686 return false; 2687 } 2688 } 2689 return true; 2690 } 2691 2692 /** 2693 * Checks the contents of this builder against another to see if they 2694 * contain the same character content. 2695 * 2696 * @param obj the object to check, null returns false 2697 * @return true if the builders contain the same characters in the same order 2698 */ 2699 @Override 2700 public boolean equals(final Object obj) { 2701 if (obj instanceof StrBuilder) { 2702 return equals((StrBuilder) obj); 2703 } 2704 return false; 2705 } 2706 2707 /** 2708 * Gets a suitable hash code for this builder. 2709 * 2710 * @return a hash code 2711 */ 2712 @Override 2713 public int hashCode() { 2714 final char buf[] = buffer; 2715 int hash = 0; 2716 for (int i = size - 1; i >= 0; i--) { 2717 hash = 31 * hash + buf[i]; 2718 } 2719 return hash; 2720 } 2721 2722 //----------------------------------------------------------------------- 2723 /** 2724 * Gets a String version of the string builder, creating a new instance 2725 * each time the method is called. 2726 * <p> 2727 * Note that unlike StringBuffer, the string version returned is 2728 * independent of the string builder. 2729 * 2730 * @return the builder as a String 2731 */ 2732 @Override 2733 public String toString() { 2734 return new String(buffer, 0, size); 2735 } 2736 2737 /** 2738 * Gets a StringBuffer version of the string builder, creating a 2739 * new instance each time the method is called. 2740 * 2741 * @return the builder as a StringBuffer 2742 */ 2743 public StringBuffer toStringBuffer() { 2744 return new StringBuffer(size).append(buffer, 0, size); 2745 } 2746 2747 /** 2748 * Gets a StringBuilder version of the string builder, creating a 2749 * new instance each time the method is called. 2750 * 2751 * @return the builder as a StringBuilder 2752 * @since 3.2 2753 */ 2754 public StringBuilder toStringBuilder() { 2755 return new StringBuilder(size).append(buffer, 0, size); 2756 } 2757 2758 /** 2759 * Implement the {@link Builder} interface. 2760 * @return the builder as a String 2761 * @since 3.2 2762 * @see #toString() 2763 */ 2764 @Override 2765 public String build() { 2766 return toString(); 2767 } 2768 2769 //----------------------------------------------------------------------- 2770 /** 2771 * Validates parameters defining a range of the builder. 2772 * 2773 * @param startIndex the start index, inclusive, must be valid 2774 * @param endIndex the end index, exclusive, must be valid except 2775 * that if too large it is treated as end of string 2776 * @return the new string 2777 * @throws IndexOutOfBoundsException if the index is invalid 2778 */ 2779 protected int validateRange(final int startIndex, int endIndex) { 2780 if (startIndex < 0) { 2781 throw new StringIndexOutOfBoundsException(startIndex); 2782 } 2783 if (endIndex > size) { 2784 endIndex = size; 2785 } 2786 if (startIndex > endIndex) { 2787 throw new StringIndexOutOfBoundsException("end < start"); 2788 } 2789 return endIndex; 2790 } 2791 2792 /** 2793 * Validates parameters defining a single index in the builder. 2794 * 2795 * @param index the index, must be valid 2796 * @throws IndexOutOfBoundsException if the index is invalid 2797 */ 2798 protected void validateIndex(final int index) { 2799 if (index < 0 || index > size) { 2800 throw new StringIndexOutOfBoundsException(index); 2801 } 2802 } 2803 2804 //----------------------------------------------------------------------- 2805 /** 2806 * Inner class to allow StrBuilder to operate as a tokenizer. 2807 */ 2808 class StrBuilderTokenizer extends StrTokenizer { 2809 2810 /** 2811 * Default constructor. 2812 */ 2813 StrBuilderTokenizer() { 2814 super(); 2815 } 2816 2817 /** {@inheritDoc} */ 2818 @Override 2819 protected List<String> tokenize(final char[] chars, final int offset, final int count) { 2820 if (chars == null) { 2821 return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size()); 2822 } 2823 return super.tokenize(chars, offset, count); 2824 } 2825 2826 /** {@inheritDoc} */ 2827 @Override 2828 public String getContent() { 2829 final String str = super.getContent(); 2830 if (str == null) { 2831 return StrBuilder.this.toString(); 2832 } 2833 return str; 2834 } 2835 } 2836 2837 //----------------------------------------------------------------------- 2838 /** 2839 * Inner class to allow StrBuilder to operate as a reader. 2840 */ 2841 class StrBuilderReader extends Reader { 2842 /** The current stream position. */ 2843 private int pos; 2844 /** The last mark position. */ 2845 private int mark; 2846 2847 /** 2848 * Default constructor. 2849 */ 2850 StrBuilderReader() { 2851 super(); 2852 } 2853 2854 /** {@inheritDoc} */ 2855 @Override 2856 public void close() { 2857 // do nothing 2858 } 2859 2860 /** {@inheritDoc} */ 2861 @Override 2862 public int read() { 2863 if (ready() == false) { 2864 return -1; 2865 } 2866 return StrBuilder.this.charAt(pos++); 2867 } 2868 2869 /** {@inheritDoc} */ 2870 @Override 2871 public int read(final char b[], final int off, int len) { 2872 if (off < 0 || len < 0 || off > b.length || 2873 (off + len) > b.length || (off + len) < 0) { 2874 throw new IndexOutOfBoundsException(); 2875 } 2876 if (len == 0) { 2877 return 0; 2878 } 2879 if (pos >= StrBuilder.this.size()) { 2880 return -1; 2881 } 2882 if (pos + len > size()) { 2883 len = StrBuilder.this.size() - pos; 2884 } 2885 StrBuilder.this.getChars(pos, pos + len, b, off); 2886 pos += len; 2887 return len; 2888 } 2889 2890 /** {@inheritDoc} */ 2891 @Override 2892 public long skip(long n) { 2893 if (pos + n > StrBuilder.this.size()) { 2894 n = StrBuilder.this.size() - pos; 2895 } 2896 if (n < 0) { 2897 return 0; 2898 } 2899 pos += n; 2900 return n; 2901 } 2902 2903 /** {@inheritDoc} */ 2904 @Override 2905 public boolean ready() { 2906 return pos < StrBuilder.this.size(); 2907 } 2908 2909 /** {@inheritDoc} */ 2910 @Override 2911 public boolean markSupported() { 2912 return true; 2913 } 2914 2915 /** {@inheritDoc} */ 2916 @Override 2917 public void mark(final int readAheadLimit) { 2918 mark = pos; 2919 } 2920 2921 /** {@inheritDoc} */ 2922 @Override 2923 public void reset() { 2924 pos = mark; 2925 } 2926 } 2927 2928 //----------------------------------------------------------------------- 2929 /** 2930 * Inner class to allow StrBuilder to operate as a writer. 2931 */ 2932 class StrBuilderWriter extends Writer { 2933 2934 /** 2935 * Default constructor. 2936 */ 2937 StrBuilderWriter() { 2938 super(); 2939 } 2940 2941 /** {@inheritDoc} */ 2942 @Override 2943 public void close() { 2944 // do nothing 2945 } 2946 2947 /** {@inheritDoc} */ 2948 @Override 2949 public void flush() { 2950 // do nothing 2951 } 2952 2953 /** {@inheritDoc} */ 2954 @Override 2955 public void write(final int c) { 2956 StrBuilder.this.append((char) c); 2957 } 2958 2959 /** {@inheritDoc} */ 2960 @Override 2961 public void write(final char[] cbuf) { 2962 StrBuilder.this.append(cbuf); 2963 } 2964 2965 /** {@inheritDoc} */ 2966 @Override 2967 public void write(final char[] cbuf, final int off, final int len) { 2968 StrBuilder.this.append(cbuf, off, len); 2969 } 2970 2971 /** {@inheritDoc} */ 2972 @Override 2973 public void write(final String str) { 2974 StrBuilder.this.append(str); 2975 } 2976 2977 /** {@inheritDoc} */ 2978 @Override 2979 public void write(final String str, final int off, final int len) { 2980 StrBuilder.this.append(str, off, len); 2981 } 2982 } 2983 2984}