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 1552657 2013-12-20 13:30:16Z britter $ 074 */ 075public class StrBuilder implements CharSequence, Appendable, Serializable, Builder<String> { 076 077 /** 078 * The extra capacity for new builders. 079 */ 080 static final int CAPACITY = 32; 081 082 /** 083 * Required for serialization support. 084 * 085 * @see java.io.Serializable 086 */ 087 private static final long serialVersionUID = 7628716375283629643L; 088 089 /** Internal data storage. */ 090 protected char[] buffer; // TODO make private? 091 /** Current size of the buffer. */ 092 protected int size; // TODO make private? 093 /** The new line. */ 094 private String newLine; 095 /** The null text. */ 096 private String nullText; 097 098 //----------------------------------------------------------------------- 099 /** 100 * Constructor that creates an empty builder initial capacity 32 characters. 101 */ 102 public StrBuilder() { 103 this(CAPACITY); 104 } 105 106 /** 107 * Constructor that creates an empty builder the specified initial capacity. 108 * 109 * @param initialCapacity the initial capacity, zero or less will be converted to 32 110 */ 111 public StrBuilder(int initialCapacity) { 112 super(); 113 if (initialCapacity <= 0) { 114 initialCapacity = CAPACITY; 115 } 116 buffer = new char[initialCapacity]; 117 } 118 119 /** 120 * Constructor that creates a builder from the string, allocating 121 * 32 extra characters for growth. 122 * 123 * @param str the string to copy, null treated as blank string 124 */ 125 public StrBuilder(final String str) { 126 super(); 127 if (str == null) { 128 buffer = new char[CAPACITY]; 129 } else { 130 buffer = new char[str.length() + CAPACITY]; 131 append(str); 132 } 133 } 134 135 //----------------------------------------------------------------------- 136 /** 137 * Gets the text to be appended when a new line is added. 138 * 139 * @return the new line text, null means use system default 140 */ 141 public String getNewLineText() { 142 return newLine; 143 } 144 145 /** 146 * Sets the text to be appended when a new line is added. 147 * 148 * @param newLine the new line text, null means use system default 149 * @return this, to enable chaining 150 */ 151 public StrBuilder setNewLineText(final String newLine) { 152 this.newLine = newLine; 153 return this; 154 } 155 156 //----------------------------------------------------------------------- 157 /** 158 * Gets the text to be appended when null is added. 159 * 160 * @return the null text, null means no append 161 */ 162 public String getNullText() { 163 return nullText; 164 } 165 166 /** 167 * Sets the text to be appended when null is added. 168 * 169 * @param nullText the null text, null means no append 170 * @return this, to enable chaining 171 */ 172 public StrBuilder setNullText(String nullText) { 173 if (nullText != null && nullText.isEmpty()) { 174 nullText = null; 175 } 176 this.nullText = nullText; 177 return this; 178 } 179 180 //----------------------------------------------------------------------- 181 /** 182 * Gets the length of the string builder. 183 * 184 * @return the length 185 */ 186 @Override 187 public int length() { 188 return size; 189 } 190 191 /** 192 * Updates the length of the builder by either dropping the last characters 193 * or adding filler of Unicode zero. 194 * 195 * @param length the length to set to, must be zero or positive 196 * @return this, to enable chaining 197 * @throws IndexOutOfBoundsException if the length is negative 198 */ 199 public StrBuilder setLength(final int length) { 200 if (length < 0) { 201 throw new StringIndexOutOfBoundsException(length); 202 } 203 if (length < size) { 204 size = length; 205 } else if (length > size) { 206 ensureCapacity(length); 207 final int oldEnd = size; 208 final int newEnd = length; 209 size = length; 210 for (int i = oldEnd; i < newEnd; i++) { 211 buffer[i] = '\0'; 212 } 213 } 214 return this; 215 } 216 217 //----------------------------------------------------------------------- 218 /** 219 * Gets the current size of the internal character array buffer. 220 * 221 * @return the capacity 222 */ 223 public int capacity() { 224 return buffer.length; 225 } 226 227 /** 228 * Checks the capacity and ensures that it is at least the size specified. 229 * 230 * @param capacity the capacity to ensure 231 * @return this, to enable chaining 232 */ 233 public StrBuilder ensureCapacity(final int capacity) { 234 if (capacity > buffer.length) { 235 final char[] old = buffer; 236 buffer = new char[capacity * 2]; 237 System.arraycopy(old, 0, buffer, 0, size); 238 } 239 return this; 240 } 241 242 /** 243 * Minimizes the capacity to the actual length of the string. 244 * 245 * @return this, to enable chaining 246 */ 247 public StrBuilder minimizeCapacity() { 248 if (buffer.length > length()) { 249 final char[] old = buffer; 250 buffer = new char[length()]; 251 System.arraycopy(old, 0, buffer, 0, size); 252 } 253 return this; 254 } 255 256 //----------------------------------------------------------------------- 257 /** 258 * Gets the length of the string builder. 259 * <p> 260 * This method is the same as {@link #length()} and is provided to match the 261 * API of Collections. 262 * 263 * @return the length 264 */ 265 public int size() { 266 return size; 267 } 268 269 /** 270 * Checks is the string builder is empty (convenience Collections API style method). 271 * <p> 272 * This method is the same as checking {@link #length()} and is provided to match the 273 * API of Collections. 274 * 275 * @return <code>true</code> if the size is <code>0</code>. 276 */ 277 public boolean isEmpty() { 278 return size == 0; 279 } 280 281 /** 282 * Clears the string builder (convenience Collections API style method). 283 * <p> 284 * This method does not reduce the size of the internal character buffer. 285 * To do that, call <code>clear()</code> followed by {@link #minimizeCapacity()}. 286 * <p> 287 * This method is the same as {@link #setLength(int)} called with zero 288 * and is provided to match the API of Collections. 289 * 290 * @return this, to enable chaining 291 */ 292 public StrBuilder clear() { 293 size = 0; 294 return this; 295 } 296 297 //----------------------------------------------------------------------- 298 /** 299 * Gets the character at the specified index. 300 * 301 * @see #setCharAt(int, char) 302 * @see #deleteCharAt(int) 303 * @param index the index to retrieve, must be valid 304 * @return the character at the index 305 * @throws IndexOutOfBoundsException if the index is invalid 306 */ 307 @Override 308 public char charAt(final int index) { 309 if (index < 0 || index >= length()) { 310 throw new StringIndexOutOfBoundsException(index); 311 } 312 return buffer[index]; 313 } 314 315 /** 316 * Sets the character at the specified index. 317 * 318 * @see #charAt(int) 319 * @see #deleteCharAt(int) 320 * @param index the index to set 321 * @param ch the new character 322 * @return this, to enable chaining 323 * @throws IndexOutOfBoundsException if the index is invalid 324 */ 325 public StrBuilder setCharAt(final int index, final char ch) { 326 if (index < 0 || index >= length()) { 327 throw new StringIndexOutOfBoundsException(index); 328 } 329 buffer[index] = ch; 330 return this; 331 } 332 333 /** 334 * Deletes the character at the specified index. 335 * 336 * @see #charAt(int) 337 * @see #setCharAt(int, char) 338 * @param index the index to delete 339 * @return this, to enable chaining 340 * @throws IndexOutOfBoundsException if the index is invalid 341 */ 342 public StrBuilder deleteCharAt(final int index) { 343 if (index < 0 || index >= size) { 344 throw new StringIndexOutOfBoundsException(index); 345 } 346 deleteImpl(index, index + 1, 1); 347 return this; 348 } 349 350 //----------------------------------------------------------------------- 351 /** 352 * Copies the builder's character array into a new character array. 353 * 354 * @return a new array that represents the contents of the builder 355 */ 356 public char[] toCharArray() { 357 if (size == 0) { 358 return ArrayUtils.EMPTY_CHAR_ARRAY; 359 } 360 final char chars[] = new char[size]; 361 System.arraycopy(buffer, 0, chars, 0, size); 362 return chars; 363 } 364 365 /** 366 * Copies part of the builder's character array into a new character array. 367 * 368 * @param startIndex the start index, inclusive, must be valid 369 * @param endIndex the end index, exclusive, must be valid except that 370 * if too large it is treated as end of string 371 * @return a new array that holds part of the contents of the builder 372 * @throws IndexOutOfBoundsException if startIndex is invalid, 373 * or if endIndex is invalid (but endIndex greater than size is valid) 374 */ 375 public char[] toCharArray(final int startIndex, int endIndex) { 376 endIndex = validateRange(startIndex, endIndex); 377 final int len = endIndex - startIndex; 378 if (len == 0) { 379 return ArrayUtils.EMPTY_CHAR_ARRAY; 380 } 381 final char chars[] = new char[len]; 382 System.arraycopy(buffer, startIndex, chars, 0, len); 383 return chars; 384 } 385 386 /** 387 * Copies the character array into the specified array. 388 * 389 * @param destination the destination array, null will cause an array to be created 390 * @return the input array, unless that was null or too small 391 */ 392 public char[] getChars(char[] destination) { 393 final int len = length(); 394 if (destination == null || destination.length < len) { 395 destination = new char[len]; 396 } 397 System.arraycopy(buffer, 0, destination, 0, len); 398 return destination; 399 } 400 401 /** 402 * Copies the character array into the specified array. 403 * 404 * @param startIndex first index to copy, inclusive, must be valid 405 * @param endIndex last index, exclusive, must be valid 406 * @param destination the destination array, must not be null or too small 407 * @param destinationIndex the index to start copying in destination 408 * @throws NullPointerException if the array is null 409 * @throws IndexOutOfBoundsException if any index is invalid 410 */ 411 public void getChars(final int startIndex, final int endIndex, final char destination[], final int destinationIndex) { 412 if (startIndex < 0) { 413 throw new StringIndexOutOfBoundsException(startIndex); 414 } 415 if (endIndex < 0 || endIndex > length()) { 416 throw new StringIndexOutOfBoundsException(endIndex); 417 } 418 if (startIndex > endIndex) { 419 throw new StringIndexOutOfBoundsException("end < start"); 420 } 421 System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex); 422 } 423 424 //----------------------------------------------------------------------- 425 /** 426 * Appends the new line string to this string builder. 427 * <p> 428 * The new line string can be altered using {@link #setNewLineText(String)}. 429 * This might be used to force the output to always use Unix line endings 430 * even when on Windows. 431 * 432 * @return this, to enable chaining 433 */ 434 public StrBuilder appendNewLine() { 435 if (newLine == null) { 436 append(SystemUtils.LINE_SEPARATOR); 437 return this; 438 } 439 return append(newLine); 440 } 441 442 /** 443 * Appends the text representing <code>null</code> to this string builder. 444 * 445 * @return this, to enable chaining 446 */ 447 public StrBuilder appendNull() { 448 if (nullText == null) { 449 return this; 450 } 451 return append(nullText); 452 } 453 454 /** 455 * Appends an object to this string builder. 456 * Appending null will call {@link #appendNull()}. 457 * 458 * @param obj the object to append 459 * @return this, to enable chaining 460 */ 461 public StrBuilder append(final Object obj) { 462 if (obj == null) { 463 return appendNull(); 464 } 465 return append(obj.toString()); 466 } 467 468 /** 469 * Appends a CharSequence to this string builder. 470 * Appending null will call {@link #appendNull()}. 471 * 472 * @param seq the CharSequence to append 473 * @return this, to enable chaining 474 * @since 3.0 475 */ 476 @Override 477 public StrBuilder append(final CharSequence seq) { 478 if (seq == null) { 479 return appendNull(); 480 } 481 return append(seq.toString()); 482 } 483 484 /** 485 * Appends part of a CharSequence to this string builder. 486 * Appending null will call {@link #appendNull()}. 487 * 488 * @param seq the CharSequence to append 489 * @param startIndex the start index, inclusive, must be valid 490 * @param length the length to append, must be valid 491 * @return this, to enable chaining 492 * @since 3.0 493 */ 494 @Override 495 public StrBuilder append(final CharSequence seq, final int startIndex, final int length) { 496 if (seq == null) { 497 return appendNull(); 498 } 499 return append(seq.toString(), startIndex, length); 500 } 501 502 /** 503 * Appends a string to this string builder. 504 * Appending null will call {@link #appendNull()}. 505 * 506 * @param str the string to append 507 * @return this, to enable chaining 508 */ 509 public StrBuilder append(final String str) { 510 if (str == null) { 511 return appendNull(); 512 } 513 final int strLen = str.length(); 514 if (strLen > 0) { 515 final int len = length(); 516 ensureCapacity(len + strLen); 517 str.getChars(0, strLen, buffer, len); 518 size += strLen; 519 } 520 return this; 521 } 522 523 524 /** 525 * Appends part of a string to this string builder. 526 * Appending null will call {@link #appendNull()}. 527 * 528 * @param str the string to append 529 * @param startIndex the start index, inclusive, must be valid 530 * @param length the length to append, must be valid 531 * @return this, to enable chaining 532 */ 533 public StrBuilder append(final String str, final int startIndex, final int length) { 534 if (str == null) { 535 return appendNull(); 536 } 537 if (startIndex < 0 || startIndex > str.length()) { 538 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 539 } 540 if (length < 0 || (startIndex + length) > str.length()) { 541 throw new StringIndexOutOfBoundsException("length must be valid"); 542 } 543 if (length > 0) { 544 final int len = length(); 545 ensureCapacity(len + length); 546 str.getChars(startIndex, startIndex + length, buffer, len); 547 size += length; 548 } 549 return this; 550 } 551 552 /** 553 * Calls {@link String#format(String, Object...)} and appends the result. 554 * 555 * @param format the format string 556 * @param objs the objects to use in the format string 557 * @return {@code this} to enable chaining 558 * @see String#format(String, Object...) 559 * @since 3.2 560 */ 561 public StrBuilder append(final String format, final Object... objs) { 562 return append(String.format(format, objs)); 563 } 564 565 /** 566 * Appends a string buffer to this string builder. 567 * Appending null will call {@link #appendNull()}. 568 * 569 * @param str the string buffer to append 570 * @return this, to enable chaining 571 */ 572 public StrBuilder append(final StringBuffer str) { 573 if (str == null) { 574 return appendNull(); 575 } 576 final int strLen = str.length(); 577 if (strLen > 0) { 578 final int len = length(); 579 ensureCapacity(len + strLen); 580 str.getChars(0, strLen, buffer, len); 581 size += strLen; 582 } 583 return this; 584 } 585 586 /** 587 * Appends part of a string buffer to this string builder. 588 * Appending null will call {@link #appendNull()}. 589 * 590 * @param str the string to append 591 * @param startIndex the start index, inclusive, must be valid 592 * @param length the length to append, must be valid 593 * @return this, to enable chaining 594 */ 595 public StrBuilder append(final StringBuffer str, final int startIndex, final int length) { 596 if (str == null) { 597 return appendNull(); 598 } 599 if (startIndex < 0 || startIndex > str.length()) { 600 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 601 } 602 if (length < 0 || (startIndex + length) > str.length()) { 603 throw new StringIndexOutOfBoundsException("length must be valid"); 604 } 605 if (length > 0) { 606 final int len = length(); 607 ensureCapacity(len + length); 608 str.getChars(startIndex, startIndex + length, buffer, len); 609 size += length; 610 } 611 return this; 612 } 613 614 /** 615 * Appends a StringBuilder to this string builder. 616 * Appending null will call {@link #appendNull()}. 617 * 618 * @param str the StringBuilder to append 619 * @return this, to enable chaining 620 * @since 3.2 621 */ 622 public StrBuilder append(final StringBuilder str) { 623 if (str == null) { 624 return appendNull(); 625 } 626 final int strLen = str.length(); 627 if (strLen > 0) { 628 final int len = length(); 629 ensureCapacity(len + strLen); 630 str.getChars(0, strLen, buffer, len); 631 size += strLen; 632 } 633 return this; 634 } 635 636 /** 637 * Appends part of a StringBuilder to this string builder. 638 * Appending null will call {@link #appendNull()}. 639 * 640 * @param str the StringBuilder to append 641 * @param startIndex the start index, inclusive, must be valid 642 * @param length the length to append, must be valid 643 * @return this, to enable chaining 644 * @since 3.2 645 */ 646 public StrBuilder append(final StringBuilder str, final int startIndex, final int length) { 647 if (str == null) { 648 return appendNull(); 649 } 650 if (startIndex < 0 || startIndex > str.length()) { 651 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 652 } 653 if (length < 0 || (startIndex + length) > str.length()) { 654 throw new StringIndexOutOfBoundsException("length must be valid"); 655 } 656 if (length > 0) { 657 final int len = length(); 658 ensureCapacity(len + length); 659 str.getChars(startIndex, startIndex + length, buffer, len); 660 size += length; 661 } 662 return this; 663 } 664 665 /** 666 * Appends another string builder to this string builder. 667 * Appending null will call {@link #appendNull()}. 668 * 669 * @param str the string builder to append 670 * @return this, to enable chaining 671 */ 672 public StrBuilder append(final StrBuilder str) { 673 if (str == null) { 674 return appendNull(); 675 } 676 final int strLen = str.length(); 677 if (strLen > 0) { 678 final int len = length(); 679 ensureCapacity(len + strLen); 680 System.arraycopy(str.buffer, 0, buffer, len, strLen); 681 size += strLen; 682 } 683 return this; 684 } 685 686 /** 687 * Appends part of a string builder to this string builder. 688 * Appending null will call {@link #appendNull()}. 689 * 690 * @param str the string to append 691 * @param startIndex the start index, inclusive, must be valid 692 * @param length the length to append, must be valid 693 * @return this, to enable chaining 694 */ 695 public StrBuilder append(final StrBuilder str, final int startIndex, final int length) { 696 if (str == null) { 697 return appendNull(); 698 } 699 if (startIndex < 0 || startIndex > str.length()) { 700 throw new StringIndexOutOfBoundsException("startIndex must be valid"); 701 } 702 if (length < 0 || (startIndex + length) > str.length()) { 703 throw new StringIndexOutOfBoundsException("length must be valid"); 704 } 705 if (length > 0) { 706 final int len = length(); 707 ensureCapacity(len + length); 708 str.getChars(startIndex, startIndex + length, buffer, len); 709 size += length; 710 } 711 return this; 712 } 713 714 /** 715 * Appends a char array to the string builder. 716 * Appending null will call {@link #appendNull()}. 717 * 718 * @param chars the char array to append 719 * @return this, to enable chaining 720 */ 721 public StrBuilder append(final char[] chars) { 722 if (chars == null) { 723 return appendNull(); 724 } 725 final int strLen = chars.length; 726 if (strLen > 0) { 727 final int len = length(); 728 ensureCapacity(len + strLen); 729 System.arraycopy(chars, 0, buffer, len, strLen); 730 size += strLen; 731 } 732 return this; 733 } 734 735 /** 736 * Appends a char array to the string builder. 737 * Appending null will call {@link #appendNull()}. 738 * 739 * @param chars the char array to append 740 * @param startIndex the start index, inclusive, must be valid 741 * @param length the length to append, must be valid 742 * @return this, to enable chaining 743 */ 744 public StrBuilder append(final char[] chars, final int startIndex, final int length) { 745 if (chars == null) { 746 return appendNull(); 747 } 748 if (startIndex < 0 || startIndex > chars.length) { 749 throw new StringIndexOutOfBoundsException("Invalid startIndex: " + length); 750 } 751 if (length < 0 || (startIndex + length) > chars.length) { 752 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 753 } 754 if (length > 0) { 755 final int len = length(); 756 ensureCapacity(len + length); 757 System.arraycopy(chars, startIndex, buffer, len, length); 758 size += length; 759 } 760 return this; 761 } 762 763 /** 764 * Appends a boolean value to the string builder. 765 * 766 * @param value the value to append 767 * @return this, to enable chaining 768 */ 769 public StrBuilder append(final boolean value) { 770 if (value) { 771 ensureCapacity(size + 4); 772 buffer[size++] = 't'; 773 buffer[size++] = 'r'; 774 buffer[size++] = 'u'; 775 buffer[size++] = 'e'; 776 } else { 777 ensureCapacity(size + 5); 778 buffer[size++] = 'f'; 779 buffer[size++] = 'a'; 780 buffer[size++] = 'l'; 781 buffer[size++] = 's'; 782 buffer[size++] = 'e'; 783 } 784 return this; 785 } 786 787 /** 788 * Appends a char value to the string builder. 789 * 790 * @param ch the value to append 791 * @return this, to enable chaining 792 * @since 3.0 793 */ 794 @Override 795 public StrBuilder append(final char ch) { 796 final int len = length(); 797 ensureCapacity(len + 1); 798 buffer[size++] = ch; 799 return this; 800 } 801 802 /** 803 * Appends an int value to the string builder using <code>String.valueOf</code>. 804 * 805 * @param value the value to append 806 * @return this, to enable chaining 807 */ 808 public StrBuilder append(final int value) { 809 return append(String.valueOf(value)); 810 } 811 812 /** 813 * Appends a long value to the string builder using <code>String.valueOf</code>. 814 * 815 * @param value the value to append 816 * @return this, to enable chaining 817 */ 818 public StrBuilder append(final long value) { 819 return append(String.valueOf(value)); 820 } 821 822 /** 823 * Appends a float value to the string builder using <code>String.valueOf</code>. 824 * 825 * @param value the value to append 826 * @return this, to enable chaining 827 */ 828 public StrBuilder append(final float value) { 829 return append(String.valueOf(value)); 830 } 831 832 /** 833 * Appends a double value to the string builder using <code>String.valueOf</code>. 834 * 835 * @param value the value to append 836 * @return this, to enable chaining 837 */ 838 public StrBuilder append(final double value) { 839 return append(String.valueOf(value)); 840 } 841 842 //----------------------------------------------------------------------- 843 /** 844 * Appends an object followed by a new line to this string builder. 845 * Appending null will call {@link #appendNull()}. 846 * 847 * @param obj the object to append 848 * @return this, to enable chaining 849 * @since 2.3 850 */ 851 public StrBuilder appendln(final Object obj) { 852 return append(obj).appendNewLine(); 853 } 854 855 /** 856 * Appends a string followed by a new line to this string builder. 857 * Appending null will call {@link #appendNull()}. 858 * 859 * @param str the string to append 860 * @return this, to enable chaining 861 * @since 2.3 862 */ 863 public StrBuilder appendln(final String str) { 864 return append(str).appendNewLine(); 865 } 866 867 /** 868 * Appends part of a string followed by a new line to this string builder. 869 * Appending null will call {@link #appendNull()}. 870 * 871 * @param str the string to append 872 * @param startIndex the start index, inclusive, must be valid 873 * @param length the length to append, must be valid 874 * @return this, to enable chaining 875 * @since 2.3 876 */ 877 public StrBuilder appendln(final String str, final int startIndex, final int length) { 878 return append(str, startIndex, length).appendNewLine(); 879 } 880 881 /** 882 * Calls {@link String#format(String, Object...)} and appends the result. 883 * 884 * @param format the format string 885 * @param objs the objects to use in the format string 886 * @return {@code this} to enable chaining 887 * @see String#format(String, Object...) 888 * @since 3.2 889 */ 890 public StrBuilder appendln(final String format, final Object... objs) { 891 return append(format, objs).appendNewLine(); 892 } 893 894 /** 895 * Appends a string buffer followed by a new line to this string builder. 896 * Appending null will call {@link #appendNull()}. 897 * 898 * @param str the string buffer to append 899 * @return this, to enable chaining 900 * @since 2.3 901 */ 902 public StrBuilder appendln(final StringBuffer str) { 903 return append(str).appendNewLine(); 904 } 905 906 /** 907 * Appends a string builder followed by a new line to this string builder. 908 * Appending null will call {@link #appendNull()}. 909 * 910 * @param str the string builder to append 911 * @return this, to enable chaining 912 * @since 3.2 913 */ 914 public StrBuilder appendln(final StringBuilder str) { 915 return append(str).appendNewLine(); 916 } 917 918 /** 919 * Appends part of a string builder followed by a new line to this string builder. 920 * Appending null will call {@link #appendNull()}. 921 * 922 * @param str the string builder to append 923 * @param startIndex the start index, inclusive, must be valid 924 * @param length the length to append, must be valid 925 * @return this, to enable chaining 926 * @since 3.2 927 */ 928 public StrBuilder appendln(final StringBuilder str, final int startIndex, final int length) { 929 return append(str, startIndex, length).appendNewLine(); 930 } 931 932 /** 933 * Appends part of a string buffer followed by a new line to this string builder. 934 * Appending null will call {@link #appendNull()}. 935 * 936 * @param str the string to append 937 * @param startIndex the start index, inclusive, must be valid 938 * @param length the length to append, must be valid 939 * @return this, to enable chaining 940 * @since 2.3 941 */ 942 public StrBuilder appendln(final StringBuffer str, final int startIndex, final int length) { 943 return append(str, startIndex, length).appendNewLine(); 944 } 945 946 /** 947 * Appends another string builder followed by a new line to this string builder. 948 * Appending null will call {@link #appendNull()}. 949 * 950 * @param str the string builder to append 951 * @return this, to enable chaining 952 * @since 2.3 953 */ 954 public StrBuilder appendln(final StrBuilder str) { 955 return append(str).appendNewLine(); 956 } 957 958 /** 959 * Appends part of a string builder followed by a new line to this string builder. 960 * Appending null will call {@link #appendNull()}. 961 * 962 * @param str the string to append 963 * @param startIndex the start index, inclusive, must be valid 964 * @param length the length to append, must be valid 965 * @return this, to enable chaining 966 * @since 2.3 967 */ 968 public StrBuilder appendln(final StrBuilder str, final int startIndex, final int length) { 969 return append(str, startIndex, length).appendNewLine(); 970 } 971 972 /** 973 * Appends a char array followed by a new line to the string builder. 974 * Appending null will call {@link #appendNull()}. 975 * 976 * @param chars the char array to append 977 * @return this, to enable chaining 978 * @since 2.3 979 */ 980 public StrBuilder appendln(final char[] chars) { 981 return append(chars).appendNewLine(); 982 } 983 984 /** 985 * Appends a char array followed by a new line to the string builder. 986 * Appending null will call {@link #appendNull()}. 987 * 988 * @param chars the char array to append 989 * @param startIndex the start index, inclusive, must be valid 990 * @param length the length to append, must be valid 991 * @return this, to enable chaining 992 * @since 2.3 993 */ 994 public StrBuilder appendln(final char[] chars, final int startIndex, final int length) { 995 return append(chars, startIndex, length).appendNewLine(); 996 } 997 998 /** 999 * Appends a boolean value followed by a new line to the string builder. 1000 * 1001 * @param value the value to append 1002 * @return this, to enable chaining 1003 * @since 2.3 1004 */ 1005 public StrBuilder appendln(final boolean value) { 1006 return append(value).appendNewLine(); 1007 } 1008 1009 /** 1010 * Appends a char value followed by a new line to the string builder. 1011 * 1012 * @param ch the value to append 1013 * @return this, to enable chaining 1014 * @since 2.3 1015 */ 1016 public StrBuilder appendln(final char ch) { 1017 return append(ch).appendNewLine(); 1018 } 1019 1020 /** 1021 * Appends an int value followed by a new line to the string builder using <code>String.valueOf</code>. 1022 * 1023 * @param value the value to append 1024 * @return this, to enable chaining 1025 * @since 2.3 1026 */ 1027 public StrBuilder appendln(final int value) { 1028 return append(value).appendNewLine(); 1029 } 1030 1031 /** 1032 * Appends a long value followed by a new line to the string builder using <code>String.valueOf</code>. 1033 * 1034 * @param value the value to append 1035 * @return this, to enable chaining 1036 * @since 2.3 1037 */ 1038 public StrBuilder appendln(final long value) { 1039 return append(value).appendNewLine(); 1040 } 1041 1042 /** 1043 * Appends a float value followed by a new line to the string builder using <code>String.valueOf</code>. 1044 * 1045 * @param value the value to append 1046 * @return this, to enable chaining 1047 * @since 2.3 1048 */ 1049 public StrBuilder appendln(final float value) { 1050 return append(value).appendNewLine(); 1051 } 1052 1053 /** 1054 * Appends a double value followed by a new line to the string builder using <code>String.valueOf</code>. 1055 * 1056 * @param value the value to append 1057 * @return this, to enable chaining 1058 * @since 2.3 1059 */ 1060 public StrBuilder appendln(final double value) { 1061 return append(value).appendNewLine(); 1062 } 1063 1064 //----------------------------------------------------------------------- 1065 /** 1066 * Appends each item in an array to the builder without any separators. 1067 * Appending a null array will have no effect. 1068 * Each object is appended using {@link #append(Object)}. 1069 * 1070 * @param <T> the element type 1071 * @param array the array to append 1072 * @return this, to enable chaining 1073 * @since 2.3 1074 */ 1075 public <T> StrBuilder appendAll(final T... array) { 1076 if (array != null && array.length > 0) { 1077 for (final Object element : array) { 1078 append(element); 1079 } 1080 } 1081 return this; 1082 } 1083 1084 /** 1085 * Appends each item in a iterable to the builder without any separators. 1086 * Appending a null iterable will have no effect. 1087 * Each object is appended using {@link #append(Object)}. 1088 * 1089 * @param iterable the iterable to append 1090 * @return this, to enable chaining 1091 * @since 2.3 1092 */ 1093 public StrBuilder appendAll(final Iterable<?> iterable) { 1094 if (iterable != null) { 1095 for (final Object o : iterable) { 1096 append(o); 1097 } 1098 } 1099 return this; 1100 } 1101 1102 /** 1103 * Appends each item in an iterator to the builder without any separators. 1104 * Appending a null iterator will have no effect. 1105 * Each object is appended using {@link #append(Object)}. 1106 * 1107 * @param it the iterator to append 1108 * @return this, to enable chaining 1109 * @since 2.3 1110 */ 1111 public StrBuilder appendAll(final Iterator<?> it) { 1112 if (it != null) { 1113 while (it.hasNext()) { 1114 append(it.next()); 1115 } 1116 } 1117 return this; 1118 } 1119 1120 //----------------------------------------------------------------------- 1121 /** 1122 * Appends an array placing separators between each value, but 1123 * not before the first or after the last. 1124 * Appending a null array will have no effect. 1125 * Each object is appended using {@link #append(Object)}. 1126 * 1127 * @param array the array to append 1128 * @param separator the separator to use, null means no separator 1129 * @return this, to enable chaining 1130 */ 1131 public StrBuilder appendWithSeparators(final Object[] array, 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 public StrBuilder insert(final int index, String str) { 1490 validateIndex(index); 1491 if (str == null) { 1492 str = nullText; 1493 } 1494 if (str != null) { 1495 final int strLen = 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); 1502 } 1503 } 1504 return this; 1505 } 1506 1507 /** 1508 * Inserts the character array into this builder. 1509 * Inserting null will use the stored null text value. 1510 * 1511 * @param index the index to add at, must be valid 1512 * @param chars the char array to insert 1513 * @return this, to enable chaining 1514 * @throws IndexOutOfBoundsException if the index is invalid 1515 */ 1516 public StrBuilder insert(final int index, final char chars[]) { 1517 validateIndex(index); 1518 if (chars == null) { 1519 return insert(index, nullText); 1520 } 1521 final int len = chars.length; 1522 if (len > 0) { 1523 ensureCapacity(size + len); 1524 System.arraycopy(buffer, index, buffer, index + len, size - index); 1525 System.arraycopy(chars, 0, buffer, index, len); 1526 size += len; 1527 } 1528 return this; 1529 } 1530 1531 /** 1532 * Inserts part of the character array into this builder. 1533 * Inserting null will use the stored null text value. 1534 * 1535 * @param index the index to add at, must be valid 1536 * @param chars the char array to insert 1537 * @param offset the offset into the character array to start at, must be valid 1538 * @param length the length of the character array part to copy, must be positive 1539 * @return this, to enable chaining 1540 * @throws IndexOutOfBoundsException if any index is invalid 1541 */ 1542 public StrBuilder insert(final int index, final char chars[], final int offset, final int length) { 1543 validateIndex(index); 1544 if (chars == null) { 1545 return insert(index, nullText); 1546 } 1547 if (offset < 0 || offset > chars.length) { 1548 throw new StringIndexOutOfBoundsException("Invalid offset: " + offset); 1549 } 1550 if (length < 0 || offset + length > chars.length) { 1551 throw new StringIndexOutOfBoundsException("Invalid length: " + length); 1552 } 1553 if (length > 0) { 1554 ensureCapacity(size + length); 1555 System.arraycopy(buffer, index, buffer, index + length, size - index); 1556 System.arraycopy(chars, offset, buffer, index, length); 1557 size += length; 1558 } 1559 return this; 1560 } 1561 1562 /** 1563 * Inserts the value into this builder. 1564 * 1565 * @param index the index to add at, must be valid 1566 * @param value the value to insert 1567 * @return this, to enable chaining 1568 * @throws IndexOutOfBoundsException if the index is invalid 1569 */ 1570 public StrBuilder insert(int index, final boolean value) { 1571 validateIndex(index); 1572 if (value) { 1573 ensureCapacity(size + 4); 1574 System.arraycopy(buffer, index, buffer, index + 4, size - index); 1575 buffer[index++] = 't'; 1576 buffer[index++] = 'r'; 1577 buffer[index++] = 'u'; 1578 buffer[index] = 'e'; 1579 size += 4; 1580 } else { 1581 ensureCapacity(size + 5); 1582 System.arraycopy(buffer, index, buffer, index + 5, size - index); 1583 buffer[index++] = 'f'; 1584 buffer[index++] = 'a'; 1585 buffer[index++] = 'l'; 1586 buffer[index++] = 's'; 1587 buffer[index] = 'e'; 1588 size += 5; 1589 } 1590 return this; 1591 } 1592 1593 /** 1594 * Inserts the value into this builder. 1595 * 1596 * @param index the index to add at, must be valid 1597 * @param value the value to insert 1598 * @return this, to enable chaining 1599 * @throws IndexOutOfBoundsException if the index is invalid 1600 */ 1601 public StrBuilder insert(final int index, final char value) { 1602 validateIndex(index); 1603 ensureCapacity(size + 1); 1604 System.arraycopy(buffer, index, buffer, index + 1, size - index); 1605 buffer[index] = value; 1606 size++; 1607 return this; 1608 } 1609 1610 /** 1611 * Inserts the value into this builder. 1612 * 1613 * @param index the index to add at, must be valid 1614 * @param value the value to insert 1615 * @return this, to enable chaining 1616 * @throws IndexOutOfBoundsException if the index is invalid 1617 */ 1618 public StrBuilder insert(final int index, final int value) { 1619 return insert(index, String.valueOf(value)); 1620 } 1621 1622 /** 1623 * Inserts the value into this builder. 1624 * 1625 * @param index the index to add at, must be valid 1626 * @param value the value to insert 1627 * @return this, to enable chaining 1628 * @throws IndexOutOfBoundsException if the index is invalid 1629 */ 1630 public StrBuilder insert(final int index, final long value) { 1631 return insert(index, String.valueOf(value)); 1632 } 1633 1634 /** 1635 * Inserts the value into this builder. 1636 * 1637 * @param index the index to add at, must be valid 1638 * @param value the value to insert 1639 * @return this, to enable chaining 1640 * @throws IndexOutOfBoundsException if the index is invalid 1641 */ 1642 public StrBuilder insert(final int index, final float value) { 1643 return insert(index, String.valueOf(value)); 1644 } 1645 1646 /** 1647 * Inserts the value into this builder. 1648 * 1649 * @param index the index to add at, must be valid 1650 * @param value the value to insert 1651 * @return this, to enable chaining 1652 * @throws IndexOutOfBoundsException if the index is invalid 1653 */ 1654 public StrBuilder insert(final int index, final double value) { 1655 return insert(index, String.valueOf(value)); 1656 } 1657 1658 //----------------------------------------------------------------------- 1659 /** 1660 * Internal method to delete a range without validation. 1661 * 1662 * @param startIndex the start index, must be valid 1663 * @param endIndex the end index (exclusive), must be valid 1664 * @param len the length, must be valid 1665 * @throws IndexOutOfBoundsException if any index is invalid 1666 */ 1667 private void deleteImpl(final int startIndex, final int endIndex, final int len) { 1668 System.arraycopy(buffer, endIndex, buffer, startIndex, size - endIndex); 1669 size -= len; 1670 } 1671 1672 /** 1673 * Deletes the characters between the two specified indices. 1674 * 1675 * @param startIndex the start index, inclusive, must be valid 1676 * @param endIndex the end index, exclusive, must be valid except 1677 * that if too large it is treated as end of string 1678 * @return this, to enable chaining 1679 * @throws IndexOutOfBoundsException if the index is invalid 1680 */ 1681 public StrBuilder delete(final int startIndex, int endIndex) { 1682 endIndex = validateRange(startIndex, endIndex); 1683 final int len = endIndex - startIndex; 1684 if (len > 0) { 1685 deleteImpl(startIndex, endIndex, len); 1686 } 1687 return this; 1688 } 1689 1690 //----------------------------------------------------------------------- 1691 /** 1692 * Deletes the character wherever it occurs in the builder. 1693 * 1694 * @param ch the character to delete 1695 * @return this, to enable chaining 1696 */ 1697 public StrBuilder deleteAll(final char ch) { 1698 for (int i = 0; i < size; i++) { 1699 if (buffer[i] == ch) { 1700 final int start = i; 1701 while (++i < size) { 1702 if (buffer[i] != ch) { 1703 break; 1704 } 1705 } 1706 final int len = i - start; 1707 deleteImpl(start, i, len); 1708 i -= len; 1709 } 1710 } 1711 return this; 1712 } 1713 1714 /** 1715 * Deletes the character wherever it occurs in the builder. 1716 * 1717 * @param ch the character to delete 1718 * @return this, to enable chaining 1719 */ 1720 public StrBuilder deleteFirst(final char ch) { 1721 for (int i = 0; i < size; i++) { 1722 if (buffer[i] == ch) { 1723 deleteImpl(i, i + 1, 1); 1724 break; 1725 } 1726 } 1727 return this; 1728 } 1729 1730 //----------------------------------------------------------------------- 1731 /** 1732 * Deletes the string wherever it occurs in the builder. 1733 * 1734 * @param str the string to delete, null causes no action 1735 * @return this, to enable chaining 1736 */ 1737 public StrBuilder deleteAll(final String str) { 1738 final int len = (str == null ? 0 : str.length()); 1739 if (len > 0) { 1740 int index = indexOf(str, 0); 1741 while (index >= 0) { 1742 deleteImpl(index, index + len, len); 1743 index = indexOf(str, index); 1744 } 1745 } 1746 return this; 1747 } 1748 1749 /** 1750 * Deletes the string wherever it occurs in the builder. 1751 * 1752 * @param str the string to delete, null causes no action 1753 * @return this, to enable chaining 1754 */ 1755 public StrBuilder deleteFirst(final String str) { 1756 final int len = (str == null ? 0 : str.length()); 1757 if (len > 0) { 1758 final int index = indexOf(str, 0); 1759 if (index >= 0) { 1760 deleteImpl(index, index + len, len); 1761 } 1762 } 1763 return this; 1764 } 1765 1766 //----------------------------------------------------------------------- 1767 /** 1768 * Deletes all parts of the builder that the matcher matches. 1769 * <p> 1770 * Matchers can be used to perform advanced deletion behaviour. 1771 * For example you could write a matcher to delete all occurrences 1772 * where the character 'a' is followed by a number. 1773 * 1774 * @param matcher the matcher to use to find the deletion, null causes no action 1775 * @return this, to enable chaining 1776 */ 1777 public StrBuilder deleteAll(final StrMatcher matcher) { 1778 return replace(matcher, null, 0, size, -1); 1779 } 1780 1781 /** 1782 * Deletes the first match within the builder using the specified matcher. 1783 * <p> 1784 * Matchers can be used to perform advanced deletion behaviour. 1785 * For example you could write a matcher to delete 1786 * where the character 'a' is followed by a number. 1787 * 1788 * @param matcher the matcher to use to find the deletion, null causes no action 1789 * @return this, to enable chaining 1790 */ 1791 public StrBuilder deleteFirst(final StrMatcher matcher) { 1792 return replace(matcher, null, 0, size, 1); 1793 } 1794 1795 //----------------------------------------------------------------------- 1796 /** 1797 * Internal method to delete a range without validation. 1798 * 1799 * @param startIndex the start index, must be valid 1800 * @param endIndex the end index (exclusive), must be valid 1801 * @param removeLen the length to remove (endIndex - startIndex), must be valid 1802 * @param insertStr the string to replace with, null means delete range 1803 * @param insertLen the length of the insert string, must be valid 1804 * @throws IndexOutOfBoundsException if any index is invalid 1805 */ 1806 private void replaceImpl(final int startIndex, final int endIndex, final int removeLen, final String insertStr, final int insertLen) { 1807 final int newSize = size - removeLen + insertLen; 1808 if (insertLen != removeLen) { 1809 ensureCapacity(newSize); 1810 System.arraycopy(buffer, endIndex, buffer, startIndex + insertLen, size - endIndex); 1811 size = newSize; 1812 } 1813 if (insertLen > 0) { 1814 insertStr.getChars(0, insertLen, buffer, startIndex); 1815 } 1816 } 1817 1818 /** 1819 * Replaces a portion of the string builder with another string. 1820 * The length of the inserted string does not have to match the removed length. 1821 * 1822 * @param startIndex the start index, inclusive, must be valid 1823 * @param endIndex the end index, exclusive, must be valid except 1824 * that if too large it is treated as end of string 1825 * @param replaceStr the string to replace with, null means delete range 1826 * @return this, to enable chaining 1827 * @throws IndexOutOfBoundsException if the index is invalid 1828 */ 1829 public StrBuilder replace(final int startIndex, int endIndex, final String replaceStr) { 1830 endIndex = validateRange(startIndex, endIndex); 1831 final int insertLen = (replaceStr == null ? 0 : replaceStr.length()); 1832 replaceImpl(startIndex, endIndex, endIndex - startIndex, replaceStr, insertLen); 1833 return this; 1834 } 1835 1836 //----------------------------------------------------------------------- 1837 /** 1838 * Replaces the search character with the replace character 1839 * throughout the builder. 1840 * 1841 * @param search the search character 1842 * @param replace the replace character 1843 * @return this, to enable chaining 1844 */ 1845 public StrBuilder replaceAll(final char search, final char replace) { 1846 if (search != replace) { 1847 for (int i = 0; i < size; i++) { 1848 if (buffer[i] == search) { 1849 buffer[i] = replace; 1850 } 1851 } 1852 } 1853 return this; 1854 } 1855 1856 /** 1857 * Replaces the first instance of the search character with the 1858 * replace character in the builder. 1859 * 1860 * @param search the search character 1861 * @param replace the replace character 1862 * @return this, to enable chaining 1863 */ 1864 public StrBuilder replaceFirst(final char search, final char replace) { 1865 if (search != replace) { 1866 for (int i = 0; i < size; i++) { 1867 if (buffer[i] == search) { 1868 buffer[i] = replace; 1869 break; 1870 } 1871 } 1872 } 1873 return this; 1874 } 1875 1876 //----------------------------------------------------------------------- 1877 /** 1878 * Replaces the search string with the replace string throughout the builder. 1879 * 1880 * @param searchStr the search string, null causes no action to occur 1881 * @param replaceStr the replace string, null is equivalent to an empty string 1882 * @return this, to enable chaining 1883 */ 1884 public StrBuilder replaceAll(final String searchStr, final String replaceStr) { 1885 final int searchLen = (searchStr == null ? 0 : searchStr.length()); 1886 if (searchLen > 0) { 1887 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); 1888 int index = indexOf(searchStr, 0); 1889 while (index >= 0) { 1890 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 1891 index = indexOf(searchStr, index + replaceLen); 1892 } 1893 } 1894 return this; 1895 } 1896 1897 /** 1898 * Replaces the first instance of the search string with the replace string. 1899 * 1900 * @param searchStr the search string, null causes no action to occur 1901 * @param replaceStr the replace string, null is equivalent to an empty string 1902 * @return this, to enable chaining 1903 */ 1904 public StrBuilder replaceFirst(final String searchStr, final String replaceStr) { 1905 final int searchLen = (searchStr == null ? 0 : searchStr.length()); 1906 if (searchLen > 0) { 1907 final int index = indexOf(searchStr, 0); 1908 if (index >= 0) { 1909 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); 1910 replaceImpl(index, index + searchLen, searchLen, replaceStr, replaceLen); 1911 } 1912 } 1913 return this; 1914 } 1915 1916 //----------------------------------------------------------------------- 1917 /** 1918 * Replaces all matches within the builder with the replace string. 1919 * <p> 1920 * Matchers can be used to perform advanced replace behaviour. 1921 * For example you could write a matcher to replace all occurrences 1922 * where the character 'a' is followed by a number. 1923 * 1924 * @param matcher the matcher to use to find the deletion, null causes no action 1925 * @param replaceStr the replace string, null is equivalent to an empty string 1926 * @return this, to enable chaining 1927 */ 1928 public StrBuilder replaceAll(final StrMatcher matcher, final String replaceStr) { 1929 return replace(matcher, replaceStr, 0, size, -1); 1930 } 1931 1932 /** 1933 * Replaces the first match within the builder with the replace string. 1934 * <p> 1935 * Matchers can be used to perform advanced replace behaviour. 1936 * For example you could write a matcher to replace 1937 * where the character 'a' is followed by a number. 1938 * 1939 * @param matcher the matcher to use to find the deletion, null causes no action 1940 * @param replaceStr the replace string, null is equivalent to an empty string 1941 * @return this, to enable chaining 1942 */ 1943 public StrBuilder replaceFirst(final StrMatcher matcher, final String replaceStr) { 1944 return replace(matcher, replaceStr, 0, size, 1); 1945 } 1946 1947 // ----------------------------------------------------------------------- 1948 /** 1949 * Advanced search and replaces within the builder using a matcher. 1950 * <p> 1951 * Matchers can be used to perform advanced behaviour. 1952 * For example you could write a matcher to delete all occurrences 1953 * where the character 'a' is followed by a number. 1954 * 1955 * @param matcher the matcher to use to find the deletion, null causes no action 1956 * @param replaceStr the string to replace the match with, null is a delete 1957 * @param startIndex the start index, inclusive, must be valid 1958 * @param endIndex the end index, exclusive, must be valid except 1959 * that if too large it is treated as end of string 1960 * @param replaceCount the number of times to replace, -1 for replace all 1961 * @return this, to enable chaining 1962 * @throws IndexOutOfBoundsException if start index is invalid 1963 */ 1964 public StrBuilder replace( 1965 final StrMatcher matcher, final String replaceStr, 1966 final int startIndex, int endIndex, final int replaceCount) { 1967 endIndex = validateRange(startIndex, endIndex); 1968 return replaceImpl(matcher, replaceStr, startIndex, endIndex, replaceCount); 1969 } 1970 1971 /** 1972 * Replaces within the builder using a matcher. 1973 * <p> 1974 * Matchers can be used to perform advanced behaviour. 1975 * For example you could write a matcher to delete all occurrences 1976 * where the character 'a' is followed by a number. 1977 * 1978 * @param matcher the matcher to use to find the deletion, null causes no action 1979 * @param replaceStr the string to replace the match with, null is a delete 1980 * @param from the start index, must be valid 1981 * @param to the end index (exclusive), must be valid 1982 * @param replaceCount the number of times to replace, -1 for replace all 1983 * @return this, to enable chaining 1984 * @throws IndexOutOfBoundsException if any index is invalid 1985 */ 1986 private StrBuilder replaceImpl( 1987 final StrMatcher matcher, final String replaceStr, 1988 final int from, int to, int replaceCount) { 1989 if (matcher == null || size == 0) { 1990 return this; 1991 } 1992 final int replaceLen = (replaceStr == null ? 0 : replaceStr.length()); 1993 final char[] buf = buffer; 1994 for (int i = from; i < to && replaceCount != 0; i++) { 1995 final int removeLen = matcher.isMatch(buf, i, from, to); 1996 if (removeLen > 0) { 1997 replaceImpl(i, i + removeLen, removeLen, replaceStr, replaceLen); 1998 to = to - removeLen + replaceLen; 1999 i = i + replaceLen - 1; 2000 if (replaceCount > 0) { 2001 replaceCount--; 2002 } 2003 } 2004 } 2005 return this; 2006 } 2007 2008 //----------------------------------------------------------------------- 2009 /** 2010 * Reverses the string builder placing each character in the opposite index. 2011 * 2012 * @return this, to enable chaining 2013 */ 2014 public StrBuilder reverse() { 2015 if (size == 0) { 2016 return this; 2017 } 2018 2019 final int half = size / 2; 2020 final char[] buf = buffer; 2021 for (int leftIdx = 0, rightIdx = size - 1; leftIdx < half; leftIdx++,rightIdx--) { 2022 final char swap = buf[leftIdx]; 2023 buf[leftIdx] = buf[rightIdx]; 2024 buf[rightIdx] = swap; 2025 } 2026 return this; 2027 } 2028 2029 //----------------------------------------------------------------------- 2030 /** 2031 * Trims the builder by removing characters less than or equal to a space 2032 * from the beginning and end. 2033 * 2034 * @return this, to enable chaining 2035 */ 2036 public StrBuilder trim() { 2037 if (size == 0) { 2038 return this; 2039 } 2040 int len = size; 2041 final char[] buf = buffer; 2042 int pos = 0; 2043 while (pos < len && buf[pos] <= ' ') { 2044 pos++; 2045 } 2046 while (pos < len && buf[len - 1] <= ' ') { 2047 len--; 2048 } 2049 if (len < size) { 2050 delete(len, size); 2051 } 2052 if (pos > 0) { 2053 delete(0, pos); 2054 } 2055 return this; 2056 } 2057 2058 //----------------------------------------------------------------------- 2059 /** 2060 * Checks whether this builder starts with the specified string. 2061 * <p> 2062 * Note that this method handles null input quietly, unlike String. 2063 * 2064 * @param str the string to search for, null returns false 2065 * @return true if the builder starts with the string 2066 */ 2067 public boolean startsWith(final String str) { 2068 if (str == null) { 2069 return false; 2070 } 2071 final int len = str.length(); 2072 if (len == 0) { 2073 return true; 2074 } 2075 if (len > size) { 2076 return false; 2077 } 2078 for (int i = 0; i < len; i++) { 2079 if (buffer[i] != str.charAt(i)) { 2080 return false; 2081 } 2082 } 2083 return true; 2084 } 2085 2086 /** 2087 * Checks whether this builder ends with the specified string. 2088 * <p> 2089 * Note that this method handles null input quietly, unlike String. 2090 * 2091 * @param str the string to search for, null returns false 2092 * @return true if the builder ends with the string 2093 */ 2094 public boolean endsWith(final String str) { 2095 if (str == null) { 2096 return false; 2097 } 2098 final int len = str.length(); 2099 if (len == 0) { 2100 return true; 2101 } 2102 if (len > size) { 2103 return false; 2104 } 2105 int pos = size - len; 2106 for (int i = 0; i < len; i++,pos++) { 2107 if (buffer[pos] != str.charAt(i)) { 2108 return false; 2109 } 2110 } 2111 return true; 2112 } 2113 2114 //----------------------------------------------------------------------- 2115 /** 2116 * {@inheritDoc} 2117 * @since 3.0 2118 */ 2119 @Override 2120 public CharSequence subSequence(final int startIndex, final int endIndex) { 2121 if (startIndex < 0) { 2122 throw new StringIndexOutOfBoundsException(startIndex); 2123 } 2124 if (endIndex > size) { 2125 throw new StringIndexOutOfBoundsException(endIndex); 2126 } 2127 if (startIndex > endIndex) { 2128 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 2129 } 2130 return substring(startIndex, endIndex); 2131 } 2132 2133 /** 2134 * Extracts a portion of this string builder as a string. 2135 * 2136 * @param start the start index, inclusive, must be valid 2137 * @return the new string 2138 * @throws IndexOutOfBoundsException if the index is invalid 2139 */ 2140 public String substring(final int start) { 2141 return substring(start, size); 2142 } 2143 2144 /** 2145 * Extracts a portion of this string builder as a string. 2146 * <p> 2147 * Note: This method treats an endIndex greater than the length of the 2148 * builder as equal to the length of the builder, and continues 2149 * without error, unlike StringBuffer or String. 2150 * 2151 * @param startIndex the start index, inclusive, must be valid 2152 * @param endIndex the end index, exclusive, must be valid except 2153 * that if too large it is treated as end of string 2154 * @return the new string 2155 * @throws IndexOutOfBoundsException if the index is invalid 2156 */ 2157 public String substring(final int startIndex, int endIndex) { 2158 endIndex = validateRange(startIndex, endIndex); 2159 return new String(buffer, startIndex, endIndex - startIndex); 2160 } 2161 2162 /** 2163 * Extracts the leftmost characters from the string builder without 2164 * throwing an exception. 2165 * <p> 2166 * This method extracts the left <code>length</code> characters from 2167 * the builder. If this many characters are not available, the whole 2168 * builder is returned. Thus the returned string may be shorter than the 2169 * length requested. 2170 * 2171 * @param length the number of characters to extract, negative returns empty string 2172 * @return the new string 2173 */ 2174 public String leftString(final int length) { 2175 if (length <= 0) { 2176 return ""; 2177 } else if (length >= size) { 2178 return new String(buffer, 0, size); 2179 } else { 2180 return new String(buffer, 0, length); 2181 } 2182 } 2183 2184 /** 2185 * Extracts the rightmost characters from the string builder without 2186 * throwing an exception. 2187 * <p> 2188 * This method extracts the right <code>length</code> characters from 2189 * the builder. If this many characters are not available, the whole 2190 * builder is returned. Thus the returned string may be shorter than the 2191 * length requested. 2192 * 2193 * @param length the number of characters to extract, negative returns empty string 2194 * @return the new string 2195 */ 2196 public String rightString(final int length) { 2197 if (length <= 0) { 2198 return ""; 2199 } else if (length >= size) { 2200 return new String(buffer, 0, size); 2201 } else { 2202 return new String(buffer, size - length, length); 2203 } 2204 } 2205 2206 /** 2207 * Extracts some characters from the middle of the string builder without 2208 * throwing an exception. 2209 * <p> 2210 * This method extracts <code>length</code> characters from the builder 2211 * at the specified index. 2212 * If the index is negative it is treated as zero. 2213 * If the index is greater than the builder size, it is treated as the builder size. 2214 * If the length is negative, the empty string is returned. 2215 * If insufficient characters are available in the builder, as much as possible is returned. 2216 * Thus the returned string may be shorter than the length requested. 2217 * 2218 * @param index the index to start at, negative means zero 2219 * @param length the number of characters to extract, negative returns empty string 2220 * @return the new string 2221 */ 2222 public String midString(int index, final int length) { 2223 if (index < 0) { 2224 index = 0; 2225 } 2226 if (length <= 0 || index >= size) { 2227 return ""; 2228 } 2229 if (size <= index + length) { 2230 return new String(buffer, index, size - index); 2231 } 2232 return new String(buffer, index, length); 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 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 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 } 2820 return super.tokenize(chars, offset, count); 2821 } 2822 2823 /** {@inheritDoc} */ 2824 @Override 2825 public String getContent() { 2826 final String str = super.getContent(); 2827 if (str == null) { 2828 return StrBuilder.this.toString(); 2829 } 2830 return str; 2831 } 2832 } 2833 2834 //----------------------------------------------------------------------- 2835 /** 2836 * Inner class to allow StrBuilder to operate as a reader. 2837 */ 2838 class StrBuilderReader extends Reader { 2839 /** The current stream position. */ 2840 private int pos; 2841 /** The last mark position. */ 2842 private int mark; 2843 2844 /** 2845 * Default constructor. 2846 */ 2847 StrBuilderReader() { 2848 super(); 2849 } 2850 2851 /** {@inheritDoc} */ 2852 @Override 2853 public void close() { 2854 // do nothing 2855 } 2856 2857 /** {@inheritDoc} */ 2858 @Override 2859 public int read() { 2860 if (ready() == false) { 2861 return -1; 2862 } 2863 return StrBuilder.this.charAt(pos++); 2864 } 2865 2866 /** {@inheritDoc} */ 2867 @Override 2868 public int read(final char b[], final int off, int len) { 2869 if (off < 0 || len < 0 || off > b.length || 2870 (off + len) > b.length || (off + len) < 0) { 2871 throw new IndexOutOfBoundsException(); 2872 } 2873 if (len == 0) { 2874 return 0; 2875 } 2876 if (pos >= StrBuilder.this.size()) { 2877 return -1; 2878 } 2879 if (pos + len > size()) { 2880 len = StrBuilder.this.size() - pos; 2881 } 2882 StrBuilder.this.getChars(pos, pos + len, b, off); 2883 pos += len; 2884 return len; 2885 } 2886 2887 /** {@inheritDoc} */ 2888 @Override 2889 public long skip(long n) { 2890 if (pos + n > StrBuilder.this.size()) { 2891 n = StrBuilder.this.size() - pos; 2892 } 2893 if (n < 0) { 2894 return 0; 2895 } 2896 pos += n; 2897 return n; 2898 } 2899 2900 /** {@inheritDoc} */ 2901 @Override 2902 public boolean ready() { 2903 return pos < StrBuilder.this.size(); 2904 } 2905 2906 /** {@inheritDoc} */ 2907 @Override 2908 public boolean markSupported() { 2909 return true; 2910 } 2911 2912 /** {@inheritDoc} */ 2913 @Override 2914 public void mark(final int readAheadLimit) { 2915 mark = pos; 2916 } 2917 2918 /** {@inheritDoc} */ 2919 @Override 2920 public void reset() { 2921 pos = mark; 2922 } 2923 } 2924 2925 //----------------------------------------------------------------------- 2926 /** 2927 * Inner class to allow StrBuilder to operate as a writer. 2928 */ 2929 class StrBuilderWriter extends Writer { 2930 2931 /** 2932 * Default constructor. 2933 */ 2934 StrBuilderWriter() { 2935 super(); 2936 } 2937 2938 /** {@inheritDoc} */ 2939 @Override 2940 public void close() { 2941 // do nothing 2942 } 2943 2944 /** {@inheritDoc} */ 2945 @Override 2946 public void flush() { 2947 // do nothing 2948 } 2949 2950 /** {@inheritDoc} */ 2951 @Override 2952 public void write(final int c) { 2953 StrBuilder.this.append((char) c); 2954 } 2955 2956 /** {@inheritDoc} */ 2957 @Override 2958 public void write(final char[] cbuf) { 2959 StrBuilder.this.append(cbuf); 2960 } 2961 2962 /** {@inheritDoc} */ 2963 @Override 2964 public void write(final char[] cbuf, final int off, final int len) { 2965 StrBuilder.this.append(cbuf, off, len); 2966 } 2967 2968 /** {@inheritDoc} */ 2969 @Override 2970 public void write(final String str) { 2971 StrBuilder.this.append(str); 2972 } 2973 2974 /** {@inheritDoc} */ 2975 @Override 2976 public void write(final String str, final int off, final int len) { 2977 StrBuilder.this.append(str, off, len); 2978 } 2979 } 2980 2981}