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