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