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