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