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