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