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