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