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 * @author Apache Software Foundation 070 * @author Robert Scholte 071 * @since 2.2 072 * @version $Id: StrBuilder.java 916081 2010-02-25 01:28:13Z niallp $ 073 */ 074 public class StrBuilder implements CharSequence, Appendable { 075 076 /** 077 * The extra capacity for new builders. 078 */ 079 static final int CAPACITY = 32; 080 081 /** 082 * Required for serialization support. 083 * 084 * @see java.io.Serializable 085 */ 086 private static final long serialVersionUID = 7628716375283629643L; 087 088 /** Internal data storage. */ 089 protected char[] buffer; // TODO make private? 090 /** Current size of the buffer. */ 091 protected int size; // TODO make private? 092 /** The new line. */ 093 private String newLine; 094 /** The null text. */ 095 private String nullText; 096 097 //----------------------------------------------------------------------- 098 /** 099 * Constructor that creates an empty builder initial capacity 32 characters. 100 */ 101 public StrBuilder() { 102 this(CAPACITY); 103 } 104 105 /** 106 * Constructor that creates an empty builder the specified initial capacity. 107 * 108 * @param initialCapacity the initial capacity, zero or less will be converted to 32 109 */ 110 public StrBuilder(int initialCapacity) { 111 super(); 112 if (initialCapacity <= 0) { 113 initialCapacity = CAPACITY; 114 } 115 buffer = new char[initialCapacity]; 116 } 117 118 /** 119 * Constructor that creates a builder from the string, allocating 120 * 32 extra characters for growth. 121 * 122 * @param str the string to copy, null treated as blank string 123 */ 124 public StrBuilder(String str) { 125 super(); 126 if (str == null) { 127 buffer = new char[CAPACITY]; 128 } else { 129 buffer = new char[str.length() + CAPACITY]; 130 append(str); 131 } 132 } 133 134 //----------------------------------------------------------------------- 135 /** 136 * Gets the text to be appended when a new line is added. 137 * 138 * @return the new line text, null means use system default 139 */ 140 public String getNewLineText() { 141 return newLine; 142 } 143 144 /** 145 * Sets the text to be appended when a new line is added. 146 * 147 * @param newLine the new line text, null means use system default 148 * @return this, to enable chaining 149 */ 150 public StrBuilder setNewLineText(String newLine) { 151 this.newLine = newLine; 152 return this; 153 } 154 155 //----------------------------------------------------------------------- 156 /** 157 * Gets the text to be appended when null is added. 158 * 159 * @return the null text, null means no append 160 */ 161 public String getNullText() { 162 return nullText; 163 } 164 165 /** 166 * Sets the text to be appended when null is added. 167 * 168 * @param nullText the null text, null means no append 169 * @return this, to enable chaining 170 */ 171 public StrBuilder setNullText(String nullText) { 172 if (nullText != null && nullText.length() == 0) { 173 nullText = null; 174 } 175 this.nullText = nullText; 176 return this; 177 } 178 179 //----------------------------------------------------------------------- 180 /** 181 * Gets the length of the string builder. 182 * 183 * @return the length 184 */ 185 public int length() { 186 return size; 187 } 188 189 /** 190 * Updates the length of the builder by either dropping the last characters 191 * or adding filler of unicode zero. 192 * 193 * @param length the length to set to, must be zero or positive 194 * @return this, to enable chaining 195 * @throws IndexOutOfBoundsException if the length is negative 196 */ 197 public StrBuilder setLength(int length) { 198 if (length < 0) { 199 throw new StringIndexOutOfBoundsException(length); 200 } 201 if (length < size) { 202 size = length; 203 } else if (length > size) { 204 ensureCapacity(length); 205 int oldEnd = size; 206 int newEnd = length; 207 size = length; 208 for (int i = oldEnd; i < newEnd; i++) { 209 buffer[i] = '\0'; 210 } 211 } 212 return this; 213 } 214 215 //----------------------------------------------------------------------- 216 /** 217 * Gets the current size of the internal character array buffer. 218 * 219 * @return the capacity 220 */ 221 public int capacity() { 222 return buffer.length; 223 } 224 225 /** 226 * Checks the capacity and ensures that it is at least the size specified. 227 * 228 * @param capacity the capacity to ensure 229 * @return this, to enable chaining 230 */ 231 public StrBuilder ensureCapacity(int capacity) { 232 if (capacity > buffer.length) { 233 char[] old = buffer; 234 buffer = new char[capacity * 2]; 235 System.arraycopy(old, 0, buffer, 0, size); 236 } 237 return this; 238 } 239 240 /** 241 * Minimizes the capacity to the actual length of the string. 242 * 243 * @return this, to enable chaining 244 */ 245 public StrBuilder minimizeCapacity() { 246 if (buffer.length > length()) { 247 char[] old = buffer; 248 buffer = new char[length()]; 249 System.arraycopy(old, 0, buffer, 0, size); 250 } 251 return this; 252 } 253 254 //----------------------------------------------------------------------- 255 /** 256 * Gets the length of the string builder. 257 * <p> 258 * This method is the same as {@link #length()} and is provided to match the 259 * API of Collections. 260 * 261 * @return the length 262 */ 263 public int size() { 264 return size; 265 } 266 267 /** 268 * Checks is the string builder is empty (convenience Collections API style method). 269 * <p> 270 * This method is the same as checking {@link #length()} and is provided to match the 271 * API of Collections. 272 * 273 * @return <code>true</code> if the size is <code>0</code>. 274 */ 275 public boolean isEmpty() { 276 return size == 0; 277 } 278 279 /** 280 * Clears the string builder (convenience Collections API style method). 281 * <p> 282 * This method does not reduce the size of the internal character buffer. 283 * To do that, call <code>clear()</code> followed by {@link #minimizeCapacity()}. 284 * <p> 285 * This method is the same as {@link #setLength(int)} called with zero 286 * and is provided to match the API of Collections. 287 * 288 * @return this, to enable chaining 289 */ 290 public StrBuilder clear() { 291 size = 0; 292 return this; 293 } 294 295 //----------------------------------------------------------------------- 296 /** 297 * Gets the character at the specified index. 298 * 299 * @see #setCharAt(int, char) 300 * @see #deleteCharAt(int) 301 * @param index the index to retrieve, must be valid 302 * @return the character at the index 303 * @throws IndexOutOfBoundsException if the index is invalid 304 */ 305 public char charAt(int index) { 306 if (index < 0 || index >= length()) { 307 throw new StringIndexOutOfBoundsException(index); 308 } 309 return buffer[index]; 310 } 311 312 /** 313 * Sets the character at the specified index. 314 * 315 * @see #charAt(int) 316 * @see #deleteCharAt(int) 317 * @param index the index to set 318 * @param ch the new character 319 * @return this, to enable chaining 320 * @throws IndexOutOfBoundsException if the index is invalid 321 */ 322 public StrBuilder setCharAt(int index, char ch) { 323 if (index < 0 || index >= length()) { 324 throw new StringIndexOutOfBoundsException(index); 325 } 326 buffer[index] = ch; 327 return this; 328 } 329 330 /** 331 * Deletes the character at the specified index. 332 * 333 * @see #charAt(int) 334 * @see #setCharAt(int, char) 335 * @param index the index to delete 336 * @return this, to enable chaining 337 * @throws IndexOutOfBoundsException if the index is invalid 338 */ 339 public StrBuilder deleteCharAt(int index) { 340 if (index < 0 || index >= size) { 341 throw new StringIndexOutOfBoundsException(index); 342 } 343 deleteImpl(index, index + 1, 1); 344 return this; 345 } 346 347 //----------------------------------------------------------------------- 348 /** 349 * Copies the builder's character array into a new character array. 350 * 351 * @return a new array that represents the contents of the builder 352 */ 353 public char[] toCharArray() { 354 if (size == 0) { 355 return ArrayUtils.EMPTY_CHAR_ARRAY; 356 } 357 char chars[] = new char[size]; 358 System.arraycopy(buffer, 0, chars, 0, size); 359 return chars; 360 } 361 362 /** 363 * Copies part of the builder's character array into a new character array. 364 * 365 * @param startIndex the start index, inclusive, must be valid 366 * @param endIndex the end index, exclusive, must be valid except that 367 * if too large it is treated as end of string 368 * @return a new array that holds part of the contents of the builder 369 * @throws IndexOutOfBoundsException if startIndex is invalid, 370 * or if endIndex is invalid (but endIndex greater than size is valid) 371 */ 372 public char[] toCharArray(int startIndex, int endIndex) { 373 endIndex = validateRange(startIndex, endIndex); 374 int len = endIndex - startIndex; 375 if (len == 0) { 376 return ArrayUtils.EMPTY_CHAR_ARRAY; 377 } 378 char chars[] = new char[len]; 379 System.arraycopy(buffer, startIndex, chars, 0, len); 380 return chars; 381 } 382 383 /** 384 * Copies the character array into the specified array. 385 * 386 * @param destination the destination array, null will cause an array to be created 387 * @return the input array, unless that was null or too small 388 */ 389 public char[] getChars(char[] destination) { 390 int len = length(); 391 if (destination == null || destination.length < len) { 392 destination = new char[len]; 393 } 394 System.arraycopy(buffer, 0, destination, 0, len); 395 return destination; 396 } 397 398 /** 399 * Copies the character array into the specified array. 400 * 401 * @param startIndex first index to copy, inclusive, must be valid 402 * @param endIndex last index, exclusive, must be valid 403 * @param destination the destination array, must not be null or too small 404 * @param destinationIndex the index to start copying in destination 405 * @throws NullPointerException if the array is null 406 * @throws IndexOutOfBoundsException if any index is invalid 407 */ 408 public void getChars(int startIndex, int endIndex, char destination[], int destinationIndex) { 409 if (startIndex < 0) { 410 throw new StringIndexOutOfBoundsException(startIndex); 411 } 412 if (endIndex < 0 || endIndex > length()) { 413 throw new StringIndexOutOfBoundsException(endIndex); 414 } 415 if (startIndex > endIndex) { 416 throw new StringIndexOutOfBoundsException("end < start"); 417 } 418 System.arraycopy(buffer, startIndex, destination, destinationIndex, endIndex - startIndex); 419 } 420 421 //----------------------------------------------------------------------- 422 /** 423 * Appends the new line string to this string builder. 424 * <p> 425 * The new line string can be altered using {@link #setNewLineText(String)}. 426 * This might be used to force the output to always use Unix line endings 427 * even when on Windows. 428 * 429 * @return this, to enable chaining 430 */ 431 public StrBuilder appendNewLine() { 432 if (newLine == null) { 433 append(SystemUtils.LINE_SEPARATOR); 434 return this; 435 } 436 return append(newLine); 437 } 438 439 /** 440 * Appends the text representing <code>null</code> to this string builder. 441 * 442 * @return this, to enable chaining 443 */ 444 public StrBuilder appendNull() { 445 if (nullText == null) { 446 return this; 447 } 448 return append(nullText); 449 } 450 451 /** 452 * Appends an object to this string builder. 453 * Appending null will call {@link #appendNull()}. 454 * 455 * @param obj the object to append 456 * @return this, to enable chaining 457 */ 458 public StrBuilder append(Object obj) { 459 if (obj == null) { 460 return appendNull(); 461 } 462 return append(obj.toString()); 463 } 464 465 /** 466 * Appends a CharSequence to this string builder. 467 * Appending null will call {@link #appendNull()}. 468 * 469 * @param seq the CharSequence to append 470 * @return this, to enable chaining 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 */ 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 */ 721 public StrBuilder append(char ch) { 722 int len = length(); 723 ensureCapacity(len + 1); 724 buffer[size++] = ch; 725 return this; 726 } 727 728 /** 729 * Appends an int value to the string builder using <code>String.valueOf</code>. 730 * 731 * @param value the value to append 732 * @return this, to enable chaining 733 */ 734 public StrBuilder append(int value) { 735 return append(String.valueOf(value)); 736 } 737 738 /** 739 * Appends a long value to the string builder using <code>String.valueOf</code>. 740 * 741 * @param value the value to append 742 * @return this, to enable chaining 743 */ 744 public StrBuilder append(long value) { 745 return append(String.valueOf(value)); 746 } 747 748 /** 749 * Appends a float value to the string builder using <code>String.valueOf</code>. 750 * 751 * @param value the value to append 752 * @return this, to enable chaining 753 */ 754 public StrBuilder append(float value) { 755 return append(String.valueOf(value)); 756 } 757 758 /** 759 * Appends a double value to the string builder using <code>String.valueOf</code>. 760 * 761 * @param value the value to append 762 * @return this, to enable chaining 763 */ 764 public StrBuilder append(double value) { 765 return append(String.valueOf(value)); 766 } 767 768 //----------------------------------------------------------------------- 769 /** 770 * Appends an object followed by a new line to this string builder. 771 * Appending null will call {@link #appendNull()}. 772 * 773 * @param obj the object to append 774 * @return this, to enable chaining 775 * @since 2.3 776 */ 777 public StrBuilder appendln(Object obj) { 778 return append(obj).appendNewLine(); 779 } 780 781 /** 782 * Appends a string followed by a new line to this string builder. 783 * Appending null will call {@link #appendNull()}. 784 * 785 * @param str the string to append 786 * @return this, to enable chaining 787 * @since 2.3 788 */ 789 public StrBuilder appendln(String str) { 790 return append(str).appendNewLine(); 791 } 792 793 /** 794 * Appends part of a string followed by a new line to this string builder. 795 * Appending null will call {@link #appendNull()}. 796 * 797 * @param str the string to append 798 * @param startIndex the start index, inclusive, must be valid 799 * @param length the length to append, must be valid 800 * @return this, to enable chaining 801 * @since 2.3 802 */ 803 public StrBuilder appendln(String str, int startIndex, int length) { 804 return append(str, startIndex, length).appendNewLine(); 805 } 806 807 /** 808 * Appends a string buffer followed by a new line to this string builder. 809 * Appending null will call {@link #appendNull()}. 810 * 811 * @param str the string buffer to append 812 * @return this, to enable chaining 813 * @since 2.3 814 */ 815 public StrBuilder appendln(StringBuffer str) { 816 return append(str).appendNewLine(); 817 } 818 819 /** 820 * Appends part of a string buffer followed by a new line to this string builder. 821 * Appending null will call {@link #appendNull()}. 822 * 823 * @param str the string to append 824 * @param startIndex the start index, inclusive, must be valid 825 * @param length the length to append, must be valid 826 * @return this, to enable chaining 827 * @since 2.3 828 */ 829 public StrBuilder appendln(StringBuffer str, int startIndex, int length) { 830 return append(str, startIndex, length).appendNewLine(); 831 } 832 833 /** 834 * Appends another string builder followed by a new line to this string builder. 835 * Appending null will call {@link #appendNull()}. 836 * 837 * @param str the string builder to append 838 * @return this, to enable chaining 839 * @since 2.3 840 */ 841 public StrBuilder appendln(StrBuilder str) { 842 return append(str).appendNewLine(); 843 } 844 845 /** 846 * Appends part of a string builder followed by a new line to this string builder. 847 * Appending null will call {@link #appendNull()}. 848 * 849 * @param str the string to append 850 * @param startIndex the start index, inclusive, must be valid 851 * @param length the length to append, must be valid 852 * @return this, to enable chaining 853 * @since 2.3 854 */ 855 public StrBuilder appendln(StrBuilder str, int startIndex, int length) { 856 return append(str, startIndex, length).appendNewLine(); 857 } 858 859 /** 860 * Appends a char array followed by a new line to the string builder. 861 * Appending null will call {@link #appendNull()}. 862 * 863 * @param chars the char array to append 864 * @return this, to enable chaining 865 * @since 2.3 866 */ 867 public StrBuilder appendln(char[] chars) { 868 return append(chars).appendNewLine(); 869 } 870 871 /** 872 * Appends a char array followed by a new line to the string builder. 873 * Appending null will call {@link #appendNull()}. 874 * 875 * @param chars the char array to append 876 * @param startIndex the start index, inclusive, must be valid 877 * @param length the length to append, must be valid 878 * @return this, to enable chaining 879 * @since 2.3 880 */ 881 public StrBuilder appendln(char[] chars, int startIndex, int length) { 882 return append(chars, startIndex, length).appendNewLine(); 883 } 884 885 /** 886 * Appends a boolean value followed by a new line to the string builder. 887 * 888 * @param value the value to append 889 * @return this, to enable chaining 890 * @since 2.3 891 */ 892 public StrBuilder appendln(boolean value) { 893 return append(value).appendNewLine(); 894 } 895 896 /** 897 * Appends a char value followed by a new line to the string builder. 898 * 899 * @param ch the value to append 900 * @return this, to enable chaining 901 * @since 2.3 902 */ 903 public StrBuilder appendln(char ch) { 904 return append(ch).appendNewLine(); 905 } 906 907 /** 908 * Appends an int value followed by a new line to the string builder using <code>String.valueOf</code>. 909 * 910 * @param value the value to append 911 * @return this, to enable chaining 912 * @since 2.3 913 */ 914 public StrBuilder appendln(int value) { 915 return append(value).appendNewLine(); 916 } 917 918 /** 919 * Appends a long value followed by a new line to the string builder using <code>String.valueOf</code>. 920 * 921 * @param value the value to append 922 * @return this, to enable chaining 923 * @since 2.3 924 */ 925 public StrBuilder appendln(long value) { 926 return append(value).appendNewLine(); 927 } 928 929 /** 930 * Appends a float value followed by a new line to the string builder using <code>String.valueOf</code>. 931 * 932 * @param value the value to append 933 * @return this, to enable chaining 934 * @since 2.3 935 */ 936 public StrBuilder appendln(float value) { 937 return append(value).appendNewLine(); 938 } 939 940 /** 941 * Appends a double value followed by a new line to the string builder using <code>String.valueOf</code>. 942 * 943 * @param value the value to append 944 * @return this, to enable chaining 945 * @since 2.3 946 */ 947 public StrBuilder appendln(double value) { 948 return append(value).appendNewLine(); 949 } 950 951 //----------------------------------------------------------------------- 952 /** 953 * Appends each item in an array to the builder without any separators. 954 * Appending a null array will have no effect. 955 * Each object is appended using {@link #append(Object)}. 956 * 957 * @param array the array to append 958 * @return this, to enable chaining 959 * @since 2.3 960 */ 961 public StrBuilder appendAll(Object[] array) { 962 if (array != null && array.length > 0) { 963 for (int i = 0; i < array.length; i++) { 964 append(array[i]); 965 } 966 } 967 return this; 968 } 969 970 /** 971 * Appends each item in a iterable to the builder without any separators. 972 * Appending a null iterable will have no effect. 973 * Each object is appended using {@link #append(Object)}. 974 * 975 * @param iterable the iterable to append 976 * @return this, to enable chaining 977 * @since 2.3 978 */ 979 public StrBuilder appendAll(Iterable<?> iterable) { 980 if (iterable != null) { 981 Iterator<?> it = iterable.iterator(); 982 while (it.hasNext()) { 983 append(it.next()); 984 } 985 } 986 return this; 987 } 988 989 /** 990 * Appends each item in an iterator to the builder without any separators. 991 * Appending a null iterator will have no effect. 992 * Each object is appended using {@link #append(Object)}. 993 * 994 * @param it the iterator to append 995 * @return this, to enable chaining 996 * @since 2.3 997 */ 998 public StrBuilder appendAll(Iterator<?> it) { 999 if (it != null) { 1000 while (it.hasNext()) { 1001 append(it.next()); 1002 } 1003 } 1004 return this; 1005 } 1006 1007 //----------------------------------------------------------------------- 1008 /** 1009 * Appends an array placing separators between each value, but 1010 * not before the first or after the last. 1011 * Appending a null array will have no effect. 1012 * Each object is appended using {@link #append(Object)}. 1013 * 1014 * @param array the array to append 1015 * @param separator the separator to use, null means no separator 1016 * @return this, to enable chaining 1017 */ 1018 public StrBuilder appendWithSeparators(Object[] array, String separator) { 1019 if (array != null && array.length > 0) { 1020 separator = (separator == null ? "" : separator); 1021 append(array[0]); 1022 for (int i = 1; i < array.length; i++) { 1023 append(separator); 1024 append(array[i]); 1025 } 1026 } 1027 return this; 1028 } 1029 1030 /** 1031 * Appends a iterable placing separators between each value, but 1032 * not before the first or after the last. 1033 * Appending a null iterable will have no effect. 1034 * Each object is appended using {@link #append(Object)}. 1035 * 1036 * @param iterable the iterable to append 1037 * @param separator the separator to use, null means no separator 1038 * @return this, to enable chaining 1039 */ 1040 public StrBuilder appendWithSeparators(Iterable<?> iterable, String separator) { 1041 if (iterable != null) { 1042 separator = (separator == null ? "" : separator); 1043 Iterator<?> it = iterable.iterator(); 1044 while (it.hasNext()) { 1045 append(it.next()); 1046 if (it.hasNext()) { 1047 append(separator); 1048 } 1049 } 1050 } 1051 return this; 1052 } 1053 1054 /** 1055 * Appends an iterator placing separators between each value, but 1056 * not before the first or after the last. 1057 * Appending a null iterator will have no effect. 1058 * Each object is appended using {@link #append(Object)}. 1059 * 1060 * @param it the iterator to append 1061 * @param separator the separator to use, null means no separator 1062 * @return this, to enable chaining 1063 */ 1064 public StrBuilder appendWithSeparators(Iterator<?> it, String separator) { 1065 if (it != null) { 1066 separator = (separator == null ? "" : separator); 1067 while (it.hasNext()) { 1068 append(it.next()); 1069 if (it.hasNext()) { 1070 append(separator); 1071 } 1072 } 1073 } 1074 return this; 1075 } 1076 1077 //----------------------------------------------------------------------- 1078 /** 1079 * Appends a separator if the builder is currently non-empty. 1080 * Appending a null separator will have no effect. 1081 * The separator is appended using {@link #append(String)}. 1082 * <p> 1083 * This method is useful for adding a separator each time around the 1084 * loop except the first. 1085 * <pre> 1086 * for (Iterator it = list.iterator(); it.hasNext(); ) { 1087 * appendSeparator(","); 1088 * append(it.next()); 1089 * } 1090 * </pre> 1091 * Note that for this simple example, you should use 1092 * {@link #appendWithSeparators(Iterable, String)}. 1093 * 1094 * @param separator the separator to use, null means no separator 1095 * @return this, to enable chaining 1096 * @since 2.3 1097 */ 1098 public StrBuilder appendSeparator(String separator) { 1099 return appendSeparator(separator, null); 1100 } 1101 1102 /** 1103 * Appends one of both separators to the StrBuilder. 1104 * If the builder is currently empty it will append the defaultIfEmpty-separator 1105 * Otherwise it will append the standard-separator 1106 * 1107 * Appending a null separator will have no effect. 1108 * The separator is appended using {@link #append(String)}. 1109 * <p> 1110 * This method is for example useful for constructing queries 1111 * <pre> 1112 * StrBuilder whereClause = new StrBuilder(); 1113 * if(searchCommand.getPriority() != null) { 1114 * whereClause.appendSeparator(" and", " where"); 1115 * whereClause.append(" priority = ?") 1116 * } 1117 * if(searchCommand.getComponent() != null) { 1118 * whereClause.appendSeparator(" and", " where"); 1119 * whereClause.append(" component = ?") 1120 * } 1121 * selectClause.append(whereClause) 1122 * </pre> 1123 * 1124 * @param standard the separator if builder is not empty, null means no separator 1125 * @param defaultIfEmpty the separator if builder is empty, null means no separator 1126 * @return this, to enable chaining 1127 * @since 2.5 1128 */ 1129 public StrBuilder appendSeparator(String standard, String defaultIfEmpty) { 1130 String str = isEmpty() ? defaultIfEmpty : standard; 1131 if (str != null) { 1132 append(str); 1133 } 1134 return this; 1135 } 1136 1137 /** 1138 * Appends a separator if the builder is currently non-empty. 1139 * The separator is appended using {@link #append(char)}. 1140 * <p> 1141 * This method is useful for adding a separator each time around the 1142 * loop except the first. 1143 * <pre> 1144 * for (Iterator it = list.iterator(); it.hasNext(); ) { 1145 * appendSeparator(','); 1146 * append(it.next()); 1147 * } 1148 * </pre> 1149 * Note that for this simple example, you should use 1150 * {@link #appendWithSeparators(Iterable, String)}. 1151 * 1152 * @param separator the separator to use 1153 * @return this, to enable chaining 1154 * @since 2.3 1155 */ 1156 public StrBuilder appendSeparator(char separator) { 1157 if (size() > 0) { 1158 append(separator); 1159 } 1160 return this; 1161 } 1162 1163 /** 1164 * Append one of both separators to the builder 1165 * If the builder is currently empty it will append the defaultIfEmpty-separator 1166 * Otherwise it will append the standard-separator 1167 * 1168 * The separator is appended using {@link #append(char)}. 1169 * @param standard the separator if builder is not empty 1170 * @param defaultIfEmpty the separator if builder is empty 1171 * @return this, to enable chaining 1172 * @since 2.5 1173 */ 1174 public StrBuilder appendSeparator(char standard, char defaultIfEmpty) { 1175 if (size() > 0) { 1176 append(standard); 1177 } 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 */ 2005 public CharSequence subSequence(int startIndex, int endIndex) { 2006 if (startIndex < 0) { 2007 throw new StringIndexOutOfBoundsException(startIndex); 2008 } 2009 if (endIndex > size) { 2010 throw new StringIndexOutOfBoundsException(endIndex); 2011 } 2012 if (startIndex > endIndex) { 2013 throw new StringIndexOutOfBoundsException(endIndex - startIndex); 2014 } 2015 return substring(startIndex, endIndex); 2016 } 2017 2018 /** 2019 * Extracts a portion of this string builder as a string. 2020 * 2021 * @param start the start index, inclusive, must be valid 2022 * @return the new string 2023 * @throws IndexOutOfBoundsException if the index is invalid 2024 */ 2025 public String substring(int start) { 2026 return substring(start, size); 2027 } 2028 2029 /** 2030 * Extracts a portion of this string builder as a string. 2031 * <p> 2032 * Note: This method treats an endIndex greater than the length of the 2033 * builder as equal to the length of the builder, and continues 2034 * without error, unlike StringBuffer or String. 2035 * 2036 * @param startIndex the start index, inclusive, must be valid 2037 * @param endIndex the end index, exclusive, must be valid except 2038 * that if too large it is treated as end of string 2039 * @return the new string 2040 * @throws IndexOutOfBoundsException if the index is invalid 2041 */ 2042 public String substring(int startIndex, int endIndex) { 2043 endIndex = validateRange(startIndex, endIndex); 2044 return new String(buffer, startIndex, endIndex - startIndex); 2045 } 2046 2047 /** 2048 * Extracts the leftmost characters from the string builder without 2049 * throwing an exception. 2050 * <p> 2051 * This method extracts the left <code>length</code> characters from 2052 * the builder. If this many characters are not available, the whole 2053 * builder is returned. Thus the returned string may be shorter than the 2054 * length requested. 2055 * 2056 * @param length the number of characters to extract, negative returns empty string 2057 * @return the new string 2058 */ 2059 public String leftString(int length) { 2060 if (length <= 0) { 2061 return ""; 2062 } else if (length >= size) { 2063 return new String(buffer, 0, size); 2064 } else { 2065 return new String(buffer, 0, length); 2066 } 2067 } 2068 2069 /** 2070 * Extracts the rightmost characters from the string builder without 2071 * throwing an exception. 2072 * <p> 2073 * This method extracts the right <code>length</code> characters from 2074 * the builder. If this many characters are not available, the whole 2075 * builder is returned. Thus the returned string may be shorter than the 2076 * length requested. 2077 * 2078 * @param length the number of characters to extract, negative returns empty string 2079 * @return the new string 2080 */ 2081 public String rightString(int length) { 2082 if (length <= 0) { 2083 return ""; 2084 } else if (length >= size) { 2085 return new String(buffer, 0, size); 2086 } else { 2087 return new String(buffer, size - length, length); 2088 } 2089 } 2090 2091 /** 2092 * Extracts some characters from the middle of the string builder without 2093 * throwing an exception. 2094 * <p> 2095 * This method extracts <code>length</code> characters from the builder 2096 * at the specified index. 2097 * If the index is negative it is treated as zero. 2098 * If the index is greater than the builder size, it is treated as the builder size. 2099 * If the length is negative, the empty string is returned. 2100 * If insufficient characters are available in the builder, as much as possible is returned. 2101 * Thus the returned string may be shorter than the length requested. 2102 * 2103 * @param index the index to start at, negative means zero 2104 * @param length the number of characters to extract, negative returns empty string 2105 * @return the new string 2106 */ 2107 public String midString(int index, int length) { 2108 if (index < 0) { 2109 index = 0; 2110 } 2111 if (length <= 0 || index >= size) { 2112 return ""; 2113 } 2114 if (size <= index + length) { 2115 return new String(buffer, index, size - index); 2116 } else { 2117 return new String(buffer, index, length); 2118 } 2119 } 2120 2121 //----------------------------------------------------------------------- 2122 /** 2123 * Checks if the string builder contains the specified char. 2124 * 2125 * @param ch the character to find 2126 * @return true if the builder contains the character 2127 */ 2128 public boolean contains(char ch) { 2129 char[] thisBuf = buffer; 2130 for (int i = 0; i < this.size; i++) { 2131 if (thisBuf[i] == ch) { 2132 return true; 2133 } 2134 } 2135 return false; 2136 } 2137 2138 /** 2139 * Checks if the string builder contains the specified string. 2140 * 2141 * @param str the string to find 2142 * @return true if the builder contains the string 2143 */ 2144 public boolean contains(String str) { 2145 return indexOf(str, 0) >= 0; 2146 } 2147 2148 /** 2149 * Checks if the string builder contains a string matched using the 2150 * specified matcher. 2151 * <p> 2152 * Matchers can be used to perform advanced searching behaviour. 2153 * For example you could write a matcher to search for the character 2154 * 'a' followed by a number. 2155 * 2156 * @param matcher the matcher to use, null returns -1 2157 * @return true if the matcher finds a match in the builder 2158 */ 2159 public boolean contains(StrMatcher matcher) { 2160 return indexOf(matcher, 0) >= 0; 2161 } 2162 2163 //----------------------------------------------------------------------- 2164 /** 2165 * Searches the string builder to find the first reference to the specified char. 2166 * 2167 * @param ch the character to find 2168 * @return the first index of the character, or -1 if not found 2169 */ 2170 public int indexOf(char ch) { 2171 return indexOf(ch, 0); 2172 } 2173 2174 /** 2175 * Searches the string builder to find the first reference to the specified char. 2176 * 2177 * @param ch the character to find 2178 * @param startIndex the index to start at, invalid index rounded to edge 2179 * @return the first index of the character, or -1 if not found 2180 */ 2181 public int indexOf(char ch, int startIndex) { 2182 startIndex = (startIndex < 0 ? 0 : startIndex); 2183 if (startIndex >= size) { 2184 return -1; 2185 } 2186 char[] thisBuf = buffer; 2187 for (int i = startIndex; i < size; i++) { 2188 if (thisBuf[i] == ch) { 2189 return i; 2190 } 2191 } 2192 return -1; 2193 } 2194 2195 /** 2196 * Searches the string builder to find the first reference to the specified string. 2197 * <p> 2198 * Note that a null input string will return -1, whereas the JDK throws an exception. 2199 * 2200 * @param str the string to find, null returns -1 2201 * @return the first index of the string, or -1 if not found 2202 */ 2203 public int indexOf(String str) { 2204 return indexOf(str, 0); 2205 } 2206 2207 /** 2208 * Searches the string builder to find the first reference to the specified 2209 * string starting searching from the given index. 2210 * <p> 2211 * Note that a null input string will return -1, whereas the JDK throws an exception. 2212 * 2213 * @param str the string to find, null returns -1 2214 * @param startIndex the index to start at, invalid index rounded to edge 2215 * @return the first index of the string, or -1 if not found 2216 */ 2217 public int indexOf(String str, int startIndex) { 2218 startIndex = (startIndex < 0 ? 0 : startIndex); 2219 if (str == null || startIndex >= size) { 2220 return -1; 2221 } 2222 int strLen = str.length(); 2223 if (strLen == 1) { 2224 return indexOf(str.charAt(0), startIndex); 2225 } 2226 if (strLen == 0) { 2227 return startIndex; 2228 } 2229 if (strLen > size) { 2230 return -1; 2231 } 2232 char[] thisBuf = buffer; 2233 int len = size - strLen + 1; 2234 outer: 2235 for (int i = startIndex; i < len; i++) { 2236 for (int j = 0; j < strLen; j++) { 2237 if (str.charAt(j) != thisBuf[i + j]) { 2238 continue outer; 2239 } 2240 } 2241 return i; 2242 } 2243 return -1; 2244 } 2245 2246 /** 2247 * Searches the string builder using the matcher to find the first match. 2248 * <p> 2249 * Matchers can be used to perform advanced searching behaviour. 2250 * For example you could write a matcher to find the character 'a' 2251 * followed by a number. 2252 * 2253 * @param matcher the matcher to use, null returns -1 2254 * @return the first index matched, or -1 if not found 2255 */ 2256 public int indexOf(StrMatcher matcher) { 2257 return indexOf(matcher, 0); 2258 } 2259 2260 /** 2261 * Searches the string builder using the matcher to find the first 2262 * match searching from the given index. 2263 * <p> 2264 * Matchers can be used to perform advanced searching behaviour. 2265 * For example you could write a matcher to find the character 'a' 2266 * followed by a number. 2267 * 2268 * @param matcher the matcher to use, null returns -1 2269 * @param startIndex the index to start at, invalid index rounded to edge 2270 * @return the first index matched, or -1 if not found 2271 */ 2272 public int indexOf(StrMatcher matcher, int startIndex) { 2273 startIndex = (startIndex < 0 ? 0 : startIndex); 2274 if (matcher == null || startIndex >= size) { 2275 return -1; 2276 } 2277 int len = size; 2278 char[] buf = buffer; 2279 for (int i = startIndex; i < len; i++) { 2280 if (matcher.isMatch(buf, i, startIndex, len) > 0) { 2281 return i; 2282 } 2283 } 2284 return -1; 2285 } 2286 2287 //----------------------------------------------------------------------- 2288 /** 2289 * Searches the string builder to find the last reference to the specified char. 2290 * 2291 * @param ch the character to find 2292 * @return the last index of the character, or -1 if not found 2293 */ 2294 public int lastIndexOf(char ch) { 2295 return lastIndexOf(ch, size - 1); 2296 } 2297 2298 /** 2299 * Searches the string builder to find the last reference to the specified char. 2300 * 2301 * @param ch the character to find 2302 * @param startIndex the index to start at, invalid index rounded to edge 2303 * @return the last index of the character, or -1 if not found 2304 */ 2305 public int lastIndexOf(char ch, int startIndex) { 2306 startIndex = (startIndex >= size ? size - 1 : startIndex); 2307 if (startIndex < 0) { 2308 return -1; 2309 } 2310 for (int i = startIndex; i >= 0; i--) { 2311 if (buffer[i] == ch) { 2312 return i; 2313 } 2314 } 2315 return -1; 2316 } 2317 2318 /** 2319 * Searches the string builder to find the last reference to the specified string. 2320 * <p> 2321 * Note that a null input string will return -1, whereas the JDK throws an exception. 2322 * 2323 * @param str the string to find, null returns -1 2324 * @return the last index of the string, or -1 if not found 2325 */ 2326 public int lastIndexOf(String str) { 2327 return lastIndexOf(str, size - 1); 2328 } 2329 2330 /** 2331 * Searches the string builder to find the last reference to the specified 2332 * string starting searching from the given index. 2333 * <p> 2334 * Note that a null input string will return -1, whereas the JDK throws an exception. 2335 * 2336 * @param str the string to find, null returns -1 2337 * @param startIndex the index to start at, invalid index rounded to edge 2338 * @return the last index of the string, or -1 if not found 2339 */ 2340 public int lastIndexOf(String str, int startIndex) { 2341 startIndex = (startIndex >= size ? size - 1 : startIndex); 2342 if (str == null || startIndex < 0) { 2343 return -1; 2344 } 2345 int strLen = str.length(); 2346 if (strLen > 0 && strLen <= size) { 2347 if (strLen == 1) { 2348 return lastIndexOf(str.charAt(0), startIndex); 2349 } 2350 2351 outer: 2352 for (int i = startIndex - strLen + 1; i >= 0; i--) { 2353 for (int j = 0; j < strLen; j++) { 2354 if (str.charAt(j) != buffer[i + j]) { 2355 continue outer; 2356 } 2357 } 2358 return i; 2359 } 2360 2361 } else if (strLen == 0) { 2362 return startIndex; 2363 } 2364 return -1; 2365 } 2366 2367 /** 2368 * Searches the string builder using the matcher to find the last match. 2369 * <p> 2370 * Matchers can be used to perform advanced searching behaviour. 2371 * For example you could write a matcher to find the character 'a' 2372 * followed by a number. 2373 * 2374 * @param matcher the matcher to use, null returns -1 2375 * @return the last index matched, or -1 if not found 2376 */ 2377 public int lastIndexOf(StrMatcher matcher) { 2378 return lastIndexOf(matcher, size); 2379 } 2380 2381 /** 2382 * Searches the string builder using the matcher to find the last 2383 * match searching from the given index. 2384 * <p> 2385 * Matchers can be used to perform advanced searching behaviour. 2386 * For example you could write a matcher to find the character 'a' 2387 * followed by a number. 2388 * 2389 * @param matcher the matcher to use, null returns -1 2390 * @param startIndex the index to start at, invalid index rounded to edge 2391 * @return the last index matched, or -1 if not found 2392 */ 2393 public int lastIndexOf(StrMatcher matcher, int startIndex) { 2394 startIndex = (startIndex >= size ? size - 1 : startIndex); 2395 if (matcher == null || startIndex < 0) { 2396 return -1; 2397 } 2398 char[] buf = buffer; 2399 int endIndex = startIndex + 1; 2400 for (int i = startIndex; i >= 0; i--) { 2401 if (matcher.isMatch(buf, i, 0, endIndex) > 0) { 2402 return i; 2403 } 2404 } 2405 return -1; 2406 } 2407 2408 //----------------------------------------------------------------------- 2409 /** 2410 * Creates a tokenizer that can tokenize the contents of this builder. 2411 * <p> 2412 * This method allows the contents of this builder to be tokenized. 2413 * The tokenizer will be setup by default to tokenize on space, tab, 2414 * newline and formfeed (as per StringTokenizer). These values can be 2415 * changed on the tokenizer class, before retrieving the tokens. 2416 * <p> 2417 * The returned tokenizer is linked to this builder. You may intermix 2418 * calls to the buider and tokenizer within certain limits, however 2419 * there is no synchronization. Once the tokenizer has been used once, 2420 * it must be {@link StrTokenizer#reset() reset} to pickup the latest 2421 * changes in the builder. For example: 2422 * <pre> 2423 * StrBuilder b = new StrBuilder(); 2424 * b.append("a b "); 2425 * StrTokenizer t = b.asTokenizer(); 2426 * String[] tokens1 = t.getTokenArray(); // returns a,b 2427 * b.append("c d "); 2428 * String[] tokens2 = t.getTokenArray(); // returns a,b (c and d ignored) 2429 * t.reset(); // reset causes builder changes to be picked up 2430 * String[] tokens3 = t.getTokenArray(); // returns a,b,c,d 2431 * </pre> 2432 * In addition to simply intermixing appends and tokenization, you can also 2433 * call the set methods on the tokenizer to alter how it tokenizes. Just 2434 * remember to call reset when you want to pickup builder changes. 2435 * <p> 2436 * Calling {@link StrTokenizer#reset(String)} or {@link StrTokenizer#reset(char[])} 2437 * with a non-null value will break the link with the builder. 2438 * 2439 * @return a tokenizer that is linked to this builder 2440 */ 2441 public StrTokenizer asTokenizer() { 2442 return new StrBuilderTokenizer(); 2443 } 2444 2445 //----------------------------------------------------------------------- 2446 /** 2447 * Gets the contents of this builder as a Reader. 2448 * <p> 2449 * This method allows the contents of the builder to be read 2450 * using any standard method that expects a Reader. 2451 * <p> 2452 * To use, simply create a <code>StrBuilder</code>, populate it with 2453 * data, call <code>asReader</code>, and then read away. 2454 * <p> 2455 * The internal character array is shared between the builder and the reader. 2456 * This allows you to append to the builder after creating the reader, 2457 * and the changes will be picked up. 2458 * Note however, that no synchronization occurs, so you must perform 2459 * all operations with the builder and the reader in one thread. 2460 * <p> 2461 * The returned reader supports marking, and ignores the flush method. 2462 * 2463 * @return a reader that reads from this builder 2464 */ 2465 public Reader asReader() { 2466 return new StrBuilderReader(); 2467 } 2468 2469 //----------------------------------------------------------------------- 2470 /** 2471 * Gets this builder as a Writer that can be written to. 2472 * <p> 2473 * This method allows you to populate the contents of the builder 2474 * using any standard method that takes a Writer. 2475 * <p> 2476 * To use, simply create a <code>StrBuilder</code>, 2477 * call <code>asWriter</code>, and populate away. The data is available 2478 * at any time using the methods of the <code>StrBuilder</code>. 2479 * <p> 2480 * The internal character array is shared between the builder and the writer. 2481 * This allows you to intermix calls that append to the builder and 2482 * write using the writer and the changes will be occur correctly. 2483 * Note however, that no synchronization occurs, so you must perform 2484 * all operations with the builder and the writer in one thread. 2485 * <p> 2486 * The returned writer ignores the close and flush methods. 2487 * 2488 * @return a writer that populates this builder 2489 */ 2490 public Writer asWriter() { 2491 return new StrBuilderWriter(); 2492 } 2493 2494 //----------------------------------------------------------------------- 2495 // /** 2496 // * Gets a String version of the string builder by calling the internal 2497 // * constructor of String by reflection. 2498 // * <p> 2499 // * WARNING: You must not use the StrBuilder after calling this method 2500 // * as the buffer is now shared with the String object. To ensure this, 2501 // * the internal character array is set to null, so you will get 2502 // * NullPointerExceptions on all method calls. 2503 // * 2504 // * @return the builder as a String 2505 // */ 2506 // public String toSharedString() { 2507 // try { 2508 // Constructor con = String.class.getDeclaredConstructor( 2509 // new Class[] {int.class, int.class, char[].class}); 2510 // con.setAccessible(true); 2511 // char[] buffer = buf; 2512 // buf = null; 2513 // size = -1; 2514 // nullText = null; 2515 // return (String) con.newInstance( 2516 // new Object[] {new Integer(0), new Integer(size), buffer}); 2517 // 2518 // } catch (Exception ex) { 2519 // ex.printStackTrace(); 2520 // throw new UnsupportedOperationException("StrBuilder.toSharedString is unsupported: " + ex.getMessage()); 2521 // } 2522 // } 2523 2524 //----------------------------------------------------------------------- 2525 /** 2526 * Checks the contents of this builder against another to see if they 2527 * contain the same character content ignoring case. 2528 * 2529 * @param other the object to check, null returns false 2530 * @return true if the builders contain the same characters in the same order 2531 */ 2532 public boolean equalsIgnoreCase(StrBuilder other) { 2533 if (this == other) { 2534 return true; 2535 } 2536 if (this.size != other.size) { 2537 return false; 2538 } 2539 char thisBuf[] = this.buffer; 2540 char otherBuf[] = other.buffer; 2541 for (int i = size - 1; i >= 0; i--) { 2542 char c1 = thisBuf[i]; 2543 char c2 = otherBuf[i]; 2544 if (c1 != c2 && Character.toUpperCase(c1) != Character.toUpperCase(c2)) { 2545 return false; 2546 } 2547 } 2548 return true; 2549 } 2550 2551 /** 2552 * Checks the contents of this builder against another to see if they 2553 * contain the same character content. 2554 * 2555 * @param other the object to check, null returns false 2556 * @return true if the builders contain the same characters in the same order 2557 */ 2558 public boolean equals(StrBuilder other) { 2559 if (this == other) { 2560 return true; 2561 } 2562 if (this.size != other.size) { 2563 return false; 2564 } 2565 char thisBuf[] = this.buffer; 2566 char otherBuf[] = other.buffer; 2567 for (int i = size - 1; i >= 0; i--) { 2568 if (thisBuf[i] != otherBuf[i]) { 2569 return false; 2570 } 2571 } 2572 return true; 2573 } 2574 2575 /** 2576 * Checks the contents of this builder against another to see if they 2577 * contain the same character content. 2578 * 2579 * @param obj the object to check, null returns false 2580 * @return true if the builders contain the same characters in the same order 2581 */ 2582 @Override 2583 public boolean equals(Object obj) { 2584 if (obj instanceof StrBuilder) { 2585 return equals((StrBuilder) obj); 2586 } 2587 return false; 2588 } 2589 2590 /** 2591 * Gets a suitable hash code for this builder. 2592 * 2593 * @return a hash code 2594 */ 2595 @Override 2596 public int hashCode() { 2597 char buf[] = buffer; 2598 int hash = 0; 2599 for (int i = size - 1; i >= 0; i--) { 2600 hash = 31 * hash + buf[i]; 2601 } 2602 return hash; 2603 } 2604 2605 //----------------------------------------------------------------------- 2606 /** 2607 * Gets a String version of the string builder, creating a new instance 2608 * each time the method is called. 2609 * <p> 2610 * Note that unlike StringBuffer, the string version returned is 2611 * independent of the string builder. 2612 * 2613 * @return the builder as a String 2614 */ 2615 @Override 2616 public String toString() { 2617 return new String(buffer, 0, size); 2618 } 2619 2620 /** 2621 * Gets a StringBuffer version of the string builder, creating a 2622 * new instance each time the method is called. 2623 * 2624 * @return the builder as a StringBuffer 2625 */ 2626 public StringBuffer toStringBuffer() { 2627 return new StringBuffer(size).append(buffer, 0, size); 2628 } 2629 2630 //----------------------------------------------------------------------- 2631 /** 2632 * Validates parameters defining a range of the builder. 2633 * 2634 * @param startIndex the start index, inclusive, must be valid 2635 * @param endIndex the end index, exclusive, must be valid except 2636 * that if too large it is treated as end of string 2637 * @return the new string 2638 * @throws IndexOutOfBoundsException if the index is invalid 2639 */ 2640 protected int validateRange(int startIndex, int endIndex) { 2641 if (startIndex < 0) { 2642 throw new StringIndexOutOfBoundsException(startIndex); 2643 } 2644 if (endIndex > size) { 2645 endIndex = size; 2646 } 2647 if (startIndex > endIndex) { 2648 throw new StringIndexOutOfBoundsException("end < start"); 2649 } 2650 return endIndex; 2651 } 2652 2653 /** 2654 * Validates parameters defining a single index in the builder. 2655 * 2656 * @param index the index, must be valid 2657 * @throws IndexOutOfBoundsException if the index is invalid 2658 */ 2659 protected void validateIndex(int index) { 2660 if (index < 0 || index > size) { 2661 throw new StringIndexOutOfBoundsException(index); 2662 } 2663 } 2664 2665 //----------------------------------------------------------------------- 2666 /** 2667 * Inner class to allow StrBuilder to operate as a tokenizer. 2668 */ 2669 class StrBuilderTokenizer extends StrTokenizer { 2670 2671 /** 2672 * Default constructor. 2673 */ 2674 StrBuilderTokenizer() { 2675 super(); 2676 } 2677 2678 /** {@inheritDoc} */ 2679 @Override 2680 protected List<String> tokenize(char[] chars, int offset, int count) { 2681 if (chars == null) { 2682 return super.tokenize(StrBuilder.this.buffer, 0, StrBuilder.this.size()); 2683 } else { 2684 return super.tokenize(chars, offset, count); 2685 } 2686 } 2687 2688 /** {@inheritDoc} */ 2689 @Override 2690 public String getContent() { 2691 String str = super.getContent(); 2692 if (str == null) { 2693 return StrBuilder.this.toString(); 2694 } else { 2695 return str; 2696 } 2697 } 2698 } 2699 2700 //----------------------------------------------------------------------- 2701 /** 2702 * Inner class to allow StrBuilder to operate as a writer. 2703 */ 2704 class StrBuilderReader extends Reader { 2705 /** The current stream position. */ 2706 private int pos; 2707 /** The last mark position. */ 2708 private int mark; 2709 2710 /** 2711 * Default constructor. 2712 */ 2713 StrBuilderReader() { 2714 super(); 2715 } 2716 2717 /** {@inheritDoc} */ 2718 @Override 2719 public void close() { 2720 // do nothing 2721 } 2722 2723 /** {@inheritDoc} */ 2724 @Override 2725 public int read() { 2726 if (ready() == false) { 2727 return -1; 2728 } 2729 return StrBuilder.this.charAt(pos++); 2730 } 2731 2732 /** {@inheritDoc} */ 2733 @Override 2734 public int read(char b[], int off, int len) { 2735 if (off < 0 || len < 0 || off > b.length || 2736 (off + len) > b.length || (off + len) < 0) { 2737 throw new IndexOutOfBoundsException(); 2738 } 2739 if (len == 0) { 2740 return 0; 2741 } 2742 if (pos >= StrBuilder.this.size()) { 2743 return -1; 2744 } 2745 if (pos + len > size()) { 2746 len = StrBuilder.this.size() - pos; 2747 } 2748 StrBuilder.this.getChars(pos, pos + len, b, off); 2749 pos += len; 2750 return len; 2751 } 2752 2753 /** {@inheritDoc} */ 2754 @Override 2755 public long skip(long n) { 2756 if (pos + n > StrBuilder.this.size()) { 2757 n = StrBuilder.this.size() - pos; 2758 } 2759 if (n < 0) { 2760 return 0; 2761 } 2762 pos += n; 2763 return n; 2764 } 2765 2766 /** {@inheritDoc} */ 2767 @Override 2768 public boolean ready() { 2769 return pos < StrBuilder.this.size(); 2770 } 2771 2772 /** {@inheritDoc} */ 2773 @Override 2774 public boolean markSupported() { 2775 return true; 2776 } 2777 2778 /** {@inheritDoc} */ 2779 @Override 2780 public void mark(int readAheadLimit) { 2781 mark = pos; 2782 } 2783 2784 /** {@inheritDoc} */ 2785 @Override 2786 public void reset() { 2787 pos = mark; 2788 } 2789 } 2790 2791 //----------------------------------------------------------------------- 2792 /** 2793 * Inner class to allow StrBuilder to operate as a writer. 2794 */ 2795 class StrBuilderWriter extends Writer { 2796 2797 /** 2798 * Default constructor. 2799 */ 2800 StrBuilderWriter() { 2801 super(); 2802 } 2803 2804 /** {@inheritDoc} */ 2805 @Override 2806 public void close() { 2807 // do nothing 2808 } 2809 2810 /** {@inheritDoc} */ 2811 @Override 2812 public void flush() { 2813 // do nothing 2814 } 2815 2816 /** {@inheritDoc} */ 2817 @Override 2818 public void write(int c) { 2819 StrBuilder.this.append((char) c); 2820 } 2821 2822 /** {@inheritDoc} */ 2823 @Override 2824 public void write(char[] cbuf) { 2825 StrBuilder.this.append(cbuf); 2826 } 2827 2828 /** {@inheritDoc} */ 2829 @Override 2830 public void write(char[] cbuf, int off, int len) { 2831 StrBuilder.this.append(cbuf, off, len); 2832 } 2833 2834 /** {@inheritDoc} */ 2835 @Override 2836 public void write(String str) { 2837 StrBuilder.this.append(str); 2838 } 2839 2840 /** {@inheritDoc} */ 2841 @Override 2842 public void write(String str, int off, int len) { 2843 StrBuilder.this.append(str, off, len); 2844 } 2845 } 2846 2847 }